/** * struct ad7150_chip_info - instance specific chip data * @client: i2c client for this device * @threshold: thresholds for simple capacitance value events * @thresh_sensitivity: threshold for simple capacitance offset * from 'average' value. * @thresh_timeout: a timeout, in samples from the moment an * adaptive threshold event occurs to when the average * value jumps to current value. Note made up of two fields, * 3:0 are for timeout receding - applies if below lower threshold * 7:4 are for timeout approaching - applies if above upper threshold * @state_lock: ensure consistent state of this structure wrt the * hardware. * @interrupts: one or two interrupt numbers depending on device type. * @int_enabled: is a given interrupt currently enabled. * @type: threshold type * @dir: threshold direction
*/ struct ad7150_chip_info { struct i2c_client *client;
u16 threshold[2][2];
u8 thresh_sensitivity[2][2];
u8 thresh_timeout[2][2]; struct mutex state_lock; int interrupts[2]; bool int_enabled[2]; enum iio_event_type type; enum iio_event_direction dir;
};
staticint ad7150_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct ad7150_chip_info *chip = iio_priv(indio_dev); int channel = chan->channel; int ret;
switch (mask) { case IIO_CHAN_INFO_RAW:
ret = i2c_smbus_read_word_swapped(chip->client,
ad7150_addresses[channel][0]); if (ret < 0) return ret;
*val = ret >> 4;
return IIO_VAL_INT; case IIO_CHAN_INFO_AVERAGE_RAW:
ret = i2c_smbus_read_word_swapped(chip->client,
ad7150_addresses[channel][1]); if (ret < 0) return ret;
*val = ret;
return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: /* * Base units for capacitance are nano farads and the value * calculated from the datasheet formula is in picofarad * so multiply by 1000
*/
*val = 1000;
*val2 = 40944 >> 4; /* To match shift in _RAW */ return IIO_VAL_FRACTIONAL; case IIO_CHAN_INFO_OFFSET:
*val = -(12288 >> 4); /* To match shift in _RAW */ return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: /* Strangely same for both 1 and 2 chan parts */
*val = 100; return IIO_VAL_INT; default: return -EINVAL;
}
}
/* state_lock should be held to ensure consistent state */ staticint ad7150_write_event_params(struct iio_dev *indio_dev, unsignedint chan, enum iio_event_type type, enum iio_event_direction dir)
{ struct ad7150_chip_info *chip = iio_priv(indio_dev); int rising = (dir == IIO_EV_DIR_RISING);
/* Only update value live, if parameter is in use */ if ((type != chip->type) || (dir != chip->dir)) return 0;
switch (type) { /* Note completely different from the adaptive versions */ case IIO_EV_TYPE_THRESH: {
u16 value = chip->threshold[rising][chan]; return i2c_smbus_write_word_swapped(chip->client,
ad7150_addresses[chan][3],
value);
} case IIO_EV_TYPE_THRESH_ADAPTIVE: { int ret;
u8 sens, timeout;
sens = chip->thresh_sensitivity[rising][chan];
ret = i2c_smbus_write_byte_data(chip->client,
ad7150_addresses[chan][4],
sens); if (ret) return ret;
/* * Single timeout register contains timeouts for both * directions.
*/
timeout = FIELD_PREP(AD7150_CH_TIMEOUT_APPROACHING,
chip->thresh_timeout[1][chan]);
timeout |= FIELD_PREP(AD7150_CH_TIMEOUT_RECEDING,
chip->thresh_timeout[0][chan]); return i2c_smbus_write_byte_data(chip->client,
ad7150_addresses[chan][5],
timeout);
} default: return -EINVAL;
}
}
/* * There is only a single shared control and no on chip * interrupt disables for the two interrupt lines. * So, enabling will switch the events configured to enable * whatever was most recently requested and if necessary enable_irq() * the interrupt and any disable will disable_irq() for that * channels interrupt.
*/ if (!state) { if ((chip->int_enabled[chan->channel]) &&
(type == chip->type) && (dir == chip->dir)) {
disable_irq(chip->interrupts[chan->channel]);
chip->int_enabled[chan->channel] = false;
} return 0;
}
mutex_lock(&chip->state_lock); if ((type != chip->type) || (dir != chip->dir)) { int rising = (dir == IIO_EV_DIR_RISING);
u8 thresh_type, cfg, fixed;
/* * Need to temporarily disable both interrupts if * enabled - this is to avoid races around changing * config and thresholds. * Note enable/disable_irq() are reference counted so * no need to check if already enabled.
*/
disable_irq(chip->interrupts[0]);
disable_irq(chip->interrupts[1]);
ret = i2c_smbus_read_byte_data(chip->client, AD7150_CFG_REG); if (ret < 0) goto error_ret;
cfg = ret & ~(AD7150_CFG_THRESHTYPE_MSK | AD7150_CFG_FIX);
ret = i2c_smbus_write_byte_data(chip->client, AD7150_CFG_REG,
cfg); if (ret < 0) goto error_ret;
/* * There is a potential race condition here, but not easy * to close given we can't disable the interrupt at the * chip side of things. Rely on the status bit.
*/
chip->type = type;
chip->dir = dir;
/* update control attributes */
ret = ad7150_write_event_params(indio_dev, chan->channel, type,
dir); if (ret) goto error_ret; /* reenable any irq's we disabled whilst changing mode */
enable_irq(chip->interrupts[0]);
enable_irq(chip->interrupts[1]);
} if (!chip->int_enabled[chan->channel]) {
enable_irq(chip->interrupts[chan->channel]);
chip->int_enabled[chan->channel] = true;
}
/* Complex register sharing going on here */ switch (info) { case IIO_EV_INFO_VALUE: switch (type) { case IIO_EV_TYPE_THRESH_ADAPTIVE:
*val = chip->thresh_sensitivity[rising][chan->channel]; return IIO_VAL_INT; case IIO_EV_TYPE_THRESH:
*val = chip->threshold[rising][chan->channel]; return IIO_VAL_INT; default: return -EINVAL;
} case IIO_EV_INFO_TIMEOUT:
*val = 0;
*val2 = chip->thresh_timeout[rising][chan->channel] * 10000; return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL;
}
}
staticint ad7150_write_event_value(struct iio_dev *indio_dev, conststruct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, enum iio_event_info info, int val, int val2)
{ int ret; struct ad7150_chip_info *chip = iio_priv(indio_dev); int rising = (dir == IIO_EV_DIR_RISING);
mutex_lock(&chip->state_lock); switch (info) { case IIO_EV_INFO_VALUE: switch (type) { case IIO_EV_TYPE_THRESH_ADAPTIVE:
chip->thresh_sensitivity[rising][chan->channel] = val; break; case IIO_EV_TYPE_THRESH:
chip->threshold[rising][chan->channel] = val; break; default:
ret = -EINVAL; goto error_ret;
} break; case IIO_EV_INFO_TIMEOUT: { /* * Raw timeout is in cycles of 10 msecs as long as both * channels are enabled. * In terms of INT_PLUS_MICRO, that is in units of 10,000
*/ int timeout = val2 / 10000;
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.