[dif/adc_ctrl] Implement filter get/set-enabled DIFs

This implements the filter get/set-enabled DIFs, and corresponding unit
tests for the ADC Controller.

Signed-off-by: Timothy Trippel <ttrippel@google.com>
diff --git a/sw/device/lib/dif/dif_adc_ctrl.c b/sw/device/lib/dif/dif_adc_ctrl.c
index 0ea3c89..85a724f 100644
--- a/sw/device/lib/dif/dif_adc_ctrl.c
+++ b/sw/device/lib/dif/dif_adc_ctrl.c
@@ -204,3 +204,133 @@
 
   return kDifOk;
 }
+
+static bool get_filter_offset(dif_adc_ctrl_channel_t channel,
+                              dif_adc_ctrl_filter_t filter,
+                              ptrdiff_t *filter_ctrl_reg_offset) {
+#define DIF_ADC_CTRL_CHANNEL0_FILTER_CTRL_REG_CASE_(filter_) \
+  case kDifAdcCtrlFilter##filter_:                           \
+    *filter_ctrl_reg_offset =                                \
+        ADC_CTRL_ADC_CHN0_FILTER_CTL_##filter_##_REG_OFFSET; \
+    break;
+
+#define DIF_ADC_CTRL_CHANNEL1_FILTER_CTRL_REG_CASE_(filter_) \
+  case kDifAdcCtrlFilter##filter_:                           \
+    *filter_ctrl_reg_offset =                                \
+        ADC_CTRL_ADC_CHN1_FILTER_CTL_##filter_##_REG_OFFSET; \
+    break;
+
+  switch (channel) {
+    case kDifAdcCtrlChannel0:
+      switch (filter) {
+        DIF_ADC_CTRL_FILTER_LIST(DIF_ADC_CTRL_CHANNEL0_FILTER_CTRL_REG_CASE_)
+        default:
+          return false;
+      }
+      break;
+    case kDifAdcCtrlChannel1:
+      switch (filter) {
+        DIF_ADC_CTRL_FILTER_LIST(DIF_ADC_CTRL_CHANNEL1_FILTER_CTRL_REG_CASE_)
+        default:
+          return false;
+      }
+      break;
+    default:
+      return false;
+  }
+
+#undef DIF_ADC_CTRL_CHANNEL0_FILTER_CTRL_REG_CASE_
+#undef DIF_ADC_CTRL_CHANNEL1_FILTER_CTRL_REG_CASE_
+
+  return true;
+}
+
+static bool get_filter_enable_bit(dif_adc_ctrl_channel_t channel,
+                                  dif_adc_ctrl_filter_t filter,
+                                  bitfield_bit32_index_t *enable_bit) {
+#define DIF_ADC_CTRL_CHANNEL0_FILTER_ENABLE_CASE_(filter_)                     \
+  case kDifAdcCtrlFilter##filter_:                                             \
+    *enable_bit = ADC_CTRL_ADC_CHN0_FILTER_CTL_##filter_##_EN_##filter_##_BIT; \
+    break;
+
+#define DIF_ADC_CTRL_CHANNEL1_FILTER_ENABLE_CASE_(filter_)                     \
+  case kDifAdcCtrlFilter##filter_:                                             \
+    *enable_bit = ADC_CTRL_ADC_CHN1_FILTER_CTL_##filter_##_EN_##filter_##_BIT; \
+    break;
+
+  switch (channel) {
+    case kDifAdcCtrlChannel0:
+      switch (filter) {
+        DIF_ADC_CTRL_FILTER_LIST(DIF_ADC_CTRL_CHANNEL0_FILTER_ENABLE_CASE_)
+        default:
+          return false;
+      }
+      break;
+    case kDifAdcCtrlChannel1:
+      switch (filter) {
+        DIF_ADC_CTRL_FILTER_LIST(DIF_ADC_CTRL_CHANNEL1_FILTER_ENABLE_CASE_)
+        default:
+          return false;
+      }
+      break;
+    default:
+      return false;
+  }
+
+#undef DIF_ADC_CTRL_CHANNEL0_FILTER_ENABLE_CASE_
+#undef DIF_ADC_CTRL_CHANNEL1_FILTER_ENABLE_CASE_
+
+  return true;
+}
+
+dif_result_t dif_adc_ctrl_filter_set_enabled(const dif_adc_ctrl_t *adc_ctrl,
+                                             dif_adc_ctrl_channel_t channel,
+                                             dif_adc_ctrl_filter_t filter,
+                                             dif_toggle_t enabled) {
+  if (adc_ctrl == NULL || !dif_is_valid_toggle(enabled)) {
+    return kDifBadArg;
+  }
+
+  ptrdiff_t filter_ctrl_reg_offset;
+  bitfield_bit32_index_t enable_bit;
+  if (!get_filter_offset(channel, filter, &filter_ctrl_reg_offset)) {
+    return kDifBadArg;
+  }
+  if (!get_filter_enable_bit(channel, filter, &enable_bit)) {
+    return kDifBadArg;
+  }
+
+  uint32_t filter_ctrl_reg =
+      mmio_region_read32(adc_ctrl->base_addr, filter_ctrl_reg_offset);
+  filter_ctrl_reg = bitfield_bit32_write(filter_ctrl_reg, enable_bit,
+                                         dif_toggle_to_bool(enabled));
+  mmio_region_write32(adc_ctrl->base_addr, filter_ctrl_reg_offset,
+                      filter_ctrl_reg);
+
+  return kDifOk;
+}
+
+dif_result_t dif_adc_ctrl_filter_get_enabled(const dif_adc_ctrl_t *adc_ctrl,
+                                             dif_adc_ctrl_channel_t channel,
+                                             dif_adc_ctrl_filter_t filter,
+                                             dif_toggle_t *is_enabled) {
+  if (adc_ctrl == NULL || is_enabled == NULL) {
+    return kDifBadArg;
+  }
+
+  ptrdiff_t filter_ctrl_reg_offset;
+  bitfield_bit32_index_t enable_bit;
+  if (!get_filter_offset(channel, filter, &filter_ctrl_reg_offset)) {
+    return kDifBadArg;
+  }
+  if (!get_filter_enable_bit(channel, filter, &enable_bit)) {
+    return kDifBadArg;
+  }
+
+  uint32_t filter_ctrl_reg =
+      mmio_region_read32(adc_ctrl->base_addr, filter_ctrl_reg_offset);
+  *is_enabled =
+      dif_bool_to_toggle(bitfield_bit32_read(filter_ctrl_reg, enable_bit));
+
+  return kDifOk;
+}
diff --git a/sw/device/lib/dif/dif_adc_ctrl_unittest.cc b/sw/device/lib/dif/dif_adc_ctrl_unittest.cc
index e7b10fd..f0671d0 100644
--- a/sw/device/lib/dif/dif_adc_ctrl_unittest.cc
+++ b/sw/device/lib/dif/dif_adc_ctrl_unittest.cc
@@ -216,5 +216,115 @@
   EXPECT_EQ(is_enabled, kDifToggleDisabled);
 }
 
+class SetFilterEnabledTest : public AdcCtrlTest {};
+
+TEST_F(SetFilterEnabledTest, NullHandle) {
+  EXPECT_DIF_BADARG(dif_adc_ctrl_filter_set_enabled(
+      nullptr, kDifAdcCtrlChannel0, kDifAdcCtrlFilter3, kDifToggleEnabled));
+}
+
+TEST_F(SetFilterEnabledTest, BadChannel) {
+  EXPECT_DIF_BADARG(dif_adc_ctrl_filter_set_enabled(
+      &adc_ctrl_, static_cast<dif_adc_ctrl_channel_t>(2), kDifAdcCtrlFilter3,
+      kDifToggleEnabled));
+}
+
+TEST_F(SetFilterEnabledTest, BadFilter) {
+  EXPECT_DIF_BADARG(dif_adc_ctrl_filter_set_enabled(
+      &adc_ctrl_, kDifAdcCtrlChannel0,
+      static_cast<dif_adc_ctrl_filter_t>(ADC_CTRL_PARAM_NUM_ADC_FILTER),
+      kDifToggleEnabled));
+  EXPECT_DIF_BADARG(dif_adc_ctrl_filter_set_enabled(
+      &adc_ctrl_, kDifAdcCtrlChannel1,
+      static_cast<dif_adc_ctrl_filter_t>(ADC_CTRL_PARAM_NUM_ADC_FILTER),
+      kDifToggleEnabled));
+}
+
+TEST_F(SetFilterEnabledTest, BadEnabled) {
+  EXPECT_DIF_BADARG(dif_adc_ctrl_filter_set_enabled(
+      &adc_ctrl_, kDifAdcCtrlChannel0, kDifAdcCtrlFilter3,
+      static_cast<dif_toggle_t>(2)));
+}
+
+TEST_F(SetFilterEnabledTest, Success) {
+  EXPECT_READ32(ADC_CTRL_ADC_CHN1_FILTER_CTL_2_REG_OFFSET,
+                {{ADC_CTRL_ADC_CHN1_FILTER_CTL_2_MIN_V_2_OFFSET,
+                  filter_config_.min_voltage},
+                 {ADC_CTRL_ADC_CHN1_FILTER_CTL_2_MAX_V_2_OFFSET,
+                  filter_config_.max_voltage},
+                 {ADC_CTRL_ADC_CHN1_FILTER_CTL_2_COND_2_BIT, true},
+                 {ADC_CTRL_ADC_CHN1_FILTER_CTL_2_EN_2_BIT, false}});
+  EXPECT_WRITE32(ADC_CTRL_ADC_CHN1_FILTER_CTL_2_REG_OFFSET,
+                 {{ADC_CTRL_ADC_CHN1_FILTER_CTL_2_MIN_V_2_OFFSET,
+                   filter_config_.min_voltage},
+                  {ADC_CTRL_ADC_CHN1_FILTER_CTL_2_MAX_V_2_OFFSET,
+                   filter_config_.max_voltage},
+                  {ADC_CTRL_ADC_CHN1_FILTER_CTL_2_COND_2_BIT, true},
+                  {ADC_CTRL_ADC_CHN1_FILTER_CTL_2_EN_2_BIT, true}});
+  EXPECT_DIF_OK(dif_adc_ctrl_filter_set_enabled(
+      &adc_ctrl_, kDifAdcCtrlChannel1, kDifAdcCtrlFilter2, kDifToggleEnabled));
+
+  EXPECT_READ32(ADC_CTRL_ADC_CHN0_FILTER_CTL_7_REG_OFFSET,
+                {{ADC_CTRL_ADC_CHN0_FILTER_CTL_7_MIN_V_7_OFFSET,
+                  filter_config_.min_voltage},
+                 {ADC_CTRL_ADC_CHN0_FILTER_CTL_7_MAX_V_7_OFFSET,
+                  filter_config_.max_voltage},
+                 {ADC_CTRL_ADC_CHN0_FILTER_CTL_7_COND_7_BIT, true},
+                 {ADC_CTRL_ADC_CHN0_FILTER_CTL_7_EN_7_BIT, true}});
+  EXPECT_WRITE32(ADC_CTRL_ADC_CHN0_FILTER_CTL_7_REG_OFFSET,
+                 {{ADC_CTRL_ADC_CHN0_FILTER_CTL_7_MIN_V_7_OFFSET,
+                   filter_config_.min_voltage},
+                  {ADC_CTRL_ADC_CHN0_FILTER_CTL_7_MAX_V_7_OFFSET,
+                   filter_config_.max_voltage},
+                  {ADC_CTRL_ADC_CHN0_FILTER_CTL_7_COND_7_BIT, true},
+                  {ADC_CTRL_ADC_CHN0_FILTER_CTL_7_EN_7_BIT, false}});
+  EXPECT_DIF_OK(dif_adc_ctrl_filter_set_enabled(
+      &adc_ctrl_, kDifAdcCtrlChannel0, kDifAdcCtrlFilter7, kDifToggleDisabled));
+}
+
+class GetFilterEnabledTest : public AdcCtrlTest {};
+
+TEST_F(GetFilterEnabledTest, NullArgs) {
+  dif_toggle_t is_enabled;
+  EXPECT_DIF_BADARG(dif_adc_ctrl_filter_get_enabled(
+      nullptr, kDifAdcCtrlChannel0, kDifAdcCtrlFilter3, &is_enabled));
+  EXPECT_DIF_BADARG(dif_adc_ctrl_filter_get_enabled(
+      &adc_ctrl_, kDifAdcCtrlChannel0, kDifAdcCtrlFilter3, nullptr));
+}
+
+TEST_F(GetFilterEnabledTest, BadChannel) {
+  dif_toggle_t is_enabled;
+  EXPECT_DIF_BADARG(dif_adc_ctrl_filter_get_enabled(
+      &adc_ctrl_, static_cast<dif_adc_ctrl_channel_t>(2), kDifAdcCtrlFilter3,
+      &is_enabled));
+}
+
+TEST_F(GetFilterEnabledTest, BadFilter) {
+  dif_toggle_t is_enabled;
+  EXPECT_DIF_BADARG(dif_adc_ctrl_filter_get_enabled(
+      &adc_ctrl_, kDifAdcCtrlChannel0,
+      static_cast<dif_adc_ctrl_filter_t>(ADC_CTRL_PARAM_NUM_ADC_FILTER),
+      &is_enabled));
+  EXPECT_DIF_BADARG(dif_adc_ctrl_filter_get_enabled(
+      &adc_ctrl_, kDifAdcCtrlChannel1,
+      static_cast<dif_adc_ctrl_filter_t>(ADC_CTRL_PARAM_NUM_ADC_FILTER),
+      &is_enabled));
+}
+
+TEST_F(GetFilterEnabledTest, Success) {
+  dif_toggle_t is_enabled;
+
+  EXPECT_READ32(ADC_CTRL_ADC_CHN0_FILTER_CTL_7_REG_OFFSET,
+                {{ADC_CTRL_ADC_CHN0_FILTER_CTL_7_EN_7_BIT, true}});
+  EXPECT_DIF_OK(dif_adc_ctrl_filter_get_enabled(
+      &adc_ctrl_, kDifAdcCtrlChannel0, kDifAdcCtrlFilter7, &is_enabled));
+  EXPECT_EQ(is_enabled, kDifToggleEnabled);
+
+  EXPECT_READ32(ADC_CTRL_ADC_CHN1_FILTER_CTL_4_REG_OFFSET, 0);
+  EXPECT_DIF_OK(dif_adc_ctrl_filter_get_enabled(
+      &adc_ctrl_, kDifAdcCtrlChannel1, kDifAdcCtrlFilter4, &is_enabled));
+  EXPECT_EQ(is_enabled, kDifToggleDisabled);
+}
+
 }  // namespace
 }  // namespace dif_adc_ctrl_unittest