/*
* thermal.c - Generic Thermal Management Sysfs support.
*
* Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kdev_t.h>
#include <linux/idr.h>
#include <linux/thermal.h>
#include <linux/spinlock.h>
MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL");
#define PREFIX "Thermal: "
struct thermal_cooling_device_instance {
int id;
char name[THERMAL_NAME_LENGTH];
struct thermal_zone_device *tz;
struct thermal_cooling_device *cdev;
int trip;
char attr_name[THERMAL_NAME_LENGTH];
struct device_attribute attr;
struct list_head node;
};
static DEFINE_IDR(thermal_tz_idr);
static DEFINE_IDR(thermal_cdev_idr);
static DEFINE_MUTEX(thermal_idr_lock);
static LIST_HEAD(thermal_tz_list);
static LIST_HEAD(thermal_cdev_list);
static DEFINE_MUTEX(thermal_list_lock);
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
{
int err;
again:
if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
return -ENOMEM;
if (lock)
mutex_lock(lock);
err = idr_get_new(idr, NULL, id);
if (lock)
mutex_unlock(lock);
if (unlikely(err == -EAGAIN))
goto again;
else if (unlikely(err))
return err;
*id = *id & MAX_ID_MASK;
return 0;
}
static void release_idr(struct idr *idr, struct mutex *lock, int id)
{
if (lock)
mutex_lock(lock);
idr_remove(idr, id);
if (lock)
mutex_unlock(lock);
}
/* sys I/F for thermal zone */
#define to_thermal_zone(_dev) \
container_of(_dev, struct thermal_zone_device, device)
static ssize_t
type_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
return sprintf(buf, "%s\n", tz->type);
}
static ssize_t
temp_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
if (!tz->ops->get_temp)
return -EPERM;
return tz->ops->get_temp(tz, buf);
}
static ssize_t
mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
if (!tz->ops->get_mode)
return -EPERM;
return tz->ops->get_mode(tz, buf);
}
static ssize_t
mode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
int result;
if (!tz->ops->set_mode)
return -EPERM;
result = tz->ops->set_mode(tz, buf);
if (result)
return result;
return count;
}
static ssize_t
trip_point_type_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
int trip;
if (!tz->ops->get_trip_type)
return -EPERM;
if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
return -EINVAL;
return tz->ops->get_trip_type(tz, trip, buf);
}
static ssize_t
trip_point_temp_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
int trip;
if (!tz->ops->get_trip_temp)
return -EPERM;
if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
return -EINVAL;
return tz->ops->get_trip_temp(tz, trip, buf);
}
static DEVICE_ATTR(type, 0444, type_show, NULL);
static DEVICE_ATTR(temp, 0444, temp_show, NULL);
static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
static struct device_attribute trip_point_attrs[] = {
__ATTR(trip_point_0_type, 0444,