[light][amlogic] Fix LED PWM frequency for Nelson
The LED frequency should be 2 kHz (for a period of 500 us). Add logic to
select this period on Nelson, and leave other boards with the original
period.
Bug: 103305
Test: fx test aml-light-test
Test: Used lights-cli to change LED brightness on Astro, Nelson, and
Sherlock
Change-Id: I97960d52e61d3ec4d4c8e4513a141148afd49694
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/693836
Reviewed-by: Ruby Zhuang <rdzhuang@google.com>
Commit-Queue: Braden Kell <bradenkell@google.com>
diff --git a/src/ui/light/drivers/aml-light/BUILD.gn b/src/ui/light/drivers/aml-light/BUILD.gn
index c25caff..58940cf 100644
--- a/src/ui/light/drivers/aml-light/BUILD.gn
+++ b/src/ui/light/drivers/aml-light/BUILD.gn
@@ -30,6 +30,7 @@
"//sdk/banjo/fuchsia.hardware.gpio:fuchsia.hardware.gpio_banjo_cpp",
"//sdk/banjo/fuchsia.hardware.pwm:fuchsia.hardware.pwm_banjo_cpp",
"//sdk/fidl/fuchsia.hardware.light:fuchsia.hardware.light_llcpp",
+ "//src/devices/bus/lib/device-protocol-pdev",
"//src/devices/lib/amlogic",
"//src/devices/lib/driver",
"//src/lib/ddk",
@@ -62,6 +63,7 @@
"//sdk/banjo/fuchsia.hardware.pwm:fuchsia.hardware.pwm_banjo_cpp",
"//sdk/banjo/fuchsia.hardware.pwm:fuchsia.hardware.pwm_banjo_cpp_mock",
"//sdk/fidl/fuchsia.hardware.light:fuchsia.hardware.light_llcpp",
+ "//src/devices/bus/lib/device-protocol-pdev",
"//src/devices/lib/amlogic",
"//src/devices/testing/no_ddk",
"//src/lib/ddk",
diff --git a/src/ui/light/drivers/aml-light/aml-light-test.cc b/src/ui/light/drivers/aml-light/aml-light-test.cc
index ea48ea3..9b038cc 100644
--- a/src/ui/light/drivers/aml-light/aml-light-test.cc
+++ b/src/ui/light/drivers/aml-light/aml-light-test.cc
@@ -26,7 +26,8 @@
class FakeAmlLight : public AmlLight {
public:
static std::unique_ptr<FakeAmlLight> Create(const gpio_protocol_t* gpio,
- std::optional<const pwm_protocol_t*> pwm) {
+ std::optional<const pwm_protocol_t*> pwm,
+ zx_duration_t pwm_period = 170'625) {
fbl::AllocChecker ac;
auto device = fbl::make_unique_checked<FakeAmlLight>(&ac);
if (!ac.check()) {
@@ -35,7 +36,8 @@
}
device->lights_.emplace_back(
"test", ddk::GpioProtocolClient(gpio),
- pwm.has_value() ? std::optional<ddk::PwmProtocolClient>(*pwm) : std::nullopt);
+ pwm.has_value() ? std::optional<ddk::PwmProtocolClient>(*pwm) : std::nullopt,
+ zx::duration(pwm_period));
EXPECT_OK(device->lights_.back().Init(true));
return device;
}
@@ -279,4 +281,42 @@
}
}
+TEST_F(AmlLightTest, SetValueTestNelson) {
+ pwm_.ExpectEnable(ZX_OK);
+ aml_pwm::mode_config regular = {aml_pwm::ON, {}};
+ pwm_config_t config = {false, 500'000, 100.0, reinterpret_cast<uint8_t*>(®ular),
+ sizeof(regular)};
+ pwm_.ExpectSetConfig(ZX_OK, config);
+
+ auto gpio = gpio_.GetProto();
+ auto pwm = pwm_.GetProto();
+ light_ = FakeAmlLight::Create(gpio, pwm, 500'000);
+ ASSERT_NOT_NULL(light_);
+ Init();
+
+ fidl::WireSyncClient<fuchsia_hardware_light::Light> client(std::move(client_));
+
+ {
+ config.duty_cycle = 0;
+ pwm_.ExpectSetConfig(ZX_OK, config);
+ auto set_result = client->SetBrightnessValue(0, 0.0);
+ EXPECT_OK(set_result.status());
+ EXPECT_FALSE(set_result->is_error());
+ }
+ {
+ config.duty_cycle = 20.0;
+ pwm_.ExpectSetConfig(ZX_OK, config);
+ auto set_result = client->SetBrightnessValue(0, 0.2);
+ EXPECT_OK(set_result.status());
+ EXPECT_FALSE(set_result->is_error());
+ }
+ {
+ config.duty_cycle = 100.0;
+ pwm_.ExpectSetConfig(ZX_OK, config);
+ auto set_result = client->SetBrightnessValue(0, 1.0);
+ EXPECT_OK(set_result.status());
+ EXPECT_FALSE(set_result->is_error());
+ }
+}
+
} // namespace aml_light
diff --git a/src/ui/light/drivers/aml-light/aml-light.cc b/src/ui/light/drivers/aml-light/aml-light.cc
index 8103775..5ee4ead 100644
--- a/src/ui/light/drivers/aml-light/aml-light.cc
+++ b/src/ui/light/drivers/aml-light/aml-light.cc
@@ -6,6 +6,7 @@
#include <lib/ddk/metadata.h>
#include <lib/ddk/platform-defs.h>
+#include <lib/device-protocol/pdev.h>
#include <string.h>
#include <cmath>
@@ -22,7 +23,10 @@
constexpr double kMaxBrightness = 1.0;
constexpr double kMinBrightness = 0.0;
-constexpr uint32_t kPwmPeriodNs = 170625;
+constexpr zx::duration kPwmPeriod = zx::nsec(170'625);
+constexpr zx::duration kNelsonPwmPeriod = zx::nsec(500'000);
+static_assert(kPwmPeriod.to_nsecs() <= UINT32_MAX);
+static_assert(kNelsonPwmPeriod.to_nsecs() <= UINT32_MAX);
} // namespace
@@ -62,7 +66,7 @@
aml_pwm::mode_config regular = {aml_pwm::ON, {}};
pwm_config_t config = {
.polarity = false,
- .period_ns = kPwmPeriodNs,
+ .period_ns = static_cast<uint32_t>(pwm_period_.to_nsecs()),
.duty_cycle = static_cast<float>(value * 100.0 / (kMaxBrightness * 1.0)),
.mode_config_buffer = reinterpret_cast<uint8_t*>(®ular),
.mode_config_size = sizeof(regular),
@@ -208,6 +212,17 @@
return ZX_ERR_INTERNAL;
}
+ ddk::PDev pdev(parent(), "pdev");
+ pdev_board_info_t board_info = {};
+ status = ZX_OK;
+ if (!pdev.is_valid() || (status = pdev.GetBoardInfo(&board_info)) != ZX_OK) {
+ board_info.pid = PDEV_PID_GENERIC;
+ }
+
+ const zx::duration pwm_period = board_info.pid == PDEV_PID_NELSON ? kNelsonPwmPeriod : kPwmPeriod;
+
+ zxlogf(INFO, "PWM period: %ld ns", pwm_period.to_nsecs());
+
uint32_t count = 1;
for (uint32_t i = 0; i < configs->size(); i++) {
auto* config = &configs.value()[i];
@@ -227,9 +242,9 @@
return status;
}
count++;
- lights_.emplace_back(name, gpio, pwm);
+ lights_.emplace_back(name, gpio, pwm, pwm_period);
} else {
- lights_.emplace_back(name, gpio, std::nullopt);
+ lights_.emplace_back(name, gpio, std::nullopt, pwm_period);
}
if ((status = lights_.back().Init(config->init_on)) != ZX_OK) {
diff --git a/src/ui/light/drivers/aml-light/aml-light.h b/src/ui/light/drivers/aml-light/aml-light.h
index 6e28b19..08861ba 100644
--- a/src/ui/light/drivers/aml-light/aml-light.h
+++ b/src/ui/light/drivers/aml-light/aml-light.h
@@ -33,8 +33,8 @@
class LightDevice {
public:
LightDevice(std::string name, ddk::GpioProtocolClient gpio,
- std::optional<ddk::PwmProtocolClient> pwm)
- : name_(std::move(name)), gpio_(gpio), pwm_(pwm) {}
+ std::optional<ddk::PwmProtocolClient> pwm, zx::duration pwm_period)
+ : name_(std::move(name)), gpio_(gpio), pwm_(pwm), pwm_period_(pwm_period) {}
zx_status_t Init(bool init_on);
@@ -53,6 +53,7 @@
std::optional<ddk::PwmProtocolClient> pwm_;
double value_ = 0;
+ const zx::duration pwm_period_;
};
class AmlLight : public AmlLightType, public ddk::EmptyProtocol<ZX_PROTOCOL_LIGHT> {