]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
spmi: Add sandbox test driver
authorMateusz Kulikowski <mateusz.kulikowski@gmail.com>
Thu, 31 Mar 2016 21:12:28 +0000 (23:12 +0200)
committerTom Rini <trini@konsulko.com>
Fri, 1 Apr 2016 21:18:12 +0000 (17:18 -0400)
This patch adds emulated spmi bus controller with part of
pm8916 pmic on it to sandbox and tests validating SPMI uclass.

Signed-off-by: Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
arch/sandbox/dts/sandbox.dts
arch/sandbox/dts/test.dts
configs/sandbox_defconfig
doc/device-tree-bindings/spmi/spmi-sandbox.txt [new file with mode: 0644]
drivers/spmi/Kconfig
drivers/spmi/Makefile
drivers/spmi/spmi-sandbox.c [new file with mode: 0644]
test/dm/Makefile
test/dm/spmi.c [new file with mode: 0644]

index e3f02bf13cacd6ad5f739433674337a45b5d5b58..2ae40148b09a3976f488b39a0df503ace67ab21f 100644 (file)
                status = "disabled";
        };
 
                status = "disabled";
        };
 
+       spmi: spmi@0 {
+               compatible = "sandbox,spmi";
+               #address-cells = <0x1>;
+               #size-cells = <0x1>;
+               pm8916@0 {
+                       compatible = "qcom,spmi-pmic";
+                       reg = <0x0 0x1>;
+                       #address-cells = <0x1>;
+                       #size-cells = <0x1>;
+
+                       spmi_gpios: gpios@c000 {
+                               compatible = "qcom,pm8916-gpio";
+                               reg = <0xc000 0x400>;
+                               gpio-controller;
+                               gpio-count = <4>;
+                               #gpio-cells = <2>;
+                               gpio-bank-name="spmi";
+                       };
+               };
+       };
 };
 
 #include "cros-ec-keyboard.dtsi"
 };
 
 #include "cros-ec-keyboard.dtsi"
index 9b8d658bf3bcfd37b3eb505e917d49c25e1fa8bb..89300096a5ab6655e4bfb710ee295c51f2b49cc0 100644 (file)
                status = "disabled";
        };
 
                status = "disabled";
        };
 
+       spmi: spmi@0 {
+               compatible = "sandbox,spmi";
+               #address-cells = <0x1>;
+               #size-cells = <0x1>;
+               pm8916@0 {
+                       compatible = "qcom,spmi-pmic";
+                       reg = <0x0 0x1>;
+                       #address-cells = <0x1>;
+                       #size-cells = <0x1>;
+
+                       spmi_gpios: gpios@c000 {
+                               compatible = "qcom,pm8916-gpio";
+                               reg = <0xc000 0x400>;
+                               gpio-controller;
+                               gpio-count = <4>;
+                               #gpio-cells = <2>;
+                               gpio-bank-name="spmi";
+                       };
+               };
+       };
 };
 
 #include "sandbox_pmic.dtsi"
 };
 
 #include "sandbox_pmic.dtsi"
index d69c9fc25dec591c4be722a05fbd191b030bad59..bfc8b61b1a6c2e6106f2077ca10665c04f2fbd09 100644 (file)
@@ -31,6 +31,7 @@ CONFIG_ADC_SANDBOX=y
 CONFIG_BLK=y
 CONFIG_CLK=y
 CONFIG_SANDBOX_GPIO=y
 CONFIG_BLK=y
 CONFIG_CLK=y
 CONFIG_SANDBOX_GPIO=y
+CONFIG_PM8916_GPIO=y
 CONFIG_SYS_I2C_SANDBOX=y
 CONFIG_CROS_EC_KEYB=y
 CONFIG_LED=y
 CONFIG_SYS_I2C_SANDBOX=y
 CONFIG_CROS_EC_KEYB=y
 CONFIG_LED=y
@@ -59,6 +60,9 @@ CONFIG_PINCONF=y
 CONFIG_PINCTRL_SANDBOX=y
 CONFIG_DM_PMIC=y
 CONFIG_DM_PMIC_SANDBOX=y
 CONFIG_PINCTRL_SANDBOX=y
 CONFIG_DM_PMIC=y
 CONFIG_DM_PMIC_SANDBOX=y
+CONFIG_PMIC_PM8916=y
+CONFIG_SPMI=y
+CONFIG_SPMI_SANDBOX=y
 CONFIG_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_SANDBOX=y
 CONFIG_RAM=y
 CONFIG_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_SANDBOX=y
 CONFIG_RAM=y
diff --git a/doc/device-tree-bindings/spmi/spmi-sandbox.txt b/doc/device-tree-bindings/spmi/spmi-sandbox.txt
new file mode 100644 (file)
index 0000000..8569a1a
--- /dev/null
@@ -0,0 +1,31 @@
+Sandbox SPMI emulated arbiter.
+
+This is bus driver for Sandbox. It includes part of emulated pm8916 pmic.
+
+Required properties:
+- compatible: "sandbox,spmi"
+- #address-cells: 0x1 - childs slave ID address
+- #size-cells: 0x1
+
+Example:
+
+spmi: spmi@0 {
+       compatible = "sandbox,spmi";
+       #address-cells = <0x1>;
+       #size-cells = <0x1>;
+       pm8916@0 {
+               compatible = "qcom,spmi-pmic";
+               reg = <0x0 0x1>;
+               #address-cells = <0x1>;
+               #size-cells = <0x1>;
+
+               spmi_gpios: gpios@c000 {
+                       compatible = "qcom,pm8916-gpio";
+                       reg = <0xc000 0x400>;
+                       gpio-controller;
+                       gpio-count = <4>;
+                       #gpio-cells = <2>;
+                       gpio-bank-name="spmi";
+               };
+       };
+};
index 0b9bd312063a0216ca05c2185187a943c139357f..c70d67582d079f750dbd8885a619361022066cc2 100644 (file)
@@ -7,4 +7,12 @@ config SPMI
          Select this to enable to support SPMI bus.
          SPMI (System Power Management Interface) bus is used
          to connect PMIC devices on various SoCs.
          Select this to enable to support SPMI bus.
          SPMI (System Power Management Interface) bus is used
          to connect PMIC devices on various SoCs.
+
+config SPMI_SANDBOX
+       boolean "Support for Sandbox SPMI bus"
+       depends on SPMI
+       ---help---
+         Demo SPMI bus implementation. Emulates part of PM8916 as single
+          slave (0) on bus. It has 4 GPIO peripherals, pid 0xC0-0xC3.
+
 endmenu
 endmenu
index 99092eba5346e2a5e0bbe803f0db8d29f478cfc5..4ca65a99d80b22b25ef5d40f41378b3532ca198f 100644 (file)
@@ -5,3 +5,4 @@
 #
 
 obj-$(CONFIG_SPMI)  += spmi-uclass.o
 #
 
 obj-$(CONFIG_SPMI)  += spmi-uclass.o
+obj-$(CONFIG_SPMI_SANDBOX) += spmi-sandbox.o
diff --git a/drivers/spmi/spmi-sandbox.c b/drivers/spmi/spmi-sandbox.c
new file mode 100644 (file)
index 0000000..2f0fea0
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Sample SPMI bus driver
+ *
+ * It emulates bus with single pm8916-like pmic that has only GPIO reigsters.
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <spmi/spmi.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define EMUL_GPIO_PID_START 0xC0
+#define EMUL_GPIO_PID_END   0xC3
+
+#define EMUL_GPIO_COUNT 4
+
+#define EMUL_GPIO_REG_END 0x46 /* Last valid register */
+
+#define EMUL_PERM_R 0x1
+#define EMUL_PERM_W 0x2
+#define EMUL_PERM_RW (EMUL_PERM_R | EMUL_PERM_W)
+
+struct sandbox_emul_fake_regs {
+       u8 value;
+       u8 access_mask;
+       u8 perms; /* Access permissions */
+};
+
+struct sandbox_emul_gpio {
+       struct sandbox_emul_fake_regs r[EMUL_GPIO_REG_END]; /* Fake registers */
+};
+
+struct sandbox_spmi_priv {
+       struct sandbox_emul_gpio gpios[EMUL_GPIO_COUNT];
+};
+
+/* Check if valid register was requested */
+static bool check_address_valid(int usid, int pid, int off)
+{
+       if (usid != 0)
+               return false;
+       if (pid < EMUL_GPIO_PID_START || pid > EMUL_GPIO_PID_END)
+               return false;
+       if (off > EMUL_GPIO_REG_END)
+               return false;
+       return true;
+}
+
+static int sandbox_spmi_write(struct udevice *dev, int usid, int pid, int off,
+                         uint8_t val)
+{
+       struct sandbox_spmi_priv *priv = dev_get_priv(dev);
+       struct sandbox_emul_fake_regs *regs;
+
+       if (!check_address_valid(usid, pid, off))
+               return -EIO;
+
+       regs = priv->gpios[pid & 0x3].r; /* Last 3 bits of pid are gpio # */
+
+       switch (off) {
+       case 0x40: /* Control */
+               val &= regs[off].access_mask;
+               if (((val & 0x30) == 0x10) || ((val & 0x30) == 0x20)) {
+                       /* out/inout - set status register */
+                       regs[0x8].value &= ~0x1;
+                       regs[0x8].value |= val & 0x1;
+               }
+               break;
+       default:
+               if (regs[off].perms & EMUL_PERM_W)
+                       regs[off].value = val & regs[off].access_mask;
+       }
+       return 0;
+}
+
+static int sandbox_spmi_read(struct udevice *dev, int usid, int pid, int off)
+{
+       struct sandbox_spmi_priv *priv = dev_get_priv(dev);
+       struct sandbox_emul_fake_regs *regs;
+
+       if (!check_address_valid(usid, pid, off))
+               return -EIO;
+
+       regs = priv->gpios[pid & 0x3].r; /* Last 3 bits of pid are gpio # */
+
+       if (regs[0x46].value == 0) /* Block disabled */
+               return 0;
+
+       switch (off) {
+       case 0x8: /* Status */
+               if (regs[0x46].value == 0) /* Block disabled */
+                       return 0;
+               return regs[off].value;
+       default:
+               if (regs[off].perms & EMUL_PERM_R)
+                       return regs[off].value;
+               else
+                       return 0;
+       }
+}
+
+static struct dm_spmi_ops sandbox_spmi_ops = {
+       .read = sandbox_spmi_read,
+       .write = sandbox_spmi_write,
+};
+
+static int sandbox_spmi_probe(struct udevice *dev)
+{
+       struct sandbox_spmi_priv *priv = dev_get_priv(dev);
+       int i;
+
+       for (i = 0; i < EMUL_GPIO_COUNT; ++i) {
+               struct sandbox_emul_fake_regs *regs = priv->gpios[i].r;
+               regs[4].perms = EMUL_PERM_R;
+               regs[4].value = 0x10;
+               regs[5].perms = EMUL_PERM_R;
+               regs[5].value = 0x5;
+               regs[8].access_mask = 0x81;
+               regs[8].perms = EMUL_PERM_RW;
+               regs[0x40].access_mask = 0x7F;
+               regs[0x40].perms = EMUL_PERM_RW;
+               regs[0x41].access_mask = 7;
+               regs[0x41].perms = EMUL_PERM_RW;
+               regs[0x42].access_mask = 7;
+               regs[0x42].perms = EMUL_PERM_RW;
+               regs[0x42].value = 0x4;
+               regs[0x45].access_mask = 0x3F;
+               regs[0x45].perms = EMUL_PERM_RW;
+               regs[0x45].value = 0x1;
+               regs[0x46].access_mask = 0x80;
+               regs[0x46].perms = EMUL_PERM_RW;
+               regs[0x46].value = 0x80;
+       }
+       return 0;
+}
+
+static const struct udevice_id sandbox_spmi_ids[] = {
+       { .compatible = "sandbox,spmi" },
+       { }
+};
+
+U_BOOT_DRIVER(msm_spmi) = {
+       .name = "sandbox_spmi",
+       .id = UCLASS_SPMI,
+       .of_match = sandbox_spmi_ids,
+       .ops = &sandbox_spmi_ops,
+       .probe = sandbox_spmi_probe,
+       .priv_auto_alloc_size = sizeof(struct sandbox_spmi_priv),
+};
index df2d71fdadd1c98b08571effd208c9dd19b94d19..9a11ae0a147a19a742440326b2e619839d771f83 100644 (file)
@@ -37,4 +37,5 @@ obj-$(CONFIG_DM_REGULATOR) += regulator.o
 obj-$(CONFIG_TIMER) += timer.o
 obj-$(CONFIG_DM_VIDEO) += video.o
 obj-$(CONFIG_ADC) += adc.o
 obj-$(CONFIG_TIMER) += timer.o
 obj-$(CONFIG_DM_VIDEO) += video.o
 obj-$(CONFIG_ADC) += adc.o
+obj-$(CONFIG_SPMI) += spmi.o
 endif
 endif
diff --git a/test/dm/spmi.c b/test/dm/spmi.c
new file mode 100644 (file)
index 0000000..d519a90
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <dm/root.h>
+#include <dm/test.h>
+#include <dm/util.h>
+#include <power/pmic.h>
+#include <spmi/spmi.h>
+#include <asm/gpio.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Test if bus childs got probed propperly*/
+static int dm_test_spmi_probe(struct unit_test_state *uts)
+{
+       const char *name = "spmi@0";
+       struct udevice *bus, *dev;
+
+       ut_assertok(uclass_get_device(UCLASS_SPMI, 0, &bus));
+
+       /* Check bus name */
+       ut_asserteq_str(name, bus->name);
+
+       /* Check that it has some devices */
+       ut_asserteq(device_has_children(bus), true);
+
+       ut_assertok(device_find_first_child(bus, &dev));
+
+       /* There should be at least one child */
+       ut_assertnonnull(dev);
+
+       /* Check that only PMICs are connected to the bus */
+       while (dev) {
+               ut_asserteq(device_get_uclass_id(dev), UCLASS_PMIC);
+               device_find_next_child(&dev);
+       }
+
+       return 0;
+}
+DM_TEST(dm_test_spmi_probe, DM_TESTF_SCAN_FDT);
+
+/* Test if it's possible to read bus directly and indirectly */
+static int dm_test_spmi_access(struct unit_test_state *uts)
+{
+       const char *pmic_name = "pm8916@0";
+       struct udevice *bus, *pmic;
+
+       ut_assertok(uclass_get_device(UCLASS_SPMI, 0, &bus));
+
+       ut_assertok(device_get_child(bus, 0, &pmic));
+
+       /* Sanity check if it's proper PMIC */
+       ut_asserteq_str(pmic_name, pmic->name);
+
+       /* Read PMIC ID reg using SPMI bus - it assumes it has slaveID == 0*/
+       ut_asserteq(spmi_reg_read(bus, 0, 0xC0, 0x4), 0x10);
+       ut_asserteq(spmi_reg_read(bus, 0, 0xC0, 0x5), 0x5);
+
+       /* Read ID reg via pmic interface */
+       ut_asserteq(pmic_reg_read(pmic, 0xC004), 0x10);
+       ut_asserteq(pmic_reg_read(pmic, 0xC005), 0x5);
+
+       return 0;
+}
+DM_TEST(dm_test_spmi_access, DM_TESTF_SCAN_FDT);
+
+
+/* Test if it's possible to access GPIO that should be in pmic */
+static int dm_test_spmi_access_peripheral(struct unit_test_state *uts)
+{
+       struct udevice *dev;
+       unsigned int offset, gpio;
+       const char *name;
+       int offset_count;
+
+       /* Get second pin of PMIC GPIO */
+       ut_assertok(gpio_lookup_name("spmi1", &dev, &offset, &gpio));
+
+       /* Check if PMIC is parent */
+       ut_asserteq(device_get_uclass_id(dev->parent), UCLASS_PMIC);
+
+       /* This should be second gpio */
+       ut_asserteq(1, offset);
+
+       name = gpio_get_bank_info(dev, &offset_count);
+
+       /* Check bank name */
+       ut_asserteq_str("spmi", name);
+       /* Check pin count */
+       ut_asserteq(4, offset_count);
+
+       ut_assertok(gpio_request(gpio, "testing"));
+
+       /* Try to set/clear gpio */
+       ut_assertok(gpio_direction_output(gpio, 0));
+       ut_asserteq(gpio_get_value(gpio), 0);
+       ut_assertok(gpio_direction_output(gpio, 1));
+       ut_asserteq(gpio_get_value(gpio), 1);
+       ut_assertok(gpio_direction_input(gpio));
+       ut_asserteq(gpio_get_value(gpio), 1);
+
+       ut_assertok(gpio_free(gpio));
+
+       return 0;
+}
+DM_TEST(dm_test_spmi_access_peripheral, DM_TESTF_SCAN_FDT);