struct spear_adc_state { struct device *dev; struct adc_regs_spear3xx __iomem *adc_base_spear3xx; struct adc_regs_spear6xx __iomem *adc_base_spear6xx; struct clk *clk; struct completion completion; /* * Lock to protect the device state during a potential concurrent * read access from userspace. Reading a raw value requires a sequence * of register writes, then a wait for a completion callback, * and finally a register read, during which userspace could issue * another read request. This lock protects a read access from * ocurring before another one has finished.
*/ struct mutex lock;
u32 current_clk;
u32 sampling_freq;
u32 avg_samples;
u32 vref_external;
u32 value;
};
/* * Functions to access some SPEAr ADC register. Abstracted into * static inline functions, because of different register offsets * on different SoC variants (SPEAr300 vs SPEAr600 etc).
*/ staticvoid spear_adc_set_status(struct spear_adc_state *st, u32 val)
{
__raw_writel(val, &st->adc_base_spear6xx->status);
}
staticint spear_adc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct spear_adc_state *st = iio_priv(indio_dev);
u32 status;
switch (mask) { case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
status = FIELD_PREP(SPEAR_ADC_STATUS_CHANNEL_NUM_MASK, chan->channel) |
FIELD_PREP(SPEAR_ADC_STATUS_AVG_SAMPLE_MASK, st->avg_samples) |
SPEAR_ADC_STATUS_START_CONVERSION |
SPEAR_ADC_STATUS_ADC_ENABLE; if (st->vref_external == 0)
status |= SPEAR_ADC_STATUS_VREF_INTERNAL;
spear_adc_set_status(st, status);
wait_for_completion(&st->completion); /* set by ISR */
*val = st->value;
mutex_unlock(&st->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = st->vref_external;
*val2 = SPEAR_ADC_DATA_BITS; return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_SAMP_FREQ:
*val = st->current_clk; return IIO_VAL_INT;
}
return -EINVAL;
}
staticint spear_adc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ struct spear_adc_state *st = iio_priv(indio_dev); int ret = 0;
if (mask != IIO_CHAN_INFO_SAMP_FREQ) return -EINVAL;
mutex_lock(&st->lock);
if ((val < SPEAR_ADC_CLK_MIN) ||
(val > SPEAR_ADC_CLK_MAX) ||
(val2 != 0)) {
ret = -EINVAL; goto out;
}
/* * SPEAr600 has a different register layout than other SPEAr SoC's * (e.g. SPEAr3xx). Let's provide two register base addresses * to support multi-arch kernels.
*/
st->adc_base_spear6xx = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(st->adc_base_spear6xx)) return PTR_ERR(st->adc_base_spear6xx);
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.