samsung: hidl: add exynos hidl power hal

Change-Id: I993353943dd1be7104b6790bfd2d73cd6f63260a
tirimbino
Jan Altensen 4 years ago
parent e893e32fe5
commit e0dd329e29
No known key found for this signature in database
GPG Key ID: 3E45BB95F7AD33DA
  1. 47
      hidl/power/Android.mk
  2. 247
      hidl/power/Power.cpp
  3. 82
      hidl/power/Power.h
  4. 4
      hidl/power/android.hardware.power@1.0-service.exynos.rc
  5. 42
      hidl/power/include/samsung_power.h
  6. 60
      hidl/power/service.cpp

@ -0,0 +1,47 @@
#
# Copyright (C) 2020 The LineageOS Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
Power.cpp \
service.cpp
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
hardware/samsung/hidl/light/include
LOCAL_SHARED_LIBRARIES := \
libbase \
libbinder \
libhidlbase \
libhidltransport \
libutils \
android.hardware.power@1.0 \
vendor.lineage.power@1.0
LOCAL_STATIC_LIBRARIES := libc++fs
LOCAL_MODULE := android.hardware.power@1.0-service.exynos
LOCAL_INIT_RC := android.hardware.power@1.0-service.exynos.rc
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_OWNER := samsung
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)

@ -0,0 +1,247 @@
/*
* Copyright (C) 2020 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.power@1.0-service.exynos"
#include "Power.h"
#include <android-base/logging.h>
#include <filesystem>
#include <fstream>
#include <iostream>
#include "samsung_lights.h"
#include "samsung_power.h"
namespace android {
namespace hardware {
namespace power {
namespace V1_0 {
namespace implementation {
/*
* Write value to path and close file.
*/
template <typename T>
static void set(const std::string& path, const T& value) {
std::ofstream file(path);
file << value << std::endl;
}
template <typename T>
static T get(const std::string& path, const T& def) {
std::ifstream file(path);
T result;
file >> result;
return file.fail() ? def : result;
}
Return<void> Power::setInteractive(bool interactive) {
if (!initialized) {
initialize();
}
if (!interactive) {
int32_t panel_brightness = get(PANEL_BRIGHTNESS_NODE, -1);
if (panel_brightness > 0) {
LOG(VERBOSE) << "Moving to non-interactive state, but screen is still on,"
<< "not disabling input devices";
return Void();
}
}
if (!sec_touchscreen.empty()) {
set(sec_touchscreen, interactive ? "1" : "0");
}
if (!sec_touchkey.empty()) {
if (!interactive) {
int button_state = get(sec_touchkey, -1);
if (button_state < 0) {
LOG(ERROR) << "Failed to read touchkey state";
goto out;
}
/*
* If button_state is 0, the keys have been disabled by another component
* (for example lineagehw), which means we don't want them to be enabled when resuming
* from suspend.
*/
if (button_state == 0) {
touchkeys_blocked = true;
}
}
if (!touchkeys_blocked) {
set(sec_touchkey, interactive ? "1" : "0");
}
}
out:
for (const std::string& interactivePath : cpuInteractivePaths) {
set(interactivePath + "/io_is_busy", interactive ? "1" : "0");
}
return Void();
}
Return<void> Power::powerHint(PowerHint hint, int32_t data) {
if (!initialized) {
initialize();
}
/* Bail out if low-power mode is active */
if (current_profile == PowerProfile::POWER_SAVE && hint != PowerHint::LOW_POWER &&
hint != static_cast<PowerHint>(LineagePowerHint::SET_PROFILE)) {
LOG(VERBOSE) << "PROFILE_POWER_SAVE active, ignoring hint " << static_cast<int32_t>(hint);
return Void();
}
switch (hint) {
case PowerHint::INTERACTION:
case PowerHint::LAUNCH:
sendBoostpulse();
break;
case PowerHint::LOW_POWER:
setProfile(data ? PowerProfile::POWER_SAVE : PowerProfile::BALANCED);
break;
default:
if (hint == static_cast<PowerHint>(LineagePowerHint::SET_PROFILE)) {
setProfile(static_cast<PowerProfile>(data));
} else if (hint == static_cast<PowerHint>(LineagePowerHint::CPU_BOOST)) {
sendBoost(data);
} else {
LOG(INFO) << "Unknown power hint: " << static_cast<int32_t>(hint);
}
break;
}
return Void();
}
Return<void> Power::setFeature(Feature feature __unused, bool activate __unused) {
if (!initialized) {
initialize();
}
#ifdef TAP_TO_WAKE_NODE
if (feature == Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE) {
set(TAP_TO_WAKE_NODE, activate ? "1" : "0");
}
#endif
return Void();
}
Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) {
_hidl_cb({}, Status::SUCCESS);
return Void();
}
Return<int32_t> Power::getFeature(LineageFeature feature) {
switch (feature) {
case LineageFeature::SUPPORTED_PROFILES:
return static_cast<int32_t>(PowerProfile::MAX);
default:
return -1;
}
}
void Power::initialize() {
findInputNodes();
current_profile = PowerProfile::BALANCED;
for (const std::string& interactivePath : cpuInteractivePaths) {
hispeed_freqs.emplace_back(get<std::string>(interactivePath + "/hispeed_freq", ""));
}
for (const std::string& sysfsPath : cpuSysfsPaths) {
max_freqs.emplace_back(get<std::string>(sysfsPath + "/cpufreq/scaling_max_freq", ""));
}
initialized = true;
}
void Power::findInputNodes() {
std::error_code ec;
for (auto& de : std::filesystem::directory_iterator("/sys/class/input/", ec)) {
/* we are only interested in the input devices that we can access */
if (ec || de.path().string().find("/sys/class/input/input") == std::string::npos) {
continue;
}
for (auto& de2 : std::filesystem::directory_iterator(de.path(), ec)) {
if (!ec && de2.path().string().find("/name") != std::string::npos) {
std::string content = get<std::string>(de2.path(), "");
if (content == "sec_touchkey") {
sec_touchkey = de.path().string().append("/enabled");
LOG(INFO) << "found sec_touchkey: " << sec_touchkey;
} else if (content == "sec_touchscreen") {
sec_touchscreen = de.path().string().append("/enabled");
LOG(INFO) << "found sec_touchscreen: " << sec_touchscreen;
}
}
}
}
}
void Power::setProfile(PowerProfile profile) {
if (current_profile == profile) {
return;
}
switch (profile) {
case PowerProfile::POWER_SAVE:
// Limit to hispeed freq
for (int i = 0; i < cpuSysfsPaths.size(); i++) {
if (hispeed_freqs.size() > i && !hispeed_freqs.at(i).empty()) {
set(cpuSysfsPaths.at(i) + "/cpufreq/scaling_max_freq", hispeed_freqs.at(i));
}
}
break;
case PowerProfile::BALANCED:
case PowerProfile::HIGH_PERFORMANCE:
// Restore normal max freq
for (int i = 0; i < cpuSysfsPaths.size(); i++) {
if (max_freqs.size() > i && !max_freqs.at(i).empty()) {
set(cpuSysfsPaths.at(i) + "/cpufreq/scaling_max_freq", max_freqs.at(i));
}
}
break;
default:
break;
}
}
void Power::sendBoostpulse() {
// the boostpulse node is only valid for the LITTLE cluster
set(cpuInteractivePaths.front() + "/boostpulse", "1");
}
void Power::sendBoost(int duration_us) {
set(cpuInteractivePaths.front() + "/boost", "1");
usleep(duration_us);
set(cpuInteractivePaths.front() + "/boost", "0");
}
} // namespace implementation
} // namespace V1_0
} // namespace power
} // namespace hardware
} // namespace android

@ -0,0 +1,82 @@
/*
* Copyright (C) 2020 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_HARDWARE_POWER_V1_0_POWER_H
#define ANDROID_HARDWARE_POWER_V1_0_POWER_H
#include <android/hardware/power/1.0/IPower.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <vendor/lineage/power/1.0/ILineagePower.h>
namespace android {
namespace hardware {
namespace power {
namespace V1_0 {
namespace implementation {
using ::android::sp;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::vendor::lineage::power::V1_0::ILineagePower;
using ::vendor::lineage::power::V1_0::LineageFeature;
using ::vendor::lineage::power::V1_0::LineagePowerHint;
// clang-format off
enum PowerProfile {
POWER_SAVE = 0,
BALANCED,
HIGH_PERFORMANCE,
MAX
};
// clang-format on
struct Power : public IPower, public ILineagePower {
Return<void> setInteractive(bool interactive) override;
Return<void> powerHint(PowerHint hint, int32_t data) override;
Return<void> setFeature(Feature feature, bool activate) override;
Return<void> getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) override;
Return<int32_t> getFeature(LineageFeature feature) override;
private:
void initialize();
void findInputNodes();
void setProfile(PowerProfile profile);
void sendBoostpulse();
void sendBoost(int duration_us);
bool initialized;
bool touchkeys_blocked;
std::string sec_touchkey;
std::string sec_touchscreen;
PowerProfile current_profile;
std::vector<std::string> hispeed_freqs;
std::vector<std::string> max_freqs;
};
} // namespace implementation
} // namespace V1_0
} // namespace power
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_POWER_V1_0_POWER_H

@ -0,0 +1,4 @@
service vendor.power-hal-1-0 /vendor/bin/hw/android.hardware.power@1.0-service.exynos
class hal
user system
group system

@ -0,0 +1,42 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* Copyright (C) 2020 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SAMSUNG_POWER_H
#define SAMSUNG_POWER_H
/*
* Board specific nodes
*
* If your kernel exposes these controls in another place, you can either
* symlink to the locations given here, or override this header in your
* device tree.
*/
static const std::vector<std::string> cpuSysfsPaths = {
"/sys/devices/system/cpu/cpu0",
"/sys/devices/system/cpu/cpu4"
};
static const std::vector<std::string> cpuInteractivePaths = {
"/sys/devices/system/cpu/cpu0/cpufreq/interactive",
"/sys/devices/system/cpu/cpu4/cpufreq/interactive"
};
/* double tap to wake node */
//#define TAP_TO_WAKE_NODE "/sys/class/sec/tsp/dt2w_enable"
#endif // SAMSUNG_POWER_H

@ -0,0 +1,60 @@
/*
* Copyright (C) 2020 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.power@1.0-service.exynos"
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include <utils/Errors.h>
#include "Power.h"
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::power::V1_0::IPower;
using android::hardware::power::V1_0::implementation::Power;
using android::OK;
using android::sp;
using android::status_t;
int main() {
sp<Power> power = new Power();
status_t status = 0;
configureRpcThreadpool(1, true);
status = power->IPower::registerAsService();
if (status != OK) {
LOG(ERROR) << "Could not register service (IPower) for Power HAL";
goto shutdown;
}
status = power->ILineagePower::registerAsService();
if (status != OK) {
LOG(ERROR) << "Could not register service (ILineagePower) for Power HAL";
goto shutdown;
}
LOG(INFO) << "Power HAL service is Ready.";
joinRpcThreadpool();
shutdown:
// In normal operation, we don't expect the thread pool to shutdown
LOG(ERROR) << "Power HAL failed to join thread pool.";
return 1;
}
Loading…
Cancel
Save