// SPDX-License-Identifier: GPL-2.0
/*
* of-thermal.c - Generic Thermal Management device tree support.
*
* Copyright (C) 2013 Texas Instruments
* Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/thermal.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/string.h>
#include "thermal_core.h"
/*** Private data structures to represent thermal device tree data ***/
/**
* struct __thermal_cooling_bind_param - a cooling device for a trip point
* @cooling_device: a pointer to identify the referred cooling device
* @min: minimum cooling state used at this trip point
* @max: maximum cooling state used at this trip point
*/
struct __thermal_cooling_bind_param {
struct device_node *cooling_device;
unsigned long min;
unsigned long max;
};
/**
* struct __thermal_bind_param - a match between trip and cooling device
* @tcbp: a pointer to an array of cooling devices
* @count: number of elements in array
* @trip_id: the trip point index
* @usage: the percentage (from 0 to 100) of cooling contribution
*/
struct __thermal_bind_params {
struct __thermal_cooling_bind_param *tcbp;
unsigned int count;
unsigned int trip_id;
unsigned int usage;
};
/**
* struct __thermal_zone - internal representation of a thermal zone
* @mode: current thermal zone device mode (enabled/disabled)
* @passive_delay: polling interval while passive cooling is activated
* @polling_delay: zone polling interval
* @slope: slope of the temperature adjustment curve
* @offset: offset of the temperature adjustment curve
* @ntrips: number of trip points
* @trips: an array of trip points (0..ntrips - 1)
* @num_tbps: number of thermal bind params
* @tbps: an array of thermal bind params (0..num_tbps - 1)
* @sensor_data: sensor private data used while reading temperature and trend
* @ops: set of callbacks to handle the thermal zone based on DT
*/
struct __thermal_zone {
enum thermal_device_mode mode;
int passive_delay;
int polling_delay;
int slope;
int offset;
/* trip data */
int ntrips;
struct thermal_trip *trips;
/* cooling binding data */
int num_tbps;
struct __thermal_bind_params *tbps;
/* sensor interface */
void *sensor_data;
const struct thermal_zone_of_device_ops *ops;
};
/*** DT thermal zone device callbacks ***/
static int of_thermal_get_temp(struct thermal_zone_device *tz,
int *temp)
{
struct __thermal_zone *data = tz->devdata;
if (!data->ops->get_temp)
return -EINVAL;
return data->ops->get_temp(data->sensor_data, temp);
}
static int of_thermal_set_trips(struct thermal_zone_device *tz,
int low, int high)
{
struct __thermal_zone *data = tz->devdata;
if (!data->ops || !data->ops->set_trips)
return -EINVAL;
return data->ops->set_trips(data->sensor_data, low, high);
}
/**
* of_thermal_get_ntrips - function to export number of available trip
* points.
* @tz: pointer to a thermal zone
*
* This function is a globally visible wrapper to get number of trip points
* stored in the local struct __thermal_zone
*
* Return: number of available trip points, -ENODEV when data not available
*/
int of_thermal_get_ntrips(struct thermal_zone_device *tz)
{
struct __thermal_zone *data = tz->devdata;
if (!data || IS_ERR(data))
return -ENODEV;
return data->ntrips;
}
EXPORT_SYMBOL_GPL(of_thermal_get_ntrips);
/**
* of_thermal_is_trip_valid - function to check if trip point is valid
*
* @tz: pointer to a thermal zone
* @trip: trip point to evaluate
*
* This function is responsible for checking if passed trip point is valid
*
* Return: true if trip point is valid, false otherwise
*/
bool of_thermal_is_trip_valid(struct thermal_zone_device *tz, int trip)
{
struct __thermal_zone *data = tz->devdata;
if (!data || trip >= data->ntrips || trip < 0)
return false;
return true;
}
EXPORT_SYMBOL_GPL(of_thermal_is_trip_valid);
/**
* of_thermal_get_trip_points - function to get access to a globally exported
* trip points
*
* @tz: pointer to a thermal zone
*
* This function provides a pointer to trip points table
*
* Return: pointer to trip points table, NULL otherwise
*/
const struct thermal_trip *
of_thermal_get_trip_points(struct thermal_zone_device *tz)
{
struct __thermal_zone *data = tz->devdata;
if (!data)
return NULL;
return data->trips;
}
EXPORT_SYMBOL_GPL(of_thermal_get_trip_points);
/**
* of_thermal_set_emul_temp - function to set emulated temperature
*
* @tz: pointer to a thermal zone
* @temp: temperature to set
*
* This function gives the ability to set emulated value of temperature,
* which is handy for debugging
*
* Return: zero on success, error code otherwise
*/
static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
int temp)
{
struct __thermal_zone *data = tz->devdata;
return data->ops->set_emul_temp(data->sensor_data, temp);
}
static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
enum thermal_trend *trend)
{
struct __thermal_zone *data = tz->devdata;
if (!data->ops->get_trend)
return -EINVAL;
return data->ops->get_trend(data->sensor_data, trip, trend);
}
static int of_thermal_bind(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
{
struct