1
0
Fork 0

spmi: Add sandbox test driver

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>
utp
Mateusz Kulikowski 2016-03-31 23:12:28 +02:00 committed by Tom Rini
parent 04868b407b
commit d33776e43d
9 changed files with 356 additions and 0 deletions

View File

@ -240,6 +240,26 @@
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"

View File

@ -351,6 +351,26 @@
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"

View File

@ -31,6 +31,7 @@ CONFIG_ADC_SANDBOX=y
CONFIG_BLK=y CONFIG_BLK=y
CONFIG_CLK=y CONFIG_CLK=y
CONFIG_SANDBOX_GPIO=y CONFIG_SANDBOX_GPIO=y
CONFIG_PM8916_GPIO=y
CONFIG_SYS_I2C_SANDBOX=y CONFIG_SYS_I2C_SANDBOX=y
CONFIG_CROS_EC_KEYB=y CONFIG_CROS_EC_KEYB=y
CONFIG_LED=y CONFIG_LED=y
@ -59,6 +60,9 @@ CONFIG_PINCONF=y
CONFIG_PINCTRL_SANDBOX=y CONFIG_PINCTRL_SANDBOX=y
CONFIG_DM_PMIC=y CONFIG_DM_PMIC=y
CONFIG_DM_PMIC_SANDBOX=y CONFIG_DM_PMIC_SANDBOX=y
CONFIG_PMIC_PM8916=y
CONFIG_SPMI=y
CONFIG_SPMI_SANDBOX=y
CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR=y
CONFIG_DM_REGULATOR_SANDBOX=y CONFIG_DM_REGULATOR_SANDBOX=y
CONFIG_RAM=y CONFIG_RAM=y

View File

@ -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";
};
};
};

View File

@ -7,4 +7,12 @@ config SPMI
Select this to enable to support SPMI bus. Select this to enable to support SPMI bus.
SPMI (System Power Management Interface) bus is used SPMI (System Power Management Interface) bus is used
to connect PMIC devices on various SoCs. 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

View File

@ -5,3 +5,4 @@
# #
obj-$(CONFIG_SPMI) += spmi-uclass.o obj-$(CONFIG_SPMI) += spmi-uclass.o
obj-$(CONFIG_SPMI_SANDBOX) += spmi-sandbox.o

View File

@ -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),
};

View File

@ -37,4 +37,5 @@ obj-$(CONFIG_DM_REGULATOR) += regulator.o
obj-$(CONFIG_TIMER) += timer.o obj-$(CONFIG_TIMER) += timer.o
obj-$(CONFIG_DM_VIDEO) += video.o obj-$(CONFIG_DM_VIDEO) += video.o
obj-$(CONFIG_ADC) += adc.o obj-$(CONFIG_ADC) += adc.o
obj-$(CONFIG_SPMI) += spmi.o
endif endif

114
test/dm/spmi.c 100644
View File

@ -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);