This commit adds implementation of Sandbox ADC device emulation.
The device provides:
- single and multi-channel conversion
- 4 channels with predefined conversion output data
- 16-bit resolution

Signed-off-by: Przemyslaw Marczak <p.marc...@samsung.com>
Cc: Simon Glass <s...@chromium.org>
---
Changes V3:
- new commit
---
 arch/sandbox/dts/sandbox_pmic.dtsi |   2 +-
 arch/sandbox/dts/test.dts          |   6 ++
 configs/sandbox_defconfig          |   2 +
 drivers/adc/Kconfig                |   9 ++
 drivers/adc/Makefile               |   1 +
 drivers/adc/sandbox.c              | 174 +++++++++++++++++++++++++++++++++++++
 6 files changed, 193 insertions(+), 1 deletion(-)
 create mode 100644 drivers/adc/sandbox.c

diff --git a/arch/sandbox/dts/sandbox_pmic.dtsi 
b/arch/sandbox/dts/sandbox_pmic.dtsi
index 44a26b1..ce261b9 100644
--- a/arch/sandbox/dts/sandbox_pmic.dtsi
+++ b/arch/sandbox/dts/sandbox_pmic.dtsi
@@ -55,7 +55,7 @@
                regulator-always-on;
        };
 
-       buck2 {
+       buck2: buck2 {
                regulator-name = "SUPPLY_3.3V";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 730de8a..e2c4971 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -189,6 +189,12 @@
                };
        };
 
+       adc@0 {
+               compatible = "sandbox,adc";
+               vdd-supply = <&buck2>;
+               vss-microvolts = <0>;
+       };
+
        leds {
                compatible = "gpio-leds";
 
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 67ae99b..94c8e68 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -65,3 +65,5 @@ CONFIG_UT_DM=y
 CONFIG_UT_ENV=y
 CONFIG_REMOTEPROC_SANDBOX=y
 CONFIG_CMD_REMOTEPROC=y
+CONFIG_ADC=y
+CONFIG_ADC_SANDBOX=y
diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig
index 223b65e..e5335f7 100644
--- a/drivers/adc/Kconfig
+++ b/drivers/adc/Kconfig
@@ -19,3 +19,12 @@ config ADC_EXYNOS
          - 10 analog input channels
          - 12-bit resolution
          - 600 KSPS of sample rate
+
+config ADC_SANDBOX
+       bool "Enable Sandbox ADC test driver"
+       help
+         This enables driver for Sandbox ADC device emulation.
+         It provides:
+         - 4 analog input channels
+         - 16-bit resolution
+         - single and multi-channel conversion mode
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile
index eb85b8b..cebf26d 100644
--- a/drivers/adc/Makefile
+++ b/drivers/adc/Makefile
@@ -7,3 +7,4 @@
 
 obj-$(CONFIG_ADC) += adc-uclass.o
 obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o
+obj-$(CONFIG_ADC_SANDBOX) += sandbox.o
diff --git a/drivers/adc/sandbox.c b/drivers/adc/sandbox.c
new file mode 100644
index 0000000..3718922
--- /dev/null
+++ b/drivers/adc/sandbox.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2015 Samsung Electronics
+ * Przemyslaw Marczak <p.marc...@samsung.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <adc.h>
+#include <sandbox-adc.h>
+
+/**
+ * struct sandbox_adc_priv - sandbox ADC device's operation status and data
+ *
+ * @conversion_status - conversion status: ACTIVE (started) / INACTIVE 
(stopped)
+ * @conversion_mode   - conversion mode: single or multi-channel
+ * @active_channel    - active channel number, valid for single channel mode
+ * data[]             - channels data
+ */
+struct sandbox_adc_priv {
+       int conversion_status;
+       int conversion_mode;
+       int active_channel_mask;
+       unsigned int data[4];
+};
+
+int sandbox_adc_start_channel(struct udevice *dev, int channel)
+{
+       struct sandbox_adc_priv *priv = dev_get_priv(dev);
+
+       /* Set single-channel mode */
+       priv->conversion_mode = SANDBOX_ADC_MODE_SINGLE_CHANNEL;
+       /* Select channel */
+       priv->active_channel_mask = 1 << channel;
+       /* Start conversion */
+       priv->conversion_status = SANDBOX_ADC_ACTIVE;
+
+       return 0;
+}
+
+int sandbox_adc_start_channels(struct udevice *dev, unsigned int channel_mask)
+{
+       struct sandbox_adc_priv *priv = dev_get_priv(dev);
+
+       /* Set single-channel mode */
+       priv->conversion_mode = SANDBOX_ADC_MODE_MULTI_CHANNEL;
+       /* Select channel */
+       priv->active_channel_mask = channel_mask;
+       /* Start conversion */
+       priv->conversion_status = SANDBOX_ADC_ACTIVE;
+
+       return 0;
+}
+
+int sandbox_adc_channel_data(struct udevice *dev, int channel,
+                            unsigned int *data)
+{
+       struct sandbox_adc_priv *priv = dev_get_priv(dev);
+
+       /* For single-channel conversion mode, check if channel was selected */
+       if ((priv->conversion_mode == SANDBOX_ADC_MODE_SINGLE_CHANNEL) &&
+           !(priv->active_channel_mask & (1 << channel))) {
+               error("Request for an inactive channel!");
+               return -EINVAL;
+       }
+
+       /* The conversion must be started before reading the data */
+       if (priv->conversion_status == SANDBOX_ADC_INACTIVE)
+               return -EIO;
+
+       *data = priv->data[channel];
+
+       return 0;
+}
+
+int sandbox_adc_channels_data(struct udevice *dev, unsigned int channel_mask,
+                             struct adc_channel *channels)
+{
+       struct sandbox_adc_priv *priv = dev_get_priv(dev);
+       int i;
+
+       /* Return error for single-channel conversion mode */
+       if (priv->conversion_mode == SANDBOX_ADC_MODE_SINGLE_CHANNEL) {
+               error("ADC in single-channel mode!");
+               return -EPERM;
+       }
+       /* Check channel selection */
+       if (!(priv->active_channel_mask & channel_mask)) {
+               error("Request for an inactive channel!");
+               return -EINVAL;
+       }
+       /* The conversion must be started before reading the data */
+       if (priv->conversion_status == SANDBOX_ADC_INACTIVE)
+               return -EIO;
+
+       for (i = 0; i < SANDBOX_ADC_CHANNELS; i++) {
+               if (!((channel_mask >> i) & 0x1))
+                       continue;
+
+               channels->data = priv->data[i];
+               channels->id = i;
+               channels++;
+       }
+
+       return 0;
+}
+
+int sandbox_adc_stop(struct udevice *dev)
+{
+       struct sandbox_adc_priv *priv = dev_get_priv(dev);
+
+       /* Start conversion */
+       priv->conversion_status = SANDBOX_ADC_INACTIVE;
+
+       return 0;
+}
+
+int sandbox_adc_probe(struct udevice *dev)
+{
+       struct sandbox_adc_priv *priv = dev_get_priv(dev);
+
+       /* Stop conversion */
+       priv->conversion_status = SANDBOX_ADC_INACTIVE;
+       /* Set single-channel mode */
+       priv->conversion_mode = SANDBOX_ADC_MODE_SINGLE_CHANNEL;
+       /* Deselect all channels */
+       priv->active_channel_mask = 0;
+
+       /* Set sandbox test data */
+       priv->data[0] = SANDBOX_ADC_CHANNEL0_DATA;
+       priv->data[1] = SANDBOX_ADC_CHANNEL1_DATA;
+       priv->data[2] = SANDBOX_ADC_CHANNEL2_DATA;
+       priv->data[3] = SANDBOX_ADC_CHANNEL3_DATA;
+
+       return 0;
+}
+
+int sandbox_adc_ofdata_to_platdata(struct udevice *dev)
+{
+       struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+
+       uc_pdata->data_mask = SANDBOX_ADC_DATA_MASK;
+       uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
+       uc_pdata->data_timeout_us = 0;
+
+       /* Mask available channel bits: [0:3] */
+       uc_pdata->channel_mask = (1 << SANDBOX_ADC_CHANNELS) - 1;
+
+       return 0;
+}
+
+static const struct adc_ops sandbox_adc_ops = {
+       .start_channel = sandbox_adc_start_channel,
+       .start_channels = sandbox_adc_start_channels,
+       .channel_data = sandbox_adc_channel_data,
+       .channels_data = sandbox_adc_channels_data,
+       .stop = sandbox_adc_stop,
+};
+
+static const struct udevice_id sandbox_adc_ids[] = {
+       { .compatible = "sandbox,adc" },
+       { }
+};
+
+U_BOOT_DRIVER(sandbox_adc) = {
+       .name           = "sandbox-adc",
+       .id             = UCLASS_ADC,
+       .of_match       = sandbox_adc_ids,
+       .ops            = &sandbox_adc_ops,
+       .probe          = sandbox_adc_probe,
+       .ofdata_to_platdata = sandbox_adc_ofdata_to_platdata,
+       .priv_auto_alloc_size = sizeof(struct sandbox_adc_priv),
+};
-- 
1.9.1

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to