Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6102c315 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  hwmon: Make PCI device ids constant
  hwmon: (coretemp) Fix TjMax for Atom N450/D410/D510 CPUs
  hwmon: (k10temp) Blacklist more family 10h processors
  hwmon: (asus_atk0110) Add debugfs interface
  hwmon: (asus_atk0110) Refactor interface probe code
  hwmon: (adt7462) Fix pin 28 monitoring
parents a29815a3 3dd3a156
Loading
Loading
Loading
Loading
+11 −6
Original line number Diff line number Diff line
@@ -3,8 +3,8 @@ Kernel driver k10temp

Supported chips:
* AMD Family 10h processors:
  Socket F: Quad-Core/Six-Core/Embedded Opteron
  Socket AM2+: Opteron, Phenom (II) X3/X4
  Socket F: Quad-Core/Six-Core/Embedded Opteron (but see below)
  Socket AM2+: Quad-Core Opteron, Phenom (II) X3/X4, Athlon X2 (but see below)
  Socket AM3: Quad-Core Opteron, Athlon/Phenom II X2/X3/X4, Sempron II
  Socket S1G3: Athlon II, Sempron, Turion II
* AMD Family 11h processors:
@@ -36,10 +36,15 @@ Description
This driver permits reading of the internal temperature sensor of AMD
Family 10h and 11h processors.

All these processors have a sensor, but on older revisions of Family 10h
processors, the sensor may return inconsistent values (erratum 319). The
driver will refuse to load on these revisions unless you specify the
"force=1" module parameter.
All these processors have a sensor, but on those for Socket F or AM2+,
the sensor may return inconsistent values (erratum 319).  The driver
will refuse to load on these revisions unless you specify the "force=1"
module parameter.

Due to technical reasons, the driver can detect only the mainboard's
socket type, not the processor's actual capabilities.  Therefore, if you
are using an AM3 processor on an AM2+ mainboard, you can safely use the
"force=1" parameter.

There is one temperature measurement value, available as temp1_input in
sysfs. It is measured in degrees Celsius with a resolution of 1/8th degree.
+1 −1
Original line number Diff line number Diff line
@@ -392,7 +392,7 @@ config SENSORS_GL520SM

config SENSORS_CORETEMP
	tristate "Intel Core/Core2/Atom temperature sensor"
	depends on X86 && EXPERIMENTAL
	depends on X86 && PCI && EXPERIMENTAL
	help
	  If you say yes here you get support for the temperature
	  sensor inside your CPU. Most of the family 6 CPUs
+1 −1
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END };
#define		ADT7462_PIN24_SHIFT		6
#define		ADT7462_PIN26_VOLT_INPUT	0x08
#define		ADT7462_PIN25_VOLT_INPUT	0x20
#define		ADT7462_PIN28_SHIFT		6	/* cfg3 */
#define		ADT7462_PIN28_SHIFT		4	/* cfg3 */
#define		ADT7462_PIN28_VOLT		0x5

#define ADT7462_REG_ALARM1			0xB8
+235 −54
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 * See COPYING in the top level directory of the kernel tree.
 */

#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/hwmon.h>
#include <linux/list.h>
@@ -101,6 +102,11 @@ struct atk_data {
	int temperature_count;
	int fan_count;
	struct list_head sensor_list;

	struct {
		struct dentry *root;
		u32 id;
	} debugfs;
};


@@ -624,6 +630,187 @@ static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
	return err;
}

#ifdef CONFIG_DEBUG_FS
static int atk_debugfs_gitm_get(void *p, u64 *val)
{
	struct atk_data *data = p;
	union acpi_object *ret;
	struct atk_acpi_ret_buffer *buf;
	int err = 0;

	if (!data->read_handle)
		return -ENODEV;

	if (!data->debugfs.id)
		return -EINVAL;

	ret = atk_gitm(data, data->debugfs.id);
	if (IS_ERR(ret))
		return PTR_ERR(ret);

	buf = (struct atk_acpi_ret_buffer *)ret->buffer.pointer;
	if (buf->flags)
		*val = buf->value;
	else
		err = -EIO;

	return err;
}

DEFINE_SIMPLE_ATTRIBUTE(atk_debugfs_gitm,
			atk_debugfs_gitm_get,
			NULL,
			"0x%08llx\n")

static int atk_acpi_print(char *buf, size_t sz, union acpi_object *obj)
{
	int ret = 0;

	switch (obj->type) {
	case ACPI_TYPE_INTEGER:
		ret = snprintf(buf, sz, "0x%08llx\n", obj->integer.value);
		break;
	case ACPI_TYPE_STRING:
		ret = snprintf(buf, sz, "%s\n", obj->string.pointer);
		break;
	}

	return ret;
}

static void atk_pack_print(char *buf, size_t sz, union acpi_object *pack)
{
	int ret;
	int i;

	for (i = 0; i < pack->package.count; i++) {
		union acpi_object *obj = &pack->package.elements[i];

		ret = atk_acpi_print(buf, sz, obj);
		if (ret >= sz)
			break;
		buf += ret;
		sz -= ret;
	}
}

static int atk_debugfs_ggrp_open(struct inode *inode, struct file *file)
{
	struct atk_data *data = inode->i_private;
	char *buf = NULL;
	union acpi_object *ret;
	u8 cls;
	int i;

	if (!data->enumerate_handle)
		return -ENODEV;
	if (!data->debugfs.id)
		return -EINVAL;

	cls = (data->debugfs.id & 0xff000000) >> 24;
	ret = atk_ggrp(data, cls);
	if (IS_ERR(ret))
		return PTR_ERR(ret);

	for (i = 0; i < ret->package.count; i++) {
		union acpi_object *pack = &ret->package.elements[i];
		union acpi_object *id;

		if (pack->type != ACPI_TYPE_PACKAGE)
			continue;
		if (!pack->package.count)
			continue;
		id = &pack->package.elements[0];
		if (id->integer.value == data->debugfs.id) {
			/* Print the package */
			buf = kzalloc(512, GFP_KERNEL);
			if (!buf) {
				ACPI_FREE(ret);
				return -ENOMEM;
			}
			atk_pack_print(buf, 512, pack);
			break;
		}
	}
	ACPI_FREE(ret);

	if (!buf)
		return -EINVAL;

	file->private_data = buf;

	return nonseekable_open(inode, file);
}

static ssize_t atk_debugfs_ggrp_read(struct file *file, char __user *buf,
		size_t count, loff_t *pos)
{
	char *str = file->private_data;
	size_t len = strlen(str);

	return simple_read_from_buffer(buf, count, pos, str, len);
}

static int atk_debugfs_ggrp_release(struct inode *inode, struct file *file)
{
	kfree(file->private_data);
	return 0;
}

static const struct file_operations atk_debugfs_ggrp_fops = {
	.read		= atk_debugfs_ggrp_read,
	.open		= atk_debugfs_ggrp_open,
	.release	= atk_debugfs_ggrp_release,
};

static void atk_debugfs_init(struct atk_data *data)
{
	struct dentry *d;
	struct dentry *f;

	data->debugfs.id = 0;

	d = debugfs_create_dir("asus_atk0110", NULL);
	if (!d || IS_ERR(d))
		return;

	f = debugfs_create_x32("id", S_IRUSR | S_IWUSR, d, &data->debugfs.id);
	if (!f || IS_ERR(f))
		goto cleanup;

	f = debugfs_create_file("gitm", S_IRUSR, d, data,
			&atk_debugfs_gitm);
	if (!f || IS_ERR(f))
		goto cleanup;

	f = debugfs_create_file("ggrp", S_IRUSR, d, data,
			&atk_debugfs_ggrp_fops);
	if (!f || IS_ERR(f))
		goto cleanup;

	data->debugfs.root = d;

	return;
cleanup:
	debugfs_remove_recursive(d);
}

static void atk_debugfs_cleanup(struct atk_data *data)
{
	debugfs_remove_recursive(data->debugfs.root);
}

#else /* CONFIG_DEBUG_FS */

static void atk_debugfs_init(struct atk_data *data)
{
}

static void atk_debugfs_cleanup(struct atk_data *data)
{
}
#endif

static int atk_add_sensor(struct atk_data *data, union acpi_object *obj)
{
	struct device *dev = &data->acpi_dev->dev;
@@ -1047,76 +1234,75 @@ static int atk_register_hwmon(struct atk_data *data)
	return err;
}

static int atk_check_old_if(struct atk_data *data)
static int atk_probe_if(struct atk_data *data)
{
	struct device *dev = &data->acpi_dev->dev;
	acpi_handle ret;
	acpi_status status;
	int err = 0;

	/* RTMP: read temperature */
	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret);
	if (status != AE_OK) {
	if (ACPI_SUCCESS(status))
		data->rtmp_handle = ret;
	else
		dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n",
				acpi_format_exception(status));
		return -ENODEV;
	}
	data->rtmp_handle = ret;

	/* RVLT: read voltage */
	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret);
	if (status != AE_OK) {
	if (ACPI_SUCCESS(status))
		data->rvlt_handle = ret;
	else
		dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n",
				acpi_format_exception(status));
		return -ENODEV;
	}
	data->rvlt_handle = ret;

	/* RFAN: read fan status */
	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret);
	if (status != AE_OK) {
	if (ACPI_SUCCESS(status))
		data->rfan_handle = ret;
	else
		dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n",
				acpi_format_exception(status));
		return -ENODEV;
	}
	data->rfan_handle = ret;

	return 0;
}

static int atk_check_new_if(struct atk_data *data)
{
	struct device *dev = &data->acpi_dev->dev;
	acpi_handle ret;
	acpi_status status;

	/* Enumeration */
	status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret);
	if (status != AE_OK) {
	if (ACPI_SUCCESS(status))
		data->enumerate_handle = ret;
	else
		dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n",
				acpi_format_exception(status));
		return -ENODEV;
	}
	data->enumerate_handle = ret;

	/* De-multiplexer (read) */
	status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret);
	if (status != AE_OK) {
	if (ACPI_SUCCESS(status))
		data->read_handle = ret;
	else
		dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
				acpi_format_exception(status));
		return -ENODEV;
	}
	data->read_handle = ret;

	/* De-multiplexer (write) */
	status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret);
	if (status != AE_OK) {
		dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
				 acpi_format_exception(status));
		return -ENODEV;
	}
	if (ACPI_SUCCESS(status))
		data->write_handle = ret;
	else
		dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n",
				 acpi_format_exception(status));

	return 0;
	/* Check for hwmon methods: first check "old" style methods; note that
	 * both may be present: in this case we stick to the old interface;
	 * analysis of multiple DSDTs indicates that when both interfaces
	 * are present the new one (GGRP/GITM) is not functional.
	 */
	if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle)
		data->old_interface = true;
	else if (data->enumerate_handle && data->read_handle &&
			data->write_handle)
		data->old_interface = false;
	else
		err = -ENODEV;

	return err;
}

static int atk_add(struct acpi_device *device)
@@ -1155,28 +1341,19 @@ static int atk_add(struct acpi_device *device)
	}
	ACPI_FREE(buf.pointer);

	/* Check for hwmon methods: first check "old" style methods; note that
	 * both may be present: in this case we stick to the old interface;
	 * analysis of multiple DSDTs indicates that when both interfaces
	 * are present the new one (GGRP/GITM) is not functional.
	 */
	err = atk_check_old_if(data);
	if (!err) {
		dev_dbg(&device->dev, "Using old hwmon interface\n");
		data->old_interface = true;
	} else {
		err = atk_check_new_if(data);
		if (err)
	err = atk_probe_if(data);
	if (err) {
		dev_err(&device->dev, "No usable hwmon interface detected\n");
		goto out;

		dev_dbg(&device->dev, "Using new hwmon interface\n");
		data->old_interface = false;
	}

	if (data->old_interface)
	if (data->old_interface) {
		dev_dbg(&device->dev, "Using old hwmon interface\n");
		err = atk_enumerate_old_hwmon(data);
	else
	} else {
		dev_dbg(&device->dev, "Using new hwmon interface\n");
		err = atk_enumerate_new_hwmon(data);
	}
	if (err < 0)
		goto out;
	if (err == 0) {
@@ -1190,6 +1367,8 @@ static int atk_add(struct acpi_device *device)
	if (err)
		goto cleanup;

	atk_debugfs_init(data);

	device->driver_data = data;
	return 0;
cleanup:
@@ -1208,6 +1387,8 @@ static int atk_remove(struct acpi_device *device, int type)

	device->driver_data = NULL;

	atk_debugfs_cleanup(data);

	atk_remove_files(data);
	atk_free_sensors(data);
	hwmon_device_unregister(data->hwmon_dev);
+14 −2
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/cpu.h>
#include <linux/pci.h>
#include <asm/msr.h>
#include <asm/processor.h>

@@ -161,6 +162,7 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *
	int usemsr_ee = 1;
	int err;
	u32 eax, edx;
	struct pci_dev *host_bridge;

	/* Early chips have no MSR for TjMax */

@@ -168,11 +170,21 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *
		usemsr_ee = 0;
	}

	/* Atoms seems to have TjMax at 90C */
	/* Atom CPUs */

	if (c->x86_model == 0x1c) {
		usemsr_ee = 0;

		host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));

		if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL
		    && (host_bridge->device == 0xa000	/* NM10 based nettop */
		    || host_bridge->device == 0xa010))	/* NM10 based netbook */
			tjmax = 100000;
		else
			tjmax = 90000;

		pci_dev_put(host_bridge);
	}

	if ((c->x86_model > 0xe) && (usemsr_ee)) {
Loading