iio: adc: meson: support reading from channel 7 mux inputs
authorGeorge Stark <gnstark@sberdevices.ru>
Fri, 14 Jul 2023 11:37:53 +0000 (14:37 +0300)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Thu, 20 Jul 2023 18:21:31 +0000 (19:21 +0100)
Add IIO channel for all muxed inputs of channel 7.
Meson saradc channel 7 is connected to a mux that can switch input
to well-known sources like Vdd, GND and several Vdd dividers.

Signed-off-by: George Stark <GNStark@sberdevices.ru>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20230714114010.293440-7-gnstark@sberdevices.ru
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/adc/meson_saradc.c

index b8c01a8..81659c0 100644 (file)
 #define MESON_SAR_ADC_MAX_FIFO_SIZE                            32
 #define MESON_SAR_ADC_TIMEOUT                                  100 /* ms */
 #define MESON_SAR_ADC_VOLTAGE_AND_TEMP_CHANNEL                 6
+#define MESON_SAR_ADC_VOLTAGE_AND_MUX_CHANNEL                  7
 #define MESON_SAR_ADC_TEMP_OFFSET                              27
 
 /* temperature sensor calibration information in eFuse */
        .datasheet_name = "TEMP_SENSOR",                                \
 }
 
+#define MESON_SAR_ADC_MUX(_chan, _sel) {                               \
+       .type = IIO_VOLTAGE,                                            \
+       .channel = _chan,                                               \
+       .indexed = 1,                                                   \
+       .address = MESON_SAR_ADC_VOLTAGE_AND_MUX_CHANNEL,               \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                  \
+                               BIT(IIO_CHAN_INFO_AVERAGE_RAW),         \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),           \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_CALIBBIAS) |       \
+                               BIT(IIO_CHAN_INFO_CALIBSCALE),          \
+       .datasheet_name = "SAR_ADC_MUX_"#_sel,                          \
+}
+
 enum meson_sar_adc_avg_mode {
        NO_AVERAGING = 0x0,
        MEAN_AVERAGING = 0x1,
@@ -234,6 +248,27 @@ enum meson_sar_adc_channel_index {
        NUM_CHAN_6,
        NUM_CHAN_7,
        NUM_CHAN_TEMP,
+       NUM_MUX_0_VSS,
+       NUM_MUX_1_VDD_DIV4,
+       NUM_MUX_2_VDD_DIV2,
+       NUM_MUX_3_VDD_MUL3_DIV4,
+       NUM_MUX_4_VDD,
+};
+
+static enum meson_sar_adc_chan7_mux_sel chan7_mux_values[] = {
+       CHAN7_MUX_VSS,
+       CHAN7_MUX_VDD_DIV4,
+       CHAN7_MUX_VDD_DIV2,
+       CHAN7_MUX_VDD_MUL3_DIV4,
+       CHAN7_MUX_VDD,
+};
+
+static const char * const chan7_mux_names[] = {
+       [CHAN7_MUX_VSS] = "gnd",
+       [CHAN7_MUX_VDD_DIV4] = "0.25vdd",
+       [CHAN7_MUX_VDD_DIV2] = "0.5vdd",
+       [CHAN7_MUX_VDD_MUL3_DIV4] = "0.75vdd",
+       [CHAN7_MUX_VDD] = "vdd",
 };
 
 static const struct iio_chan_spec meson_sar_adc_iio_channels[] = {
@@ -245,6 +280,11 @@ static const struct iio_chan_spec meson_sar_adc_iio_channels[] = {
        MESON_SAR_ADC_CHAN(NUM_CHAN_5),
        MESON_SAR_ADC_CHAN(NUM_CHAN_6),
        MESON_SAR_ADC_CHAN(NUM_CHAN_7),
+       MESON_SAR_ADC_MUX(NUM_MUX_0_VSS, 0),
+       MESON_SAR_ADC_MUX(NUM_MUX_1_VDD_DIV4, 1),
+       MESON_SAR_ADC_MUX(NUM_MUX_2_VDD_DIV2, 2),
+       MESON_SAR_ADC_MUX(NUM_MUX_3_VDD_MUL3_DIV4, 3),
+       MESON_SAR_ADC_MUX(NUM_MUX_4_VDD, 4),
 };
 
 static const struct iio_chan_spec meson_sar_adc_and_temp_iio_channels[] = {
@@ -257,6 +297,11 @@ static const struct iio_chan_spec meson_sar_adc_and_temp_iio_channels[] = {
        MESON_SAR_ADC_CHAN(NUM_CHAN_6),
        MESON_SAR_ADC_CHAN(NUM_CHAN_7),
        MESON_SAR_ADC_TEMP_CHAN(NUM_CHAN_TEMP),
+       MESON_SAR_ADC_MUX(NUM_MUX_0_VSS, 0),
+       MESON_SAR_ADC_MUX(NUM_MUX_1_VDD_DIV4, 1),
+       MESON_SAR_ADC_MUX(NUM_MUX_2_VDD_DIV2, 2),
+       MESON_SAR_ADC_MUX(NUM_MUX_3_VDD_MUL3_DIV4, 3),
+       MESON_SAR_ADC_MUX(NUM_MUX_4_VDD, 4),
 };
 
 struct meson_sar_adc_param {
@@ -295,6 +340,7 @@ struct meson_sar_adc_priv {
        bool                                    temperature_sensor_calibrated;
        u8                                      temperature_sensor_coefficient;
        u16                                     temperature_sensor_adc_val;
+       enum meson_sar_adc_chan7_mux_sel        chan7_mux_sel;
 };
 
 static const struct regmap_config meson_sar_adc_regmap_config_gxbb = {
@@ -311,6 +357,17 @@ static const struct regmap_config meson_sar_adc_regmap_config_meson8 = {
        .max_register = MESON_SAR_ADC_DELTA_10,
 };
 
+static const struct iio_chan_spec *
+find_channel_by_num(struct iio_dev *indio_dev, int num)
+{
+       int i;
+
+       for (i = 0; i < indio_dev->num_channels; i++)
+               if (indio_dev->channels[i].channel == num)
+                       return &indio_dev->channels[i];
+       return NULL;
+}
+
 static unsigned int meson_sar_adc_get_fifo_count(struct iio_dev *indio_dev)
 {
        struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
@@ -359,6 +416,8 @@ static void meson_sar_adc_set_chan7_mux(struct iio_dev *indio_dev,
                           MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval);
 
        usleep_range(10, 20);
+
+       priv->chan7_mux_sel = sel;
 }
 
 static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev,
@@ -454,6 +513,15 @@ static void meson_sar_adc_enable_channel(struct iio_dev *indio_dev,
                regmap_update_bits(priv->regmap,
                                   MESON_SAR_ADC_DELTA_10,
                                   MESON_SAR_ADC_DELTA_10_TEMP_SEL, regval);
+       } else if (chan->address == MESON_SAR_ADC_VOLTAGE_AND_MUX_CHANNEL) {
+               enum meson_sar_adc_chan7_mux_sel sel;
+
+               if (chan->channel == NUM_CHAN_7)
+                       sel = CHAN7_MUX_CH7_INPUT;
+               else
+                       sel = chan7_mux_values[chan->channel - NUM_MUX_0_VSS];
+               if (sel != priv->chan7_mux_sel)
+                       meson_sar_adc_set_chan7_mux(indio_dev, sel);
        }
 }
 
@@ -1026,7 +1094,8 @@ static int meson_sar_adc_calib(struct iio_dev *indio_dev)
        meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_DIV4);
        usleep_range(10, 20);
        ret = meson_sar_adc_get_sample(indio_dev,
-                                      &indio_dev->channels[7],
+                                      find_channel_by_num(indio_dev,
+                                                          NUM_MUX_1_VDD_DIV4),
                                       MEAN_AVERAGING, EIGHT_SAMPLES, &value0);
        if (ret < 0)
                goto out;
@@ -1034,7 +1103,8 @@ static int meson_sar_adc_calib(struct iio_dev *indio_dev)
        meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_MUL3_DIV4);
        usleep_range(10, 20);
        ret = meson_sar_adc_get_sample(indio_dev,
-                                      &indio_dev->channels[7],
+                                      find_channel_by_num(indio_dev,
+                                                          NUM_MUX_3_VDD_MUL3_DIV4),
                                       MEAN_AVERAGING, EIGHT_SAMPLES, &value1);
        if (ret < 0)
                goto out;
@@ -1061,6 +1131,9 @@ static int read_label(struct iio_dev *indio_dev,
 {
        if (chan->type == IIO_TEMP)
                return sprintf(label, "temp-sensor\n");
+       if (chan->type == IIO_VOLTAGE && chan->channel >= NUM_MUX_0_VSS)
+               return sprintf(label, "%s\n",
+                              chan7_mux_names[chan->channel - NUM_MUX_0_VSS]);
        if (chan->type == IIO_VOLTAGE)
                return sprintf(label, "channel-%d\n", chan->channel);
        return 0;