blob: 4f1a8d7701201947c19da881bfcf27fd3a13e81f [file] [log] [blame]
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Temperature sensor module for Chrome EC */
#include "common.h"
#include "console.h"
#include "hooks.h"
#include "host_command.h"
#include "task.h"
#include "temp_sensor.h"
#include "thermal.h"
#include "timer.h"
#include "util.h"
int temp_sensor_read(enum temp_sensor_id id, int *temp_ptr)
{
const struct temp_sensor_t *sensor;
if (id < 0 || id >= TEMP_SENSOR_COUNT)
return EC_ERROR_INVAL;
sensor = temp_sensors + id;
return sensor->read(sensor->idx, temp_ptr);
}
static void update_mapped_memory(void)
{
int i, t;
uint8_t *mptr = host_get_memmap(EC_MEMMAP_TEMP_SENSOR);
for (i = 0; i < TEMP_SENSOR_COUNT; i++, mptr++) {
/*
* Switch to second range if first one is full, or stop if
* second range is also full.
*/
if (i == EC_TEMP_SENSOR_ENTRIES)
mptr = host_get_memmap(EC_MEMMAP_TEMP_SENSOR_B);
else if (i >= EC_TEMP_SENSOR_ENTRIES +
EC_TEMP_SENSOR_B_ENTRIES)
break;
switch (temp_sensor_read(i, &t)) {
case EC_ERROR_NOT_POWERED:
*mptr = EC_TEMP_SENSOR_NOT_POWERED;
break;
case EC_ERROR_NOT_CALIBRATED:
*mptr = EC_TEMP_SENSOR_NOT_CALIBRATED;
break;
case EC_SUCCESS:
*mptr = t - EC_TEMP_SENSOR_OFFSET;
break;
default:
*mptr = EC_TEMP_SENSOR_ERROR;
}
}
}
/* Run after other TEMP tasks, so sensors will have updated first. */
DECLARE_HOOK(HOOK_SECOND, update_mapped_memory, HOOK_PRIO_TEMP_SENSOR_DONE);
static void temp_sensor_init(void)
{
int i;
uint8_t *base, *base_b;
/*
* Initialize memory-mapped data so that if a temperature value is read
* before we actually poll the sensors, we don't end up with an insane
* value.
*/
base = host_get_memmap(EC_MEMMAP_TEMP_SENSOR);
base_b = host_get_memmap(EC_MEMMAP_TEMP_SENSOR_B);
for (i = 0; i < TEMP_SENSOR_COUNT; ++i) {
if (i < EC_TEMP_SENSOR_ENTRIES)
base[i] = EC_TEMP_SENSOR_DEFAULT;
else
base_b[i - EC_TEMP_SENSOR_ENTRIES] =
EC_TEMP_SENSOR_DEFAULT;
}
/* Set the rest of memory region to SENSOR_NOT_PRESENT */
for (; i < EC_TEMP_SENSOR_ENTRIES + EC_TEMP_SENSOR_B_ENTRIES; ++i) {
if (i < EC_TEMP_SENSOR_ENTRIES)
base[i] = EC_TEMP_SENSOR_NOT_PRESENT;
else
base_b[i - EC_TEMP_SENSOR_ENTRIES] =
EC_TEMP_SENSOR_NOT_PRESENT;
}
/* Temp sensor data is present, with B range supported. */
*host_get_memmap(EC_MEMMAP_THERMAL_VERSION) = 2;
}
DECLARE_HOOK(HOOK_INIT, temp_sensor_init, HOOK_PRIO_DEFAULT);
/*****************************************************************************/
/* Console commands */
static int command_temps(int argc, char **argv)
{
int t, i;
int rv, rv1 = EC_SUCCESS;
for (i = 0; i < TEMP_SENSOR_COUNT; ++i) {
ccprintf(" %-20s: ", temp_sensors[i].name);
rv = temp_sensor_read(i, &t);
if (rv)
rv1 = rv;
switch (rv) {
case EC_SUCCESS:
ccprintf("%d K = %d C", t, K_TO_C(t));
if (thermal_params[i].temp_fan_off &&
thermal_params[i].temp_fan_max)
ccprintf(" %d%%",
thermal_fan_percent(
thermal_params[i].temp_fan_off,
thermal_params[i].temp_fan_max,
t));
ccprintf("\n");
break;
case EC_ERROR_NOT_POWERED:
ccprintf("Not powered\n");
break;
case EC_ERROR_NOT_CALIBRATED:
ccprintf("Not calibrated\n");
break;
default:
ccprintf("Error %d\n", rv);
}
}
return rv1;
}
DECLARE_CONSOLE_COMMAND(temps, command_temps,
NULL,
"Print temp sensors",
NULL);
/*****************************************************************************/
/* Host commands */
int temp_sensor_command_get_info(struct host_cmd_handler_args *args)
{
const struct ec_params_temp_sensor_get_info *p = args->params;
struct ec_response_temp_sensor_get_info *r = args->response;
int id = p->id;
if (id >= TEMP_SENSOR_COUNT)
return EC_RES_ERROR;
strzcpy(r->sensor_name, temp_sensors[id].name, sizeof(r->sensor_name));
r->sensor_type = temp_sensors[id].type;
args->response_size = sizeof(*r);
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_TEMP_SENSOR_GET_INFO,
temp_sensor_command_get_info,
EC_VER_MASK(0));