1
0
mirror of https://github.com/ARM-software/devlib.git synced 2025-01-31 02:00:45 +00:00

devlib: Add ThermalZone type and policy support to thermal module

The thermal module currently only reads thermal zone ids and allow
temperature reading. The mandatory thermal zone 'type' describes
what the zone is and is therefore quite useful information. This
commit also adds support for reading the current thermal zone
policy and available policies along with a few other properties.

This commit also adds async support to the thermal module.

Signed-off-by: Morten Rasmussen <morten.rasmussen@arm.com>
This commit is contained in:
Morten Rasmussen 2023-09-27 10:18:32 +02:00 committed by Marc Bonnici
parent 9199d8884e
commit 403a0faf93

View File

@ -13,8 +13,11 @@
# limitations under the License.
import re
import logging
import devlib.utils.asyn as asyn
from devlib.module import Module
from devlib.exception import TargetStableCalledProcessError
class TripPoint(object):
def __init__(self, zone, _id):
@ -27,19 +30,22 @@ class TripPoint(object):
def target(self):
return self.zone.target
def get_temperature(self):
@asyn.asyncf
async def get_temperature(self):
"""Returns the currently configured temperature of the trip point"""
temp_file = self.target.path.join(self.zone.path, self.temp_node)
return self.target.read_int(temp_file)
return await self.target.read_int.asyn(temp_file)
def set_temperature(self, temperature):
@asyn.asyncf
async def set_temperature(self, temperature):
temp_file = self.target.path.join(self.zone.path, self.temp_node)
self.target.write_value(temp_file, temperature)
await self.target.write_value.asyn(temp_file, temperature)
def get_type(self):
@asyn.asyncf
async def get_type(self):
"""Returns the type of trip point"""
type_file = self.target.path.join(self.zone.path, self.type_node)
return self.target.read_value(type_file)
return await self.target.read_value.asyn(type_file)
class ThermalZone(object):
def __init__(self, target, root, _id):
@ -47,6 +53,7 @@ class ThermalZone(object):
self.name = 'thermal_zone' + _id
self.path = target.path.join(root, self.name)
self.trip_points = {}
self.type = self.target.read_value(self.target.path.join(self.path, 'type'))
for entry in self.target.list_directory(self.path, as_root=target.is_rooted):
re_match = re.match('^trip_point_([0-9]+)_temp', entry)
@ -56,19 +63,70 @@ class ThermalZone(object):
def add_trip_point(self, _id):
self.trip_points[int(_id)] = TripPoint(self, _id)
def is_enabled(self):
@asyn.asyncf
async def is_enabled(self):
"""Returns a boolean representing the 'mode' of the thermal zone"""
value = self.target.read_value(self.target.path.join(self.path, 'mode'))
value = await self.target.read_value.asyn(self.target.path.join(self.path, 'mode'))
return value == 'enabled'
def set_enabled(self, enabled=True):
@asyn.asyncf
async def set_enabled(self, enabled=True):
value = 'enabled' if enabled else 'disabled'
self.target.write_value(self.target.path.join(self.path, 'mode'), value)
await self.target.write_value.asyn(self.target.path.join(self.path, 'mode'), value)
def get_temperature(self):
@asyn.asyncf
async def get_temperature(self):
"""Returns the temperature of the thermal zone"""
temp_file = self.target.path.join(self.path, 'temp')
return self.target.read_int(temp_file)
sysfs_temperature_file = self.target.path.join(self.path, 'temp')
return await self.target.read_int.asyn(sysfs_temperature_file)
@asyn.asyncf
async def get_policy(self):
"""Returns the policy of the thermal zone"""
temp_file = self.target.path.join(self.path, 'policy')
return await self.target.read_value.asyn(temp_file)
@asyn.asyncf
async def set_policy(self, policy):
"""
Sets the policy of the thermal zone
:params policy: Thermal governor name
:type policy: str
"""
await self.target.write_value.asyn(self.target.path.join(self.path, 'policy'), policy)
@asyn.asyncf
async def get_offset(self):
"""Returns the temperature offset of the thermal zone"""
offset_file = self.target.path.join(self.path, 'offset')
return await self.target.read_value.asyn(offset_file)
@asyn.asyncf
async def set_offset(self, offset):
"""
Sets the temperature offset in milli-degrees of the thermal zone
:params offset: Temperature offset in milli-degrees
:type policy: int
"""
await self.target.write_value.asyn(self.target.path.join(self.path, 'offset'), policy)
@asyn.asyncf
async def set_emul_temp(self, offset):
"""
Sets the emulated temperature in milli-degrees of the thermal zone
:params offset: Emulated temperature in milli-degrees
:type policy: int
"""
await self.target.write_value.asyn(self.target.path.join(self.path, 'emul_temp'), policy)
@asyn.asyncf
async def get_available_policies(self):
"""Returns the policies available for the thermal zone"""
temp_file = self.target.path.join(self.path, 'available_policies')
return await self.target.read_value.asyn(temp_file)
class ThermalModule(Module):
name = 'thermal'
@ -83,6 +141,9 @@ class ThermalModule(Module):
def __init__(self, target):
super(ThermalModule, self).__init__(target)
self.logger = logging.getLogger(self.name)
self.logger.debug('Initialized [%s] module', self.name)
self.zones = {}
self.cdevs = []
@ -105,3 +166,32 @@ class ThermalModule(Module):
"""Disables all the thermal zones in the target"""
for zone in self.zones.values():
zone.set_enabled(False)
@asyn.asyncf
async def get_all_temperatures(self, error='raise'):
"""
Returns dictionary with current reading of all thermal zones.
:params error: Sensor read error handling (raise or ignore)
:type error: str
:returns: a dictionary in the form: {tz_type:temperature}
"""
async def get_temperature_noexcep(item):
tzid, tz = item
try:
temperature = await tz.get_temperature.asyn()
except TargetStableCalledProcessError as e:
if error == 'raise':
raise e
elif error == 'ignore':
self.logger.warning(f'Skipping thermal_zone_id={tzid} thermal_zone_type={tz.type} error="{e}"')
return None
else:
raise ValueError(f'Unknown error parameter value: {error}')
return temperature
tz_temps = await self.target.async_manager.map_concurrently(get_temperature_noexcep, self.zones.items())
return {tz.type: temperature for (tzid, tz), temperature in tz_temps.items() if temperature is not None}