#include <linux/regulator/driver.h>
 #include <linux/sysfs.h>
 #include <linux/spi/spi.h>
+#include <linux/unaligned.h>
+#include <linux/util_macros.h>
 
 #include <linux/iio/buffer.h>
 #include <linux/iio/iio.h>
 #define AD7768_PWR_PWRMODE(x)          FIELD_PREP(AD7768_PWR_PWRMODE_MSK, x)
 
 /* AD7768_REG_DIGITAL_FILTER */
+#define AD7768_DIG_FIL_EN_60HZ_REJ     BIT(7)
 #define AD7768_DIG_FIL_FIL_MSK         GENMASK(6, 4)
 #define AD7768_DIG_FIL_FIL(x)          FIELD_PREP(AD7768_DIG_FIL_FIL_MSK, x)
 #define AD7768_DIG_FIL_DEC_MSK         GENMASK(2, 0)
 
 #define AD7768_TRIGGER_SOURCE_SYNC_IDX 0
 
+#define AD7768_MAX_CHANNELS 1
+
 enum ad7768_conv_mode {
        AD7768_CONTINUOUS,
        AD7768_ONE_SHOT,
        AD7768_MCLK_DIV_2
 };
 
-enum ad7768_dec_rate {
-       AD7768_DEC_RATE_32 = 0,
-       AD7768_DEC_RATE_64 = 1,
-       AD7768_DEC_RATE_128 = 2,
-       AD7768_DEC_RATE_256 = 3,
-       AD7768_DEC_RATE_512 = 4,
-       AD7768_DEC_RATE_1024 = 5,
-       AD7768_DEC_RATE_8 = 9,
-       AD7768_DEC_RATE_16 = 10
+enum ad7768_filter_type {
+       AD7768_FILTER_SINC5,
+       AD7768_FILTER_SINC3,
+       AD7768_FILTER_WIDEBAND,
+       AD7768_FILTER_SINC3_REJ60,
 };
 
-struct ad7768_clk_configuration {
-       enum ad7768_mclk_div mclk_div;
-       enum ad7768_dec_rate dec_rate;
-       unsigned int clk_div;
-       enum ad7768_pwrmode pwrmode;
+enum ad7768_filter_regval {
+       AD7768_FILTER_REGVAL_SINC5 = 0,
+       AD7768_FILTER_REGVAL_SINC5_X8 = 1,
+       AD7768_FILTER_REGVAL_SINC5_X16 = 2,
+       AD7768_FILTER_REGVAL_SINC3 = 3,
+       AD7768_FILTER_REGVAL_WIDEBAND = 4,
+       AD7768_FILTER_REGVAL_SINC3_REJ60 = 11,
 };
 
 enum ad7768_scan_type {
        16, 8, 4, 2,
 };
 
-static const struct ad7768_clk_configuration ad7768_clk_config[] = {
-       { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_8, 16,  AD7768_FAST_MODE },
-       { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_16, 32,  AD7768_FAST_MODE },
-       { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_32, 64, AD7768_FAST_MODE },
-       { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_64, 128, AD7768_FAST_MODE },
-       { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_128, 256, AD7768_FAST_MODE },
-       { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_128, 512, AD7768_MED_MODE },
-       { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_256, 1024, AD7768_MED_MODE },
-       { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_512, 2048, AD7768_MED_MODE },
-       { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_1024, 4096, AD7768_MED_MODE },
-       { AD7768_MCLK_DIV_8, AD7768_DEC_RATE_1024, 8192, AD7768_MED_MODE },
-       { AD7768_MCLK_DIV_16, AD7768_DEC_RATE_1024, 16384, AD7768_ECO_MODE },
+static const int ad7768_dec_rate_values[8] = {
+       8, 16, 32, 64, 128, 256, 512, 1024,
+};
+
+/* Decimation rate range for sinc3 filter */
+static const int ad7768_sinc3_dec_rate_range[3] = {
+       32, 32, 163840,
+};
+
+/*
+ * The AD7768-1 supports three primary filter types:
+ * Sinc5, Sinc3, and Wideband.
+ * However, the filter register values can also encode additional parameters
+ * such as decimation rates and 60Hz rejection. This utility array separates
+ * the filter type from these parameters.
+ */
+static const int ad7768_filter_regval_to_type[] = {
+       [AD7768_FILTER_REGVAL_SINC5] = AD7768_FILTER_SINC5,
+       [AD7768_FILTER_REGVAL_SINC5_X8] = AD7768_FILTER_SINC5,
+       [AD7768_FILTER_REGVAL_SINC5_X16] = AD7768_FILTER_SINC5,
+       [AD7768_FILTER_REGVAL_SINC3] = AD7768_FILTER_SINC3,
+       [AD7768_FILTER_REGVAL_WIDEBAND] = AD7768_FILTER_WIDEBAND,
+       [AD7768_FILTER_REGVAL_SINC3_REJ60] = AD7768_FILTER_SINC3_REJ60,
+};
+
+static const char * const ad7768_filter_enum[] = {
+       [AD7768_FILTER_SINC5] = "sinc5",
+       [AD7768_FILTER_SINC3] = "sinc3",
+       [AD7768_FILTER_WIDEBAND] = "wideband",
+       [AD7768_FILTER_SINC3_REJ60] = "sinc3+rej60",
 };
 
 static const struct iio_scan_type ad7768_scan_type[] = {
        },
 };
 
-static const struct iio_chan_spec ad7768_channels[] = {
-       {
-               .type = IIO_VOLTAGE,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
-               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
-               .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
-               .indexed = 1,
-               .channel = 0,
-               .scan_index = 0,
-               .has_ext_scan_type = 1,
-               .ext_scan_type = ad7768_scan_type,
-               .num_ext_scan_type = ARRAY_SIZE(ad7768_scan_type),
-       },
-};
-
 struct ad7768_state {
        struct spi_device *spi;
        struct regmap *regmap;
        unsigned int vcm_output_sel;
        struct clk *mclk;
        unsigned int mclk_freq;
-       unsigned int dec_rate;
+       unsigned int mclk_div;
+       unsigned int oversampling_ratio;
+       enum ad7768_filter_type filter_type;
        unsigned int samp_freq;
-       unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_clk_config)];
+       unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_mclk_div_rates)];
+       unsigned int samp_freq_avail_len;
        struct completion completion;
        struct iio_trigger *trig;
        struct gpio_desc *gpio_sync_in;
        struct gpio_desc *gpio_reset;
-       const char *labels[ARRAY_SIZE(ad7768_channels)];
+       const char *labels[AD7768_MAX_CHANNELS];
        struct gpio_chip gpiochip;
        bool en_spi_sync;
        /*
 
 static void ad7768_fill_samp_freq_tbl(struct ad7768_state *st)
 {
-       unsigned int i;
+       unsigned int i, samp_freq_avail, freq_filtered;
+       unsigned int len = 0;
+
+       freq_filtered = DIV_ROUND_CLOSEST(st->mclk_freq, st->oversampling_ratio);
+       for (i = 0; i < ARRAY_SIZE(ad7768_mclk_div_rates); i++) {
+               samp_freq_avail = DIV_ROUND_CLOSEST(freq_filtered, ad7768_mclk_div_rates[i]);
+               /* Sampling frequency cannot be lower than the minimum of 50 SPS */
+               if (samp_freq_avail < 50)
+                       continue;
 
-       for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++)
-               st->samp_freq_avail[i] =
-                       DIV_ROUND_CLOSEST(st->mclk_freq, ad7768_clk_config[i].clk_div);
+               st->samp_freq_avail[len++] = samp_freq_avail;
+       }
+
+       st->samp_freq_avail_len = len;
+}
+
+static int ad7768_set_mclk_div(struct ad7768_state *st, unsigned int mclk_div)
+{
+       unsigned int mclk_div_value;
+
+       mclk_div_value = AD7768_PWR_MCLK_DIV(mclk_div);
+       /*
+        * Set power mode based on mclk_div value.
+        * ECO_MODE is only recommended for MCLK_DIV = 16.
+        */
+       mclk_div_value |= mclk_div > AD7768_MCLK_DIV_16 ?
+                         AD7768_PWR_PWRMODE(AD7768_FAST_MODE) :
+                         AD7768_PWR_PWRMODE(AD7768_ECO_MODE);
+
+       return regmap_update_bits(st->regmap, AD7768_REG_POWER_CLOCK,
+                                 AD7768_PWR_MCLK_DIV_MSK | AD7768_PWR_PWRMODE_MSK,
+                                 mclk_div_value);
 }
 
 static int ad7768_set_mode(struct ad7768_state *st,
         * register provides 24-bit data, the precision is reduced by
         * right-shifting the read value by 8 bits.
         */
-       if (st->dec_rate == 8)
+       if (st->oversampling_ratio == 8)
                readval >>= 8;
 
        /*
        return ret;
 }
 
-static int ad7768_set_dig_fil(struct ad7768_state *st,
-                             enum ad7768_dec_rate dec_rate)
+static int ad7768_set_sinc3_dec_rate(struct ad7768_state *st,
+                                    unsigned int dec_rate)
 {
-       unsigned int mode;
+       unsigned int max_dec_rate;
+       u8 dec_rate_reg[2];
+       u16 regval;
        int ret;
 
-       if (dec_rate == AD7768_DEC_RATE_8 || dec_rate == AD7768_DEC_RATE_16)
-               mode = AD7768_DIG_FIL_FIL(dec_rate);
-       else
-               mode = AD7768_DIG_FIL_DEC_RATE(dec_rate);
+       /*
+        * Maximum dec_rate is limited by the MCLK_DIV value and by the ODR.
+        * The edge case is for MCLK_DIV = 2, ODR = 50 SPS.
+        * max_dec_rate <= MCLK / (2 * 50)
+        */
+       max_dec_rate = st->mclk_freq / 100;
+       dec_rate = clamp(dec_rate, 32, max_dec_rate);
+       /*
+        * Calculate the equivalent value to sinc3 decimation ratio
+        * to be written on the SINC3_DEC_RATE register:
+        *  Value = (DEC_RATE / 32) - 1
+        */
+       dec_rate = DIV_ROUND_UP(dec_rate, 32) - 1;
 
-       ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, mode);
-       if (ret < 0)
+       /*
+        * The SINC3_DEC_RATE value is a 13-bit value split across two
+        * registers: MSB [12:8] and LSB [7:0]. Prepare the 13-bit value using
+        * FIELD_PREP() and store it with the right endianness in dec_rate_reg.
+        */
+       regval = FIELD_PREP(GENMASK(12, 0), dec_rate);
+       put_unaligned_be16(regval, dec_rate_reg);
+       ret = regmap_bulk_write(st->regmap, AD7768_REG_SINC3_DEC_RATE_MSB,
+                               dec_rate_reg, 2);
+       if (ret)
+               return ret;
+
+       st->oversampling_ratio = (dec_rate + 1) * 32;
+
+       return 0;
+}
+
+static int ad7768_configure_dig_fil(struct iio_dev *dev,
+                                   enum ad7768_filter_type filter_type,
+                                   unsigned int dec_rate)
+{
+       struct ad7768_state *st = iio_priv(dev);
+       unsigned int dec_rate_idx, dig_filter_regval;
+       int ret;
+
+       switch (filter_type) {
+       case AD7768_FILTER_SINC3:
+               dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC3);
+               break;
+       case AD7768_FILTER_SINC3_REJ60:
+               dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC3) |
+                                   AD7768_DIG_FIL_EN_60HZ_REJ;
+               break;
+       case AD7768_FILTER_WIDEBAND:
+               /* Skip decimations 8 and 16, not supported by the wideband filter */
+               dec_rate_idx = find_closest(dec_rate, &ad7768_dec_rate_values[2],
+                                           ARRAY_SIZE(ad7768_dec_rate_values) - 2);
+               dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_WIDEBAND) |
+                                   AD7768_DIG_FIL_DEC_RATE(dec_rate_idx);
+               /* Correct the index offset */
+               dec_rate_idx += 2;
+               break;
+       case AD7768_FILTER_SINC5:
+               dec_rate_idx = find_closest(dec_rate, ad7768_dec_rate_values,
+                                           ARRAY_SIZE(ad7768_dec_rate_values));
+
+               /*
+                * Decimations 8 (idx 0) and 16 (idx 1) are set in the
+                * FILTER[6:4] field. The other decimations are set in the
+                * DEC_RATE[2:0] field, and the idx needs to be offsetted by two.
+                */
+               if (dec_rate_idx == 0)
+                       dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5_X8);
+               else if (dec_rate_idx == 1)
+                       dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5_X16);
+               else
+                       dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5) |
+                                           AD7768_DIG_FIL_DEC_RATE(dec_rate_idx - 2);
+               break;
+       }
+
+       ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, dig_filter_regval);
+       if (ret)
                return ret;
 
-       /* A sync-in pulse is required every time the filter dec rate changes */
+       st->filter_type = filter_type;
+       /*
+        * The decimation for SINC3 filters are configured in different
+        * registers.
+        */
+       if (filter_type == AD7768_FILTER_SINC3 ||
+           filter_type == AD7768_FILTER_SINC3_REJ60) {
+               ret = ad7768_set_sinc3_dec_rate(st, dec_rate);
+               if (ret)
+                       return ret;
+       } else {
+               st->oversampling_ratio = ad7768_dec_rate_values[dec_rate_idx];
+       }
+
+       ad7768_fill_samp_freq_tbl(st);
+
+       /* A sync-in pulse is required after every configuration change */
        return ad7768_send_sync_pulse(st);
 }
 
 static int ad7768_set_freq(struct ad7768_state *st,
                           unsigned int freq)
 {
-       unsigned int diff_new, diff_old, pwr_mode, i, idx;
-       int res, ret;
-
-       diff_old = U32_MAX;
-       idx = 0;
+       unsigned int idx, mclk_div;
+       int ret;
 
-       res = DIV_ROUND_CLOSEST(st->mclk_freq, freq);
+       freq = clamp(freq, 50, 1024000);
+       if (freq == 0)
+               return -EINVAL;
 
+       mclk_div = DIV_ROUND_CLOSEST(st->mclk_freq, freq * st->oversampling_ratio);
        /* Find the closest match for the desired sampling frequency */
-       for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) {
-               diff_new = abs(res - ad7768_clk_config[i].clk_div);
-               if (diff_new < diff_old) {
-                       diff_old = diff_new;
-                       idx = i;
-               }
-       }
-
-       /*
-        * Set both the mclk_div and pwrmode with a single write to the
-        * POWER_CLOCK register
-        */
-       pwr_mode = AD7768_PWR_MCLK_DIV(ad7768_clk_config[idx].mclk_div) |
-                  AD7768_PWR_PWRMODE(ad7768_clk_config[idx].pwrmode);
-       ret = regmap_write(st->regmap, AD7768_REG_POWER_CLOCK, pwr_mode);
-       if (ret < 0)
+       idx = find_closest_descending(mclk_div, ad7768_mclk_div_rates,
+                                     ARRAY_SIZE(ad7768_mclk_div_rates));
+       /* Set both the mclk_div and pwrmode */
+       ret = ad7768_set_mclk_div(st, idx);
+       if (ret)
                return ret;
 
-       ret =  ad7768_set_dig_fil(st, ad7768_clk_config[idx].dec_rate);
-       if (ret < 0)
+       st->samp_freq = DIV_ROUND_CLOSEST(st->mclk_freq,
+                                         ad7768_mclk_div_rates[idx] * st->oversampling_ratio);
+
+       /* A sync-in pulse is required after every configuration change */
+       return ad7768_send_sync_pulse(st);
+}
+
+static int ad7768_set_filter_type_attr(struct iio_dev *dev,
+                                      const struct iio_chan_spec *chan,
+                                      unsigned int filter)
+{
+       struct ad7768_state *st = iio_priv(dev);
+       int ret;
+
+       ret = ad7768_configure_dig_fil(dev, filter, st->oversampling_ratio);
+       if (ret)
                return ret;
 
-       st->dec_rate = ad7768_clk_config[idx].clk_div /
-                      ad7768_mclk_div_rates[ad7768_clk_config[idx].mclk_div];
-       st->samp_freq = DIV_ROUND_CLOSEST(st->mclk_freq,
-                                         ad7768_clk_config[idx].clk_div);
+       /* Update sampling frequency */
+       return ad7768_set_freq(st, st->samp_freq);
+}
 
-       return 0;
+static int ad7768_get_filter_type_attr(struct iio_dev *dev,
+                                      const struct iio_chan_spec *chan)
+{
+       struct ad7768_state *st = iio_priv(dev);
+       int ret;
+       unsigned int mode, mask;
+
+       ret = regmap_read(st->regmap, AD7768_REG_DIGITAL_FILTER, &mode);
+       if (ret)
+               return ret;
+
+       mask = AD7768_DIG_FIL_EN_60HZ_REJ | AD7768_DIG_FIL_FIL_MSK;
+       /* From the register value, get the corresponding filter type */
+       return ad7768_filter_regval_to_type[FIELD_GET(mask, mode)];
 }
 
+static const struct iio_enum ad7768_filter_type_iio_enum = {
+       .items = ad7768_filter_enum,
+       .num_items = ARRAY_SIZE(ad7768_filter_enum),
+       .set = ad7768_set_filter_type_attr,
+       .get = ad7768_get_filter_type_attr,
+};
+
+static const struct iio_chan_spec_ext_info ad7768_ext_info[] = {
+       IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ad7768_filter_type_iio_enum),
+       IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL, &ad7768_filter_type_iio_enum),
+       { }
+};
+
+static const struct iio_chan_spec ad7768_channels[] = {
+       {
+               .type = IIO_VOLTAGE,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
+                                           BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .ext_info = ad7768_ext_info,
+               .indexed = 1,
+               .channel = 0,
+               .scan_index = 0,
+               .has_ext_scan_type = 1,
+               .ext_scan_type = ad7768_scan_type,
+               .num_ext_scan_type = ARRAY_SIZE(ad7768_scan_type),
+       },
+};
+
 static int ad7768_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan,
                           int *val, int *val2, long info)
        case IIO_CHAN_INFO_SAMP_FREQ:
                *val = st->samp_freq;
 
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               *val = st->oversampling_ratio;
+
                return IIO_VAL_INT;
        }
 
                             long info)
 {
        struct ad7768_state *st = iio_priv(indio_dev);
+       unsigned int shift;
 
        switch (info) {
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               /*
+                * Sinc3 filter allows a wider range of OSR values, so show
+                * the available values in range format.
+                */
+               if (st->filter_type == AD7768_FILTER_SINC3 ||
+                   st->filter_type == AD7768_FILTER_SINC3_REJ60) {
+                       *vals = (int *)ad7768_sinc3_dec_rate_range;
+                       *type = IIO_VAL_INT;
+                       return IIO_AVAIL_RANGE;
+               }
+
+               shift = st->filter_type == AD7768_FILTER_SINC5 ? 0 : 2;
+               *vals = (int *)&ad7768_dec_rate_values[shift];
+               *length = ARRAY_SIZE(ad7768_dec_rate_values) - shift;
+               *type = IIO_VAL_INT;
+               return IIO_AVAIL_LIST;
        case IIO_CHAN_INFO_SAMP_FREQ:
                *vals = (int *)st->samp_freq_avail;
-               *length = ARRAY_SIZE(ad7768_clk_config);
+               *length = st->samp_freq_avail_len;
                *type = IIO_VAL_INT;
                return IIO_AVAIL_LIST;
        default:
        }
 }
 
-static int ad7768_write_raw(struct iio_dev *indio_dev,
-                           struct iio_chan_spec const *chan,
-                           int val, int val2, long info)
+static int __ad7768_write_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             int val, int val2, long info)
 {
        struct ad7768_state *st = iio_priv(indio_dev);
+       int ret;
 
        switch (info) {
        case IIO_CHAN_INFO_SAMP_FREQ:
                return ad7768_set_freq(st, val);
+
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               ret = ad7768_configure_dig_fil(indio_dev, st->filter_type, val);
+               if (ret)
+                       return ret;
+
+               /* Update sampling frequency */
+               return ad7768_set_freq(st, st->samp_freq);
        default:
                return -EINVAL;
        }
 }
 
+static int ad7768_write_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int val, int val2, long info)
+{
+       int ret;
+
+       if (!iio_device_claim_direct(indio_dev))
+               return -EBUSY;
+
+       ret = __ad7768_write_raw(indio_dev, chan, val, val2, info);
+       iio_device_release_direct(indio_dev);
+
+       return ret;
+}
+
 static int ad7768_read_label(struct iio_dev *indio_dev,
        const struct iio_chan_spec *chan, char *label)
 {
 {
        struct ad7768_state *st = iio_priv(indio_dev);
 
-       return st->dec_rate == 8 ?
+       return st->oversampling_ratio == 8 ?
               AD7768_SCAN_TYPE_HIGH_SPEED : AD7768_SCAN_TYPE_NORMAL;
 }
 
                        return ret;
        }
 
+       /*
+        * Set Default Digital Filter configuration:
+        * SINC5 filter with x32 Decimation rate
+        */
+       ret = ad7768_configure_dig_fil(indio_dev, AD7768_FILTER_SINC5, 32);
+       if (ret)
+               return ret;
+
        /* Set the default sampling frequency to 32000 kSPS */
        return ad7768_set_freq(st, 32000);
 }
                return PTR_ERR(st->mclk);
 
        st->mclk_freq = clk_get_rate(st->mclk);
-       ad7768_fill_samp_freq_tbl(st);
 
        indio_dev->channels = ad7768_channels;
        indio_dev->num_channels = ARRAY_SIZE(ad7768_channels);