size = <0x10000>;
};
};
+
+ cros_ec_pwm: cros-ec-pwm {
+ compatible = "google,cros-ec-pwm";
+ #pwm-cells = <1>;
+ };
+
};
dsi_host: dsi_host {
*/
void sandbox_cros_ec_set_test_flags(struct udevice *dev, uint flags);
+/**
+ * sandbox_cros_ec_get_pwm_duty() - Get EC PWM config for testing purposes
+ *
+ * @dev: Device to check
+ * @index: PWM channel index
+ * @duty: Current duty cycle in 0..EC_PWM_MAX_DUTY range.
+ * @return 0 if OK, -ENOSPC if the PWM number is invalid
+ */
+int sandbox_cros_ec_get_pwm_duty(struct udevice *dev, uint index, uint *duty);
+
#endif
CONFIG_DM_REGULATOR_SANDBOX=y
CONFIG_REGULATOR_TPS65090=y
CONFIG_DM_PWM=y
+CONFIG_PWM_CROS_EC=y
CONFIG_PWM_SANDBOX=y
CONFIG_RAM=y
CONFIG_REMOTEPROC_SANDBOX=y
CONFIG_REGULATOR_TPS65090=y
CONFIG_DM_REGULATOR_SCMI=y
CONFIG_DM_PWM=y
+CONFIG_PWM_CROS_EC=y
CONFIG_PWM_SANDBOX=y
CONFIG_RAM=y
CONFIG_REMOTEPROC_SANDBOX=y
CONFIG_DM_REGULATOR_SANDBOX=y
CONFIG_REGULATOR_TPS65090=y
CONFIG_DM_PWM=y
+CONFIG_PWM_CROS_EC=y
CONFIG_PWM_SANDBOX=y
CONFIG_RAM=y
CONFIG_REMOTEPROC_SANDBOX=y
CONFIG_DM_REGULATOR_SANDBOX=y
CONFIG_REGULATOR_TPS65090=y
CONFIG_DM_PWM=y
+CONFIG_PWM_CROS_EC=y
CONFIG_PWM_SANDBOX=y
CONFIG_RAM=y
CONFIG_REMOTEPROC_SANDBOX=y
CONFIG_DM_REGULATOR_SANDBOX=y
CONFIG_REGULATOR_TPS65090=y
CONFIG_DM_PWM=y
+CONFIG_PWM_CROS_EC=y
CONFIG_PWM_SANDBOX=y
CONFIG_RAM=y
CONFIG_REMOTEPROC_SANDBOX=y
enum {
VSTORE_SLOT_COUNT = 4,
+ PWM_CHANNEL_COUNT = 4,
};
struct vstore_slot {
u8 data[EC_VSTORE_SLOT_SIZE];
};
+struct ec_pwm_channel {
+ uint duty; /* not ns, EC_PWM_MAX_DUTY = 100% */
+};
+
/**
* struct ec_state - Information about the EC state
*
* @recovery_req: Keyboard recovery requested
* @test_flags: Flags that control behaviour for tests
* @slot_locked: Locked vstore slots (mask)
+ * @pwm: Information per PWM channel
*/
struct ec_state {
u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2];
bool recovery_req;
uint test_flags;
struct vstore_slot slot[VSTORE_SLOT_COUNT];
+ struct ec_pwm_channel pwm[PWM_CHANNEL_COUNT];
} s_state, *g_state;
/**
len = sizeof(*resp);
break;
}
+ case EC_CMD_PWM_GET_DUTY: {
+ const struct ec_params_pwm_get_duty *req = req_data;
+ struct ec_response_pwm_get_duty *resp = resp_data;
+ struct ec_pwm_channel *pwm;
+
+ if (req->pwm_type != EC_PWM_TYPE_GENERIC)
+ return -EINVAL;
+ if (req->index >= PWM_CHANNEL_COUNT)
+ return -EINVAL;
+ pwm = &ec->pwm[req->index];
+ resp->duty = pwm->duty;
+ len = sizeof(*resp);
+ break;
+ }
+ case EC_CMD_PWM_SET_DUTY: {
+ const struct ec_params_pwm_set_duty *req = req_data;
+ struct ec_pwm_channel *pwm;
+
+ if (req->pwm_type != EC_PWM_TYPE_GENERIC)
+ return -EINVAL;
+ if (req->index >= PWM_CHANNEL_COUNT)
+ return -EINVAL;
+ pwm = &ec->pwm[req->index];
+ pwm->duty = req->duty;
+ len = 0;
+ break;
+ }
default:
printf(" ** Unknown EC command %#02x\n", req_hdr->command);
return -1;
ec->test_flags = flags;
}
+int sandbox_cros_ec_get_pwm_duty(struct udevice *dev, uint index, uint *duty)
+{
+ struct ec_state *ec = dev_get_priv(dev);
+ struct ec_pwm_channel *pwm;
+
+ if (index >= PWM_CHANNEL_COUNT)
+ return -ENOSPC;
+ pwm = &ec->pwm[index];
+ *duty = pwm->duty;
+
+ return 0;
+}
+
int cros_ec_probe(struct udevice *dev)
{
struct ec_state *ec = dev_get_priv(dev);
{
struct udevice *dev;
+ /* cros-ec-pwm */
ut_assertok(uclass_get_device(UCLASS_PWM, 0, &dev));
ut_assertnonnull(dev);
ut_assertok(console_record_reset_enable());
/* pwm <invert> <pwm_dev_num> <channel> <polarity> */
- ut_assertok(run_command("pwm invert 0 0 1", 0));
+ /* cros-ec-pwm doesn't support invert */
+ ut_asserteq(1, run_command("pwm invert 0 0 1", 0));
+ ut_assert_nextline("error(-38)")
ut_assert_console_end();
- ut_assertok(run_command("pwm invert 0 0 0", 0));
+ ut_asserteq(1, run_command("pwm invert 0 0 0", 0));
+ ut_assert_nextline("error(-38)")
ut_assert_console_end();
/* pwm <config> <pwm_dev_num> <channel> <period_ns> <duty_ns> */
ut_assertok(run_command("pwm disable 0 0", 0));
ut_assert_console_end();
+ /* sandbox-pwm */
+ ut_assertok(uclass_get_device(UCLASS_PWM, 1, &dev));
+ ut_assertnonnull(dev);
+
+ ut_assertok(console_record_reset_enable());
+
+ /* pwm <invert> <pwm_dev_num> <channel> <polarity> */
+ ut_assertok(run_command("pwm invert 1 0 1", 0));
+ ut_assert_console_end();
+
+ ut_assertok(run_command("pwm invert 1 0 0", 0));
+ ut_assert_console_end();
+
+ /* pwm <config> <pwm_dev_num> <channel> <period_ns> <duty_ns> */
+ ut_assertok(run_command("pwm config 1 0 10 50", 0));
+ ut_assert_console_end();
+
+ /* pwm <enable/disable> <pwm_dev_num> <channel> */
+ ut_assertok(run_command("pwm enable 1 0", 0));
+ ut_assert_console_end();
+
+ ut_assertok(run_command("pwm disable 1 0", 0));
+ ut_assert_console_end();
+
return 0;
}
obj-$(CONFIG_CLK) += clk.o clk_ccf.o
obj-$(CONFIG_CPU) += cpu.o
obj-$(CONFIG_CROS_EC) += cros_ec.o
+obj-$(CONFIG_PWM_CROS_EC) += cros_ec_pwm.o
obj-$(CONFIG_DEVRES) += devres.o
obj-$(CONFIG_DMA) += dma.o
obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <cros_ec.h>
+#include <dm.h>
+#include <pwm.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+static int dm_test_cros_ec_pwm(struct unit_test_state *uts)
+{
+ struct udevice *pwm;
+ struct udevice *ec;
+ uint duty;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_PWM, "cros-ec-pwm", &pwm));
+ ut_assertnonnull(pwm);
+ ec = dev_get_parent(pwm);
+ ut_assertnonnull(ec);
+
+ ut_assertok(pwm_set_config(pwm, 0, 100, 50));
+ ut_assertok(pwm_set_enable(pwm, 0, true));
+ ut_assertok(sandbox_cros_ec_get_pwm_duty(ec, 0, &duty));
+ ut_asserteq(50 * EC_PWM_MAX_DUTY / 100, duty);
+
+ ut_assertok(pwm_set_config(pwm, 0, 15721, 2719));
+ ut_assertok(pwm_set_enable(pwm, 0, true));
+ ut_assertok(sandbox_cros_ec_get_pwm_duty(ec, 0, &duty));
+ ut_asserteq(2719 * EC_PWM_MAX_DUTY / 15721, duty);
+
+ ut_assertok(pwm_set_enable(pwm, 0, false));
+ ut_assertok(sandbox_cros_ec_get_pwm_duty(ec, 0, &duty));
+ ut_asserteq(0, duty);
+
+ ut_assertok(pwm_set_enable(pwm, 0, true));
+ ut_assertok(sandbox_cros_ec_get_pwm_duty(ec, 0, &duty));
+ ut_asserteq(2719 * EC_PWM_MAX_DUTY / 15721, duty);
+
+ ut_assertok(pwm_set_config(pwm, 1, 1000, 0));
+ ut_assertok(pwm_set_enable(pwm, 1, true));
+ ut_assertok(sandbox_cros_ec_get_pwm_duty(ec, 1, &duty));
+ ut_asserteq(0, duty);
+
+ ut_assertok(pwm_set_config(pwm, 2, 1000, 1024));
+ ut_assertok(pwm_set_enable(pwm, 2, true));
+ ut_assertok(sandbox_cros_ec_get_pwm_duty(ec, 2, &duty));
+ ut_asserteq(EC_PWM_MAX_DUTY, duty);
+
+ ut_assertok(pwm_set_config(pwm, 3, EC_PWM_MAX_DUTY, 0xABCD));
+ ut_assertok(pwm_set_enable(pwm, 3, true));
+ ut_assertok(sandbox_cros_ec_get_pwm_duty(ec, 3, &duty));
+ ut_asserteq(0xABCD, duty);
+
+ ut_asserteq(-EINVAL, pwm_set_enable(pwm, 4, true));
+
+ return 0;
+}
+DM_TEST(dm_test_cros_ec_pwm, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
bool polarity;
ut_assertok(uclass_first_device_err(UCLASS_PANEL, &dev));
- ut_assertok(uclass_first_device_err(UCLASS_PWM, &pwm));
+ ut_assertok(uclass_get_device_by_name(UCLASS_PWM, "pwm", &pwm));
ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio));
ut_assertok(regulator_get_by_platname("VDD_EMMC_1.8V", ®));
ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns,
bool enable;
bool polarity;
- ut_assertok(uclass_get_device(UCLASS_PWM, 0, &dev));
+ ut_assertok(uclass_get_device_by_name(UCLASS_PWM, "pwm", &dev));
ut_assertnonnull(dev);
ut_assertok(pwm_set_config(dev, 0, 100, 50));
ut_assertok(pwm_set_enable(dev, 0, true));
ut_asserteq(period_ns, 4096);
ut_asserteq(duty_ns, 50 * 4096 / 100);
+ ut_assertok(uclass_get_device(UCLASS_PWM, 0, &dev));
ut_assertok(uclass_get_device(UCLASS_PWM, 1, &dev));
- ut_asserteq(-ENODEV, uclass_get_device(UCLASS_PWM, 2, &dev));
+ ut_assertok(uclass_get_device(UCLASS_PWM, 2, &dev));
+ ut_asserteq(-ENODEV, uclass_get_device(UCLASS_PWM, 3, &dev));
return 0;
}