Skip to content

Commit

Permalink
thermal: hwmon: move hwmon support to single file
Browse files Browse the repository at this point in the history
In order to improve code organization, this patch
moves the hwmon sysfs support to a file named
thermal_hwmon. This helps to add extra support
for hwmon without scrambling the code.

In order to do this move, the hwmon list head is now
using its own locking. Before, the list used
the global thermal locking. Also, some minor changes
in the code were required, as recommended by checkpatch.pl.

Cc: Zhang Rui <rui.zhang@intel.com>
Cc: linux-pm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Acked-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Eduardo Valentin <eduardo.valentin@ti.com>
  • Loading branch information
Eduardo Valentin committed Sep 3, 2013
1 parent 73b5b1d commit 0dd8879
Show file tree
Hide file tree
Showing 5 changed files with 331 additions and 254 deletions.
9 changes: 9 additions & 0 deletions drivers/thermal/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,17 @@ if THERMAL

config THERMAL_HWMON
bool
prompt "Expose thermal sensors as hwmon device"
depends on HWMON=y || HWMON=THERMAL
default y
help
In case a sensor is registered with the thermal
framework, this option will also register it
as a hwmon. The sensor will then have the common
hwmon sysfs interface.

Say 'Y' here if you want all thermal sensors to
have hwmon sysfs interface too.

choice
prompt "Default Thermal governor"
Expand Down
3 changes: 3 additions & 0 deletions drivers/thermal/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
obj-$(CONFIG_THERMAL) += thermal_sys.o
thermal_sys-y += thermal_core.o

# interface to/from other layers providing sensors
thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o

# governors
thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o
thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o
Expand Down
255 changes: 1 addition & 254 deletions drivers/thermal/thermal_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <net/genetlink.h>

#include "thermal_core.h"
#include "thermal_hwmon.h"

MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
Expand Down Expand Up @@ -859,260 +860,6 @@ thermal_cooling_device_trip_point_show(struct device *dev,

/* Device management */

#if defined(CONFIG_THERMAL_HWMON)

/* hwmon sys I/F */
#include <linux/hwmon.h>

/* thermal zone devices with the same type share one hwmon device */
struct thermal_hwmon_device {
char type[THERMAL_NAME_LENGTH];
struct device *device;
int count;
struct list_head tz_list;
struct list_head node;
};

struct thermal_hwmon_attr {
struct device_attribute attr;
char name[16];
};

/* one temperature input for each thermal zone */
struct thermal_hwmon_temp {
struct list_head hwmon_node;
struct thermal_zone_device *tz;
struct thermal_hwmon_attr temp_input; /* hwmon sys attr */
struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
};

static LIST_HEAD(thermal_hwmon_list);

static ssize_t
name_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", hwmon->type);
}
static DEVICE_ATTR(name, 0444, name_show, NULL);

static ssize_t
temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
{
long temperature;
int ret;
struct thermal_hwmon_attr *hwmon_attr
= container_of(attr, struct thermal_hwmon_attr, attr);
struct thermal_hwmon_temp *temp
= container_of(hwmon_attr, struct thermal_hwmon_temp,
temp_input);
struct thermal_zone_device *tz = temp->tz;

ret = thermal_zone_get_temp(tz, &temperature);

if (ret)
return ret;

return sprintf(buf, "%ld\n", temperature);
}

static ssize_t
temp_crit_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_hwmon_attr *hwmon_attr
= container_of(attr, struct thermal_hwmon_attr, attr);
struct thermal_hwmon_temp *temp
= container_of(hwmon_attr, struct thermal_hwmon_temp,
temp_crit);
struct thermal_zone_device *tz = temp->tz;
long temperature;
int ret;

ret = tz->ops->get_trip_temp(tz, 0, &temperature);
if (ret)
return ret;

return sprintf(buf, "%ld\n", temperature);
}


static struct thermal_hwmon_device *
thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
{
struct thermal_hwmon_device *hwmon;

mutex_lock(&thermal_list_lock);
list_for_each_entry(hwmon, &thermal_hwmon_list, node)
if (!strcmp(hwmon->type, tz->type)) {
mutex_unlock(&thermal_list_lock);
return hwmon;
}
mutex_unlock(&thermal_list_lock);

return NULL;
}

/* Find the temperature input matching a given thermal zone */
static struct thermal_hwmon_temp *
thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
const struct thermal_zone_device *tz)
{
struct thermal_hwmon_temp *temp;

mutex_lock(&thermal_list_lock);
list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
if (temp->tz == tz) {
mutex_unlock(&thermal_list_lock);
return temp;
}
mutex_unlock(&thermal_list_lock);

return NULL;
}

static int
thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
{
struct thermal_hwmon_device *hwmon;
struct thermal_hwmon_temp *temp;
int new_hwmon_device = 1;
int result;

hwmon = thermal_hwmon_lookup_by_type(tz);
if (hwmon) {
new_hwmon_device = 0;
goto register_sys_interface;
}

hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
if (!hwmon)
return -ENOMEM;

INIT_LIST_HEAD(&hwmon->tz_list);
strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
hwmon->device = hwmon_device_register(NULL);
if (IS_ERR(hwmon->device)) {
result = PTR_ERR(hwmon->device);
goto free_mem;
}
dev_set_drvdata(hwmon->device, hwmon);
result = device_create_file(hwmon->device, &dev_attr_name);
if (result)
goto free_mem;

register_sys_interface:
temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
if (!temp) {
result = -ENOMEM;
goto unregister_name;
}

temp->tz = tz;
hwmon->count++;

snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
"temp%d_input", hwmon->count);
temp->temp_input.attr.attr.name = temp->temp_input.name;
temp->temp_input.attr.attr.mode = 0444;
temp->temp_input.attr.show = temp_input_show;
sysfs_attr_init(&temp->temp_input.attr.attr);
result = device_create_file(hwmon->device, &temp->temp_input.attr);
if (result)
goto free_temp_mem;

if (tz->ops->get_crit_temp) {
unsigned long temperature;
if (!tz->ops->get_crit_temp(tz, &temperature)) {
snprintf(temp->temp_crit.name,
sizeof(temp->temp_crit.name),
"temp%d_crit", hwmon->count);
temp->temp_crit.attr.attr.name = temp->temp_crit.name;
temp->temp_crit.attr.attr.mode = 0444;
temp->temp_crit.attr.show = temp_crit_show;
sysfs_attr_init(&temp->temp_crit.attr.attr);
result = device_create_file(hwmon->device,
&temp->temp_crit.attr);
if (result)
goto unregister_input;
}
}

mutex_lock(&thermal_list_lock);
if (new_hwmon_device)
list_add_tail(&hwmon->node, &thermal_hwmon_list);
list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
mutex_unlock(&thermal_list_lock);

return 0;

unregister_input:
device_remove_file(hwmon->device, &temp->temp_input.attr);
free_temp_mem:
kfree(temp);
unregister_name:
if (new_hwmon_device) {
device_remove_file(hwmon->device, &dev_attr_name);
hwmon_device_unregister(hwmon->device);
}
free_mem:
if (new_hwmon_device)
kfree(hwmon);

return result;
}

static void
thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
{
struct thermal_hwmon_device *hwmon;
struct thermal_hwmon_temp *temp;

hwmon = thermal_hwmon_lookup_by_type(tz);
if (unlikely(!hwmon)) {
/* Should never happen... */
dev_dbg(&tz->device, "hwmon device lookup failed!\n");
return;
}

temp = thermal_hwmon_lookup_temp(hwmon, tz);
if (unlikely(!temp)) {
/* Should never happen... */
dev_dbg(&tz->device, "temperature input lookup failed!\n");
return;
}

device_remove_file(hwmon->device, &temp->temp_input.attr);
if (tz->ops->get_crit_temp)
device_remove_file(hwmon->device, &temp->temp_crit.attr);

mutex_lock(&thermal_list_lock);
list_del(&temp->hwmon_node);
kfree(temp);
if (!list_empty(&hwmon->tz_list)) {
mutex_unlock(&thermal_list_lock);
return;
}
list_del(&hwmon->node);
mutex_unlock(&thermal_list_lock);

device_remove_file(hwmon->device, &dev_attr_name);
hwmon_device_unregister(hwmon->device);
kfree(hwmon);
}
#else
static int
thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
{
return 0;
}

static void
thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
{
}
#endif

/**
* thermal_zone_bind_cooling_device() - bind a cooling device to a thermal zone
* @tz: pointer to struct thermal_zone_device
Expand Down
Loading

0 comments on commit 0dd8879

Please sign in to comment.