Skip to content

Commit 7763e40

Browse files
dlechjic23
authored andcommitted
iio: adc: ad4695: implement calibration support
The AD4695 has a calibration feature that allows the user to compensate for variations in the analog front end. This implements this feature in the driver using the standard `calibgain` and `calibbias` attributes. Signed-off-by: David Lechner <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jonathan Cameron <[email protected]>
1 parent 2ba49fc commit 7763e40

File tree

1 file changed

+156
-2
lines changed

1 file changed

+156
-2
lines changed

drivers/iio/adc/ad4695.c

Lines changed: 156 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/iio/iio.h>
2424
#include <linux/iio/triggered_buffer.h>
2525
#include <linux/iio/trigger_consumer.h>
26+
#include <linux/minmax.h>
2627
#include <linux/property.h>
2728
#include <linux/regmap.h>
2829
#include <linux/regulator/consumer.h>
@@ -225,7 +226,11 @@ static const struct iio_chan_spec ad4695_channel_template = {
225226
.indexed = 1,
226227
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
227228
BIT(IIO_CHAN_INFO_SCALE) |
228-
BIT(IIO_CHAN_INFO_OFFSET),
229+
BIT(IIO_CHAN_INFO_OFFSET) |
230+
BIT(IIO_CHAN_INFO_CALIBSCALE) |
231+
BIT(IIO_CHAN_INFO_CALIBBIAS),
232+
.info_mask_separate_available = BIT(IIO_CHAN_INFO_CALIBSCALE) |
233+
BIT(IIO_CHAN_INFO_CALIBBIAS),
229234
.scan_type = {
230235
.sign = 'u',
231236
.realbits = 16,
@@ -619,7 +624,8 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
619624
struct ad4695_state *st = iio_priv(indio_dev);
620625
struct ad4695_channel_config *cfg = &st->channels_cfg[chan->scan_index];
621626
u8 realbits = chan->scan_type.realbits;
622-
int ret;
627+
unsigned int reg_val;
628+
int ret, tmp;
623629

624630
switch (mask) {
625631
case IIO_CHAN_INFO_RAW:
@@ -670,6 +676,152 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
670676
default:
671677
return -EINVAL;
672678
}
679+
case IIO_CHAN_INFO_CALIBSCALE:
680+
switch (chan->type) {
681+
case IIO_VOLTAGE:
682+
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
683+
ret = regmap_read(st->regmap16,
684+
AD4695_REG_GAIN_IN(chan->scan_index),
685+
&reg_val);
686+
if (ret)
687+
return ret;
688+
689+
*val = reg_val;
690+
*val2 = 15;
691+
692+
return IIO_VAL_FRACTIONAL_LOG2;
693+
}
694+
unreachable();
695+
default:
696+
return -EINVAL;
697+
}
698+
case IIO_CHAN_INFO_CALIBBIAS:
699+
switch (chan->type) {
700+
case IIO_VOLTAGE:
701+
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
702+
ret = regmap_read(st->regmap16,
703+
AD4695_REG_OFFSET_IN(chan->scan_index),
704+
&reg_val);
705+
if (ret)
706+
return ret;
707+
708+
tmp = sign_extend32(reg_val, 15);
709+
710+
*val = tmp / 4;
711+
*val2 = abs(tmp) % 4 * MICRO / 4;
712+
713+
if (tmp < 0 && *val2) {
714+
*val *= -1;
715+
*val2 *= -1;
716+
}
717+
718+
return IIO_VAL_INT_PLUS_MICRO;
719+
}
720+
unreachable();
721+
default:
722+
return -EINVAL;
723+
}
724+
default:
725+
return -EINVAL;
726+
}
727+
}
728+
729+
static int ad4695_write_raw(struct iio_dev *indio_dev,
730+
struct iio_chan_spec const *chan,
731+
int val, int val2, long mask)
732+
{
733+
struct ad4695_state *st = iio_priv(indio_dev);
734+
unsigned int reg_val;
735+
736+
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
737+
switch (mask) {
738+
case IIO_CHAN_INFO_CALIBSCALE:
739+
switch (chan->type) {
740+
case IIO_VOLTAGE:
741+
if (val < 0 || val2 < 0)
742+
reg_val = 0;
743+
else if (val > 1)
744+
reg_val = U16_MAX;
745+
else
746+
reg_val = (val * (1 << 16) +
747+
mul_u64_u32_div(val2, 1 << 16,
748+
MICRO)) / 2;
749+
750+
return regmap_write(st->regmap16,
751+
AD4695_REG_GAIN_IN(chan->scan_index),
752+
reg_val);
753+
default:
754+
return -EINVAL;
755+
}
756+
case IIO_CHAN_INFO_CALIBBIAS:
757+
switch (chan->type) {
758+
case IIO_VOLTAGE:
759+
if (val2 >= 0 && val > S16_MAX / 4)
760+
reg_val = S16_MAX;
761+
else if ((val2 < 0 ? -val : val) < S16_MIN / 4)
762+
reg_val = S16_MIN;
763+
else if (val2 < 0)
764+
reg_val = clamp_t(int,
765+
-(val * 4 + -val2 * 4 / MICRO),
766+
S16_MIN, S16_MAX);
767+
else if (val < 0)
768+
reg_val = clamp_t(int,
769+
val * 4 - val2 * 4 / MICRO,
770+
S16_MIN, S16_MAX);
771+
else
772+
reg_val = clamp_t(int,
773+
val * 4 + val2 * 4 / MICRO,
774+
S16_MIN, S16_MAX);
775+
776+
return regmap_write(st->regmap16,
777+
AD4695_REG_OFFSET_IN(chan->scan_index),
778+
reg_val);
779+
default:
780+
return -EINVAL;
781+
}
782+
default:
783+
return -EINVAL;
784+
}
785+
}
786+
unreachable();
787+
}
788+
789+
static int ad4695_read_avail(struct iio_dev *indio_dev,
790+
struct iio_chan_spec const *chan,
791+
const int **vals, int *type, int *length,
792+
long mask)
793+
{
794+
static const int ad4695_calibscale_available[6] = {
795+
/* Range of 0 (inclusive) to 2 (exclusive) */
796+
0, 15, 1, 15, U16_MAX, 15
797+
};
798+
static const int ad4695_calibbias_available[6] = {
799+
/*
800+
* Datasheet says FSR/8 which translates to signed/4. The step
801+
* depends on oversampling ratio which is always 1 for now.
802+
*/
803+
S16_MIN / 4, 0, 0, MICRO / 4, S16_MAX / 4, S16_MAX % 4 * MICRO / 4
804+
};
805+
806+
switch (mask) {
807+
case IIO_CHAN_INFO_CALIBSCALE:
808+
switch (chan->type) {
809+
case IIO_VOLTAGE:
810+
*vals = ad4695_calibscale_available;
811+
*type = IIO_VAL_FRACTIONAL_LOG2;
812+
return IIO_AVAIL_RANGE;
813+
default:
814+
return -EINVAL;
815+
}
816+
case IIO_CHAN_INFO_CALIBBIAS:
817+
switch (chan->type) {
818+
case IIO_VOLTAGE:
819+
*vals = ad4695_calibbias_available;
820+
*type = IIO_VAL_INT_PLUS_MICRO;
821+
return IIO_AVAIL_RANGE;
822+
default:
823+
return -EINVAL;
824+
}
673825
default:
674826
return -EINVAL;
675827
}
@@ -705,6 +857,8 @@ static int ad4695_debugfs_reg_access(struct iio_dev *indio_dev,
705857

706858
static const struct iio_info ad4695_info = {
707859
.read_raw = &ad4695_read_raw,
860+
.write_raw = &ad4695_write_raw,
861+
.read_avail = &ad4695_read_avail,
708862
.debugfs_reg_access = &ad4695_debugfs_reg_access,
709863
};
710864

0 commit comments

Comments
 (0)