1*6a533f56SPop Ioan Daniel // SPDX-License-Identifier: GPL-2.0-only 2*6a533f56SPop Ioan Daniel /* 3*6a533f56SPop Ioan Daniel * Analog Devices AD7405 driver 4*6a533f56SPop Ioan Daniel * 5*6a533f56SPop Ioan Daniel * Copyright 2025 Analog Devices Inc. 6*6a533f56SPop Ioan Daniel */ 7*6a533f56SPop Ioan Daniel 8*6a533f56SPop Ioan Daniel #include <linux/clk.h> 9*6a533f56SPop Ioan Daniel #include <linux/device.h> 10*6a533f56SPop Ioan Daniel #include <linux/err.h> 11*6a533f56SPop Ioan Daniel #include <linux/math64.h> 12*6a533f56SPop Ioan Daniel #include <linux/module.h> 13*6a533f56SPop Ioan Daniel #include <linux/mod_devicetable.h> 14*6a533f56SPop Ioan Daniel #include <linux/platform_device.h> 15*6a533f56SPop Ioan Daniel #include <linux/property.h> 16*6a533f56SPop Ioan Daniel #include <linux/regulator/consumer.h> 17*6a533f56SPop Ioan Daniel #include <linux/util_macros.h> 18*6a533f56SPop Ioan Daniel 19*6a533f56SPop Ioan Daniel #include <linux/iio/backend.h> 20*6a533f56SPop Ioan Daniel #include <linux/iio/iio.h> 21*6a533f56SPop Ioan Daniel 22*6a533f56SPop Ioan Daniel static const unsigned int ad7405_dec_rates_range[] = { 23*6a533f56SPop Ioan Daniel 32, 1, 4096, 24*6a533f56SPop Ioan Daniel }; 25*6a533f56SPop Ioan Daniel 26*6a533f56SPop Ioan Daniel struct ad7405_chip_info { 27*6a533f56SPop Ioan Daniel const char *name; 28*6a533f56SPop Ioan Daniel const unsigned int full_scale_mv; 29*6a533f56SPop Ioan Daniel }; 30*6a533f56SPop Ioan Daniel 31*6a533f56SPop Ioan Daniel struct ad7405_state { 32*6a533f56SPop Ioan Daniel struct iio_backend *back; 33*6a533f56SPop Ioan Daniel const struct ad7405_chip_info *info; 34*6a533f56SPop Ioan Daniel unsigned int ref_frequency; 35*6a533f56SPop Ioan Daniel unsigned int dec_rate; 36*6a533f56SPop Ioan Daniel }; 37*6a533f56SPop Ioan Daniel 38*6a533f56SPop Ioan Daniel static int ad7405_set_dec_rate(struct iio_dev *indio_dev, 39*6a533f56SPop Ioan Daniel const struct iio_chan_spec *chan, 40*6a533f56SPop Ioan Daniel unsigned int dec_rate) 41*6a533f56SPop Ioan Daniel { 42*6a533f56SPop Ioan Daniel struct ad7405_state *st = iio_priv(indio_dev); 43*6a533f56SPop Ioan Daniel int ret; 44*6a533f56SPop Ioan Daniel 45*6a533f56SPop Ioan Daniel if (dec_rate > 4096 || dec_rate < 32) 46*6a533f56SPop Ioan Daniel return -EINVAL; 47*6a533f56SPop Ioan Daniel 48*6a533f56SPop Ioan Daniel if (!iio_device_claim_direct(indio_dev)) 49*6a533f56SPop Ioan Daniel return -EBUSY; 50*6a533f56SPop Ioan Daniel 51*6a533f56SPop Ioan Daniel ret = iio_backend_oversampling_ratio_set(st->back, chan->scan_index, dec_rate); 52*6a533f56SPop Ioan Daniel iio_device_release_direct(indio_dev); 53*6a533f56SPop Ioan Daniel 54*6a533f56SPop Ioan Daniel if (ret < 0) 55*6a533f56SPop Ioan Daniel return ret; 56*6a533f56SPop Ioan Daniel 57*6a533f56SPop Ioan Daniel st->dec_rate = dec_rate; 58*6a533f56SPop Ioan Daniel 59*6a533f56SPop Ioan Daniel return 0; 60*6a533f56SPop Ioan Daniel } 61*6a533f56SPop Ioan Daniel 62*6a533f56SPop Ioan Daniel static int ad7405_read_raw(struct iio_dev *indio_dev, 63*6a533f56SPop Ioan Daniel const struct iio_chan_spec *chan, int *val, 64*6a533f56SPop Ioan Daniel int *val2, long info) 65*6a533f56SPop Ioan Daniel { 66*6a533f56SPop Ioan Daniel struct ad7405_state *st = iio_priv(indio_dev); 67*6a533f56SPop Ioan Daniel 68*6a533f56SPop Ioan Daniel switch (info) { 69*6a533f56SPop Ioan Daniel case IIO_CHAN_INFO_SCALE: 70*6a533f56SPop Ioan Daniel *val = st->info->full_scale_mv; 71*6a533f56SPop Ioan Daniel *val2 = indio_dev->channels[0].scan_type.realbits - 1; 72*6a533f56SPop Ioan Daniel return IIO_VAL_FRACTIONAL_LOG2; 73*6a533f56SPop Ioan Daniel case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 74*6a533f56SPop Ioan Daniel *val = st->dec_rate; 75*6a533f56SPop Ioan Daniel return IIO_VAL_INT; 76*6a533f56SPop Ioan Daniel case IIO_CHAN_INFO_SAMP_FREQ: 77*6a533f56SPop Ioan Daniel *val = DIV_ROUND_CLOSEST_ULL(st->ref_frequency, st->dec_rate); 78*6a533f56SPop Ioan Daniel return IIO_VAL_INT; 79*6a533f56SPop Ioan Daniel case IIO_CHAN_INFO_OFFSET: 80*6a533f56SPop Ioan Daniel *val = -(1 << (indio_dev->channels[0].scan_type.realbits - 1)); 81*6a533f56SPop Ioan Daniel return IIO_VAL_INT; 82*6a533f56SPop Ioan Daniel default: 83*6a533f56SPop Ioan Daniel return -EINVAL; 84*6a533f56SPop Ioan Daniel } 85*6a533f56SPop Ioan Daniel } 86*6a533f56SPop Ioan Daniel 87*6a533f56SPop Ioan Daniel static int ad7405_write_raw(struct iio_dev *indio_dev, 88*6a533f56SPop Ioan Daniel struct iio_chan_spec const *chan, int val, 89*6a533f56SPop Ioan Daniel int val2, long info) 90*6a533f56SPop Ioan Daniel { 91*6a533f56SPop Ioan Daniel switch (info) { 92*6a533f56SPop Ioan Daniel case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 93*6a533f56SPop Ioan Daniel if (val < 0) 94*6a533f56SPop Ioan Daniel return -EINVAL; 95*6a533f56SPop Ioan Daniel return ad7405_set_dec_rate(indio_dev, chan, val); 96*6a533f56SPop Ioan Daniel default: 97*6a533f56SPop Ioan Daniel return -EINVAL; 98*6a533f56SPop Ioan Daniel } 99*6a533f56SPop Ioan Daniel } 100*6a533f56SPop Ioan Daniel 101*6a533f56SPop Ioan Daniel static int ad7405_read_avail(struct iio_dev *indio_dev, 102*6a533f56SPop Ioan Daniel struct iio_chan_spec const *chan, 103*6a533f56SPop Ioan Daniel const int **vals, int *type, int *length, 104*6a533f56SPop Ioan Daniel long info) 105*6a533f56SPop Ioan Daniel { 106*6a533f56SPop Ioan Daniel switch (info) { 107*6a533f56SPop Ioan Daniel case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 108*6a533f56SPop Ioan Daniel *vals = ad7405_dec_rates_range; 109*6a533f56SPop Ioan Daniel *type = IIO_VAL_INT; 110*6a533f56SPop Ioan Daniel return IIO_AVAIL_RANGE; 111*6a533f56SPop Ioan Daniel default: 112*6a533f56SPop Ioan Daniel return -EINVAL; 113*6a533f56SPop Ioan Daniel } 114*6a533f56SPop Ioan Daniel } 115*6a533f56SPop Ioan Daniel 116*6a533f56SPop Ioan Daniel static const struct iio_info ad7405_iio_info = { 117*6a533f56SPop Ioan Daniel .read_raw = &ad7405_read_raw, 118*6a533f56SPop Ioan Daniel .write_raw = &ad7405_write_raw, 119*6a533f56SPop Ioan Daniel .read_avail = &ad7405_read_avail, 120*6a533f56SPop Ioan Daniel }; 121*6a533f56SPop Ioan Daniel 122*6a533f56SPop Ioan Daniel static const struct iio_chan_spec ad7405_channel = { 123*6a533f56SPop Ioan Daniel .type = IIO_VOLTAGE, 124*6a533f56SPop Ioan Daniel .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | 125*6a533f56SPop Ioan Daniel BIT(IIO_CHAN_INFO_OFFSET), 126*6a533f56SPop Ioan Daniel .info_mask_shared_by_all = IIO_CHAN_INFO_SAMP_FREQ | 127*6a533f56SPop Ioan Daniel BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 128*6a533f56SPop Ioan Daniel .info_mask_shared_by_all_available = 129*6a533f56SPop Ioan Daniel BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 130*6a533f56SPop Ioan Daniel .indexed = 1, 131*6a533f56SPop Ioan Daniel .channel = 0, 132*6a533f56SPop Ioan Daniel .channel2 = 1, 133*6a533f56SPop Ioan Daniel .differential = 1, 134*6a533f56SPop Ioan Daniel .scan_index = 0, 135*6a533f56SPop Ioan Daniel .scan_type = { 136*6a533f56SPop Ioan Daniel .sign = 'u', 137*6a533f56SPop Ioan Daniel .realbits = 16, 138*6a533f56SPop Ioan Daniel .storagebits = 16, 139*6a533f56SPop Ioan Daniel }, 140*6a533f56SPop Ioan Daniel }; 141*6a533f56SPop Ioan Daniel 142*6a533f56SPop Ioan Daniel static const struct ad7405_chip_info ad7405_chip_info = { 143*6a533f56SPop Ioan Daniel .name = "ad7405", 144*6a533f56SPop Ioan Daniel .full_scale_mv = 320, 145*6a533f56SPop Ioan Daniel }; 146*6a533f56SPop Ioan Daniel 147*6a533f56SPop Ioan Daniel static const struct ad7405_chip_info adum7701_chip_info = { 148*6a533f56SPop Ioan Daniel .name = "adum7701", 149*6a533f56SPop Ioan Daniel .full_scale_mv = 320, 150*6a533f56SPop Ioan Daniel }; 151*6a533f56SPop Ioan Daniel 152*6a533f56SPop Ioan Daniel static const struct ad7405_chip_info adum7702_chip_info = { 153*6a533f56SPop Ioan Daniel .name = "adum7702", 154*6a533f56SPop Ioan Daniel .full_scale_mv = 64, 155*6a533f56SPop Ioan Daniel }; 156*6a533f56SPop Ioan Daniel 157*6a533f56SPop Ioan Daniel static const struct ad7405_chip_info adum7703_chip_info = { 158*6a533f56SPop Ioan Daniel .name = "adum7703", 159*6a533f56SPop Ioan Daniel .full_scale_mv = 320, 160*6a533f56SPop Ioan Daniel }; 161*6a533f56SPop Ioan Daniel 162*6a533f56SPop Ioan Daniel static const char * const ad7405_power_supplies[] = { 163*6a533f56SPop Ioan Daniel "vdd1", "vdd2", 164*6a533f56SPop Ioan Daniel }; 165*6a533f56SPop Ioan Daniel 166*6a533f56SPop Ioan Daniel static int ad7405_probe(struct platform_device *pdev) 167*6a533f56SPop Ioan Daniel { 168*6a533f56SPop Ioan Daniel struct device *dev = &pdev->dev; 169*6a533f56SPop Ioan Daniel struct iio_dev *indio_dev; 170*6a533f56SPop Ioan Daniel struct ad7405_state *st; 171*6a533f56SPop Ioan Daniel struct clk *clk; 172*6a533f56SPop Ioan Daniel int ret; 173*6a533f56SPop Ioan Daniel 174*6a533f56SPop Ioan Daniel indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); 175*6a533f56SPop Ioan Daniel if (!indio_dev) 176*6a533f56SPop Ioan Daniel return -ENOMEM; 177*6a533f56SPop Ioan Daniel 178*6a533f56SPop Ioan Daniel st = iio_priv(indio_dev); 179*6a533f56SPop Ioan Daniel 180*6a533f56SPop Ioan Daniel st->info = device_get_match_data(dev); 181*6a533f56SPop Ioan Daniel if (!st->info) 182*6a533f56SPop Ioan Daniel return dev_err_probe(dev, -EINVAL, "no chip info\n"); 183*6a533f56SPop Ioan Daniel 184*6a533f56SPop Ioan Daniel ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad7405_power_supplies), 185*6a533f56SPop Ioan Daniel ad7405_power_supplies); 186*6a533f56SPop Ioan Daniel if (ret) 187*6a533f56SPop Ioan Daniel return dev_err_probe(dev, ret, "failed to get and enable supplies"); 188*6a533f56SPop Ioan Daniel 189*6a533f56SPop Ioan Daniel clk = devm_clk_get_enabled(dev, NULL); 190*6a533f56SPop Ioan Daniel if (IS_ERR(clk)) 191*6a533f56SPop Ioan Daniel return PTR_ERR(clk); 192*6a533f56SPop Ioan Daniel 193*6a533f56SPop Ioan Daniel st->ref_frequency = clk_get_rate(clk); 194*6a533f56SPop Ioan Daniel if (!st->ref_frequency) 195*6a533f56SPop Ioan Daniel return -EINVAL; 196*6a533f56SPop Ioan Daniel 197*6a533f56SPop Ioan Daniel indio_dev->name = st->info->name; 198*6a533f56SPop Ioan Daniel indio_dev->channels = &ad7405_channel; 199*6a533f56SPop Ioan Daniel indio_dev->num_channels = 1; 200*6a533f56SPop Ioan Daniel indio_dev->info = &ad7405_iio_info; 201*6a533f56SPop Ioan Daniel 202*6a533f56SPop Ioan Daniel st->back = devm_iio_backend_get(dev, NULL); 203*6a533f56SPop Ioan Daniel if (IS_ERR(st->back)) 204*6a533f56SPop Ioan Daniel return dev_err_probe(dev, PTR_ERR(st->back), 205*6a533f56SPop Ioan Daniel "failed to get IIO backend"); 206*6a533f56SPop Ioan Daniel 207*6a533f56SPop Ioan Daniel ret = iio_backend_chan_enable(st->back, 0); 208*6a533f56SPop Ioan Daniel if (ret) 209*6a533f56SPop Ioan Daniel return ret; 210*6a533f56SPop Ioan Daniel 211*6a533f56SPop Ioan Daniel ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); 212*6a533f56SPop Ioan Daniel if (ret) 213*6a533f56SPop Ioan Daniel return ret; 214*6a533f56SPop Ioan Daniel 215*6a533f56SPop Ioan Daniel ret = devm_iio_backend_enable(dev, st->back); 216*6a533f56SPop Ioan Daniel if (ret) 217*6a533f56SPop Ioan Daniel return ret; 218*6a533f56SPop Ioan Daniel 219*6a533f56SPop Ioan Daniel /* 220*6a533f56SPop Ioan Daniel * Set 256 decimation rate. The default value in the AXI_ADC register 221*6a533f56SPop Ioan Daniel * is 0, so we set the register with a decimation rate value that is 222*6a533f56SPop Ioan Daniel * functional for all parts. 223*6a533f56SPop Ioan Daniel */ 224*6a533f56SPop Ioan Daniel ret = ad7405_set_dec_rate(indio_dev, &indio_dev->channels[0], 256); 225*6a533f56SPop Ioan Daniel if (ret) 226*6a533f56SPop Ioan Daniel return ret; 227*6a533f56SPop Ioan Daniel 228*6a533f56SPop Ioan Daniel return devm_iio_device_register(dev, indio_dev); 229*6a533f56SPop Ioan Daniel } 230*6a533f56SPop Ioan Daniel 231*6a533f56SPop Ioan Daniel static const struct of_device_id ad7405_of_match[] = { 232*6a533f56SPop Ioan Daniel { .compatible = "adi,ad7405", .data = &ad7405_chip_info, }, 233*6a533f56SPop Ioan Daniel { .compatible = "adi,adum7701", .data = &adum7701_chip_info, }, 234*6a533f56SPop Ioan Daniel { .compatible = "adi,adum7702", .data = &adum7702_chip_info, }, 235*6a533f56SPop Ioan Daniel { .compatible = "adi,adum7703", .data = &adum7703_chip_info, }, 236*6a533f56SPop Ioan Daniel { } 237*6a533f56SPop Ioan Daniel }; 238*6a533f56SPop Ioan Daniel MODULE_DEVICE_TABLE(of, ad7405_of_match); 239*6a533f56SPop Ioan Daniel 240*6a533f56SPop Ioan Daniel static struct platform_driver ad7405_driver = { 241*6a533f56SPop Ioan Daniel .driver = { 242*6a533f56SPop Ioan Daniel .name = "ad7405", 243*6a533f56SPop Ioan Daniel .of_match_table = ad7405_of_match, 244*6a533f56SPop Ioan Daniel }, 245*6a533f56SPop Ioan Daniel .probe = ad7405_probe, 246*6a533f56SPop Ioan Daniel }; 247*6a533f56SPop Ioan Daniel module_platform_driver(ad7405_driver); 248*6a533f56SPop Ioan Daniel 249*6a533f56SPop Ioan Daniel MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>"); 250*6a533f56SPop Ioan Daniel MODULE_AUTHOR("Pop Ioan Daniel <pop.ioan-daniel@analog.com>"); 251*6a533f56SPop Ioan Daniel MODULE_DESCRIPTION("Analog Devices AD7405 driver"); 252*6a533f56SPop Ioan Daniel MODULE_LICENSE("GPL"); 253*6a533f56SPop Ioan Daniel MODULE_IMPORT_NS("IIO_BACKEND"); 254