Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: adc: ad7606: add offset and phase calibration support

Add support for offset and phase calibration, only for
devices that support software mode, that are:

ad7606b
ad7606c-16
ad7606c-18

Tested-by: David Lechner <dlechner@baylibre.com>
Reviewed-by: Nuno Sá <nuno.sa@analog.com>
Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://patch.msgid.link/20250606-wip-bl-ad7606-calibration-v9-3-6e014a1f92a2@baylibre.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Angelo Dureghello and committed by
Jonathan Cameron
48d487dc 342c52dd

+169
+160
drivers/iio/adc/ad7606.c
··· 95 95 1, 2, 4, 8, 16, 32, 64, 128, 96 96 }; 97 97 98 + static const int ad7606_calib_offset_avail[3] = { 99 + -128, 1, 127, 100 + }; 101 + 102 + static const int ad7606c_18bit_calib_offset_avail[3] = { 103 + -512, 4, 508, 104 + }; 105 + 106 + static const int ad7606b_calib_phase_avail[][2] = { 107 + { 0, 0 }, { 0, 1250 }, { 0, 318750 }, 108 + }; 109 + 110 + static const int ad7606c_calib_phase_avail[][2] = { 111 + { 0, 0 }, { 0, 1000 }, { 0, 255000 }, 112 + }; 113 + 98 114 static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev, 99 115 struct iio_chan_spec *chan); 100 116 static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev, ··· 180 164 .scale_setup_cb = ad7606_16bit_chan_scale_setup, 181 165 .sw_setup_cb = ad7606b_sw_mode_setup, 182 166 .offload_storagebits = 32, 167 + .calib_offset_avail = ad7606_calib_offset_avail, 168 + .calib_phase_avail = ad7606b_calib_phase_avail, 183 169 }; 184 170 EXPORT_SYMBOL_NS_GPL(ad7606b_info, "IIO_AD7606"); 185 171 ··· 195 177 .scale_setup_cb = ad7606c_16bit_chan_scale_setup, 196 178 .sw_setup_cb = ad7606b_sw_mode_setup, 197 179 .offload_storagebits = 32, 180 + .calib_offset_avail = ad7606_calib_offset_avail, 181 + .calib_phase_avail = ad7606c_calib_phase_avail, 198 182 }; 199 183 EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, "IIO_AD7606"); 200 184 ··· 246 226 .scale_setup_cb = ad7606c_18bit_chan_scale_setup, 247 227 .sw_setup_cb = ad7606b_sw_mode_setup, 248 228 .offload_storagebits = 32, 229 + .calib_offset_avail = ad7606c_18bit_calib_offset_avail, 230 + .calib_phase_avail = ad7606c_calib_phase_avail, 249 231 }; 250 232 EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, "IIO_AD7606"); 251 233 ··· 703 681 return ret; 704 682 } 705 683 684 + static int ad7606_get_calib_offset(struct ad7606_state *st, int ch, int *val) 685 + { 686 + int ret; 687 + 688 + ret = st->bops->reg_read(st, AD7606_CALIB_OFFSET(ch)); 689 + if (ret < 0) 690 + return ret; 691 + 692 + *val = st->chip_info->calib_offset_avail[0] + 693 + ret * st->chip_info->calib_offset_avail[1]; 694 + 695 + return 0; 696 + } 697 + 698 + static int ad7606_get_calib_phase(struct ad7606_state *st, int ch, int *val, 699 + int *val2) 700 + { 701 + int ret; 702 + 703 + ret = st->bops->reg_read(st, AD7606_CALIB_PHASE(ch)); 704 + if (ret < 0) 705 + return ret; 706 + 707 + *val = 0; 708 + 709 + /* 710 + * ad7606b: phase delay from 0 to 318.75 μs in steps of 1.25 μs. 711 + * ad7606c-16/18: phase delay from 0 µs to 255 µs in steps of 1 µs. 712 + */ 713 + *val2 = ret * st->chip_info->calib_phase_avail[1][1]; 714 + 715 + return 0; 716 + } 717 + 706 718 static int ad7606_read_raw(struct iio_dev *indio_dev, 707 719 struct iio_chan_spec const *chan, 708 720 int *val, ··· 771 715 pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); 772 716 *val = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, cnvst_pwm_state.period); 773 717 return IIO_VAL_INT; 718 + case IIO_CHAN_INFO_CALIBBIAS: 719 + if (!iio_device_claim_direct(indio_dev)) 720 + return -EBUSY; 721 + ret = ad7606_get_calib_offset(st, chan->scan_index, val); 722 + iio_device_release_direct(indio_dev); 723 + if (ret) 724 + return ret; 725 + return IIO_VAL_INT; 726 + case IIO_CHAN_INFO_CONVDELAY: 727 + if (!iio_device_claim_direct(indio_dev)) 728 + return -EBUSY; 729 + ret = ad7606_get_calib_phase(st, chan->scan_index, val, val2); 730 + iio_device_release_direct(indio_dev); 731 + if (ret) 732 + return ret; 733 + return IIO_VAL_INT_PLUS_NANO; 774 734 } 775 735 return -EINVAL; 776 736 } ··· 835 763 ad7606_reset(st); 836 764 837 765 return 0; 766 + } 767 + 768 + static int ad7606_set_calib_offset(struct ad7606_state *st, int ch, int val) 769 + { 770 + int start_val, step_val, stop_val; 771 + int offset; 772 + 773 + start_val = st->chip_info->calib_offset_avail[0]; 774 + step_val = st->chip_info->calib_offset_avail[1]; 775 + stop_val = st->chip_info->calib_offset_avail[2]; 776 + 777 + if (val < start_val || val > stop_val) 778 + return -EINVAL; 779 + 780 + offset = (val - start_val) / step_val; 781 + 782 + return st->bops->reg_write(st, AD7606_CALIB_OFFSET(ch), offset); 783 + } 784 + 785 + static int ad7606_set_calib_phase(struct ad7606_state *st, int ch, int val, 786 + int val2) 787 + { 788 + int wreg, start_ns, step_ns, stop_ns; 789 + 790 + if (val != 0) 791 + return -EINVAL; 792 + 793 + start_ns = st->chip_info->calib_phase_avail[0][1]; 794 + step_ns = st->chip_info->calib_phase_avail[1][1]; 795 + stop_ns = st->chip_info->calib_phase_avail[2][1]; 796 + 797 + /* 798 + * ad7606b: phase delay from 0 to 318.75 μs in steps of 1.25 μs. 799 + * ad7606c-16/18: phase delay from 0 µs to 255 µs in steps of 1 µs. 800 + */ 801 + if (val2 < start_ns || val2 > stop_ns) 802 + return -EINVAL; 803 + 804 + wreg = val2 / step_ns; 805 + 806 + return st->bops->reg_write(st, AD7606_CALIB_PHASE(ch), wreg); 807 + } 808 + 809 + static int ad7606_write_raw_get_fmt(struct iio_dev *indio_dev, 810 + struct iio_chan_spec const *chan, long info) 811 + { 812 + switch (info) { 813 + case IIO_CHAN_INFO_SCALE: 814 + return IIO_VAL_INT_PLUS_MICRO; 815 + case IIO_CHAN_INFO_SAMP_FREQ: 816 + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 817 + case IIO_CHAN_INFO_CALIBBIAS: 818 + return IIO_VAL_INT; 819 + case IIO_CHAN_INFO_CONVDELAY: 820 + return IIO_VAL_INT_PLUS_NANO; 821 + default: 822 + return -EINVAL; 823 + } 838 824 } 839 825 840 826 static int ad7606_write_raw(struct iio_dev *indio_dev, ··· 948 818 if (val < 0 && val2 != 0) 949 819 return -EINVAL; 950 820 return ad7606_set_sampling_freq(st, val); 821 + case IIO_CHAN_INFO_CALIBBIAS: 822 + if (!iio_device_claim_direct(indio_dev)) 823 + return -EBUSY; 824 + ret = ad7606_set_calib_offset(st, chan->scan_index, val); 825 + iio_device_release_direct(indio_dev); 826 + return ret; 827 + case IIO_CHAN_INFO_CONVDELAY: 828 + if (!iio_device_claim_direct(indio_dev)) 829 + return -EBUSY; 830 + ret = ad7606_set_calib_phase(st, chan->scan_index, val, val2); 831 + iio_device_release_direct(indio_dev); 832 + return ret; 951 833 default: 952 834 return -EINVAL; 953 835 } ··· 1138 996 *type = IIO_VAL_INT_PLUS_MICRO; 1139 997 1140 998 return IIO_AVAIL_LIST; 999 + case IIO_CHAN_INFO_CALIBBIAS: 1000 + *vals = st->chip_info->calib_offset_avail; 1001 + *type = IIO_VAL_INT; 1002 + return IIO_AVAIL_RANGE; 1003 + case IIO_CHAN_INFO_CONVDELAY: 1004 + *vals = (const int *)st->chip_info->calib_phase_avail; 1005 + *type = IIO_VAL_INT_PLUS_NANO; 1006 + return IIO_AVAIL_RANGE; 1141 1007 } 1142 1008 return -EINVAL; 1143 1009 } ··· 1208 1058 .read_raw = &ad7606_read_raw, 1209 1059 .write_raw = &ad7606_write_raw, 1210 1060 .read_avail = &ad7606_read_avail, 1061 + .write_raw_get_fmt = ad7606_write_raw_get_fmt, 1211 1062 .debugfs_reg_access = &ad7606_reg_access, 1212 1063 .validate_trigger = &ad7606_validate_trigger, 1213 1064 .update_scan_mode = &ad7606_update_scan_mode, ··· 1400 1249 chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE); 1401 1250 chan->info_mask_separate_available |= 1402 1251 BIT(IIO_CHAN_INFO_SCALE); 1252 + 1253 + if (st->chip_info->calib_offset_avail) { 1254 + chan->info_mask_separate |= 1255 + BIT(IIO_CHAN_INFO_CALIBBIAS) | 1256 + BIT(IIO_CHAN_INFO_CONVDELAY); 1257 + chan->info_mask_separate_available |= 1258 + BIT(IIO_CHAN_INFO_CALIBBIAS) | 1259 + BIT(IIO_CHAN_INFO_CONVDELAY); 1260 + } 1403 1261 1404 1262 /* 1405 1263 * All chips with software mode support oversampling,
+9
drivers/iio/adc/ad7606.h
··· 40 40 #define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1)) 41 41 #define AD7606_OS_MODE 0x08 42 42 43 + #define AD7606_CALIB_GAIN(ch) (0x09 + (ch)) 44 + #define AD7606_CALIB_GAIN_MASK GENMASK(5, 0) 45 + #define AD7606_CALIB_OFFSET(ch) (0x11 + (ch)) 46 + #define AD7606_CALIB_PHASE(ch) (0x19 + (ch)) 47 + 43 48 struct ad7606_state; 44 49 45 50 typedef int (*ad7606_scale_setup_cb_t)(struct iio_dev *indio_dev, ··· 66 61 * @init_delay_ms: required delay in milliseconds for initialization 67 62 * after a restart 68 63 * @offload_storagebits: storage bits used by the offload hw implementation 64 + * @calib_offset_avail: pointer to offset calibration range/limits array 65 + * @calib_phase_avail: pointer to phase calibration range/limits array 69 66 */ 70 67 struct ad7606_chip_info { 71 68 unsigned int max_samplerate; ··· 81 74 bool os_req_reset; 82 75 unsigned long init_delay_ms; 83 76 u8 offload_storagebits; 77 + const int *calib_offset_avail; 78 + const int (*calib_phase_avail)[2]; 84 79 }; 85 80 86 81 /**