Commit 4c274fff authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging

* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  hwmon: (s3c-hwmon) Disable build for S3C64xx
  MAINTAINERS: Fix Riku Voipio's address
  hwmon: (asus_atk0110) Enable the EC
  hwmon: (asus_atk0110) Refactor the code
  hwmon: (sht15) Fix spurious section mismatch warning
parents 474a503d 384e724b
...@@ -2065,7 +2065,7 @@ S: Maintained ...@@ -2065,7 +2065,7 @@ S: Maintained
F: fs/* F: fs/*
FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER
M: Riku Voipio <riku.vipio@iki.fi> M: Riku Voipio <riku.voipio@iki.fi>
L: lm-sensors@lm-sensors.org L: lm-sensors@lm-sensors.org
S: Maintained S: Maintained
F: drivers/hwmon/f75375s.c F: drivers/hwmon/f75375s.c
......
...@@ -675,7 +675,7 @@ config SENSORS_SHT15 ...@@ -675,7 +675,7 @@ config SENSORS_SHT15
config SENSORS_S3C config SENSORS_S3C
tristate "S3C24XX/S3C64XX Inbuilt ADC" tristate "S3C24XX/S3C64XX Inbuilt ADC"
depends on ARCH_S3C2410 || ARCH_S3C64XX depends on ARCH_S3C2410
help help
If you say yes here you get support for the on-board ADCs of If you say yes here you get support for the on-board ADCs of
the Samsung S3C24XX or S3C64XX series of SoC the Samsung S3C24XX or S3C64XX series of SoC
......
...@@ -35,18 +35,22 @@ ...@@ -35,18 +35,22 @@
#define METHOD_OLD_ENUM_FAN "FSIF" #define METHOD_OLD_ENUM_FAN "FSIF"
#define ATK_MUX_HWMON 0x00000006ULL #define ATK_MUX_HWMON 0x00000006ULL
#define ATK_MUX_MGMT 0x00000011ULL
#define ATK_CLASS_MASK 0xff000000ULL #define ATK_CLASS_MASK 0xff000000ULL
#define ATK_CLASS_FREQ_CTL 0x03000000ULL #define ATK_CLASS_FREQ_CTL 0x03000000ULL
#define ATK_CLASS_FAN_CTL 0x04000000ULL #define ATK_CLASS_FAN_CTL 0x04000000ULL
#define ATK_CLASS_HWMON 0x06000000ULL #define ATK_CLASS_HWMON 0x06000000ULL
#define ATK_CLASS_MGMT 0x11000000ULL
#define ATK_TYPE_MASK 0x00ff0000ULL #define ATK_TYPE_MASK 0x00ff0000ULL
#define HWMON_TYPE_VOLT 0x00020000ULL #define HWMON_TYPE_VOLT 0x00020000ULL
#define HWMON_TYPE_TEMP 0x00030000ULL #define HWMON_TYPE_TEMP 0x00030000ULL
#define HWMON_TYPE_FAN 0x00040000ULL #define HWMON_TYPE_FAN 0x00040000ULL
#define HWMON_SENSOR_ID_MASK 0x0000ffffULL #define ATK_ELEMENT_ID_MASK 0x0000ffffULL
#define ATK_EC_ID 0x11060004ULL
enum atk_pack_member { enum atk_pack_member {
HWMON_PACK_FLAGS, HWMON_PACK_FLAGS,
...@@ -89,6 +93,9 @@ struct atk_data { ...@@ -89,6 +93,9 @@ struct atk_data {
/* new inteface */ /* new inteface */
acpi_handle enumerate_handle; acpi_handle enumerate_handle;
acpi_handle read_handle; acpi_handle read_handle;
acpi_handle write_handle;
bool disable_ec;
int voltage_count; int voltage_count;
int temperature_count; int temperature_count;
...@@ -129,9 +136,22 @@ struct atk_sensor_data { ...@@ -129,9 +136,22 @@ struct atk_sensor_data {
char const *acpi_name; char const *acpi_name;
}; };
struct atk_acpi_buffer_u64 { /* Return buffer format:
union acpi_object buf; * [0-3] "value" is valid flag
u64 value; * [4-7] value
* [8- ] unknown stuff on newer mobos
*/
struct atk_acpi_ret_buffer {
u32 flags;
u32 value;
u8 data[];
};
/* Input buffer used for GITM and SITM methods */
struct atk_acpi_input_buf {
u32 id;
u32 param1;
u32 param2;
}; };
static int atk_add(struct acpi_device *device); static int atk_add(struct acpi_device *device);
...@@ -439,52 +459,147 @@ static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value) ...@@ -439,52 +459,147 @@ static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value)
return 0; return 0;
} }
static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value) static union acpi_object *atk_ggrp(struct atk_data *data, u16 mux)
{ {
struct atk_data *data = sensor->data;
struct device *dev = &data->acpi_dev->dev; struct device *dev = &data->acpi_dev->dev;
struct acpi_buffer buf;
acpi_status ret;
struct acpi_object_list params; struct acpi_object_list params;
struct acpi_buffer ret;
union acpi_object id; union acpi_object id;
struct atk_acpi_buffer_u64 tmp; union acpi_object *pack;
acpi_status status;
id.type = ACPI_TYPE_INTEGER; id.type = ACPI_TYPE_INTEGER;
id.integer.value = sensor->id; id.integer.value = mux;
params.count = 1; params.count = 1;
params.pointer = &id; params.pointer = &id;
tmp.buf.type = ACPI_TYPE_BUFFER; buf.length = ACPI_ALLOCATE_BUFFER;
tmp.buf.buffer.pointer = (u8 *)&tmp.value; ret = acpi_evaluate_object(data->enumerate_handle, NULL, &params, &buf);
tmp.buf.buffer.length = sizeof(u64); if (ret != AE_OK) {
ret.length = sizeof(tmp); dev_err(dev, "GGRP[%#x] ACPI exception: %s\n", mux,
ret.pointer = &tmp; acpi_format_exception(ret));
return ERR_PTR(-EIO);
}
pack = buf.pointer;
if (pack->type != ACPI_TYPE_PACKAGE) {
/* Execution was successful, but the id was not found */
ACPI_FREE(pack);
return ERR_PTR(-ENOENT);
}
if (pack->package.count < 1) {
dev_err(dev, "GGRP[%#x] package is too small\n", mux);
ACPI_FREE(pack);
return ERR_PTR(-EIO);
}
return pack;
}
static union acpi_object *atk_gitm(struct atk_data *data, u64 id)
{
struct device *dev = &data->acpi_dev->dev;
struct atk_acpi_input_buf buf;
union acpi_object tmp;
struct acpi_object_list params;
struct acpi_buffer ret;
union acpi_object *obj;
acpi_status status;
buf.id = id;
buf.param1 = 0;
buf.param2 = 0;
tmp.type = ACPI_TYPE_BUFFER;
tmp.buffer.pointer = (u8 *)&buf;
tmp.buffer.length = sizeof(buf);
params.count = 1;
params.pointer = (void *)&tmp;
ret.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->read_handle, NULL, &params, status = acpi_evaluate_object_typed(data->read_handle, NULL, &params,
&ret, ACPI_TYPE_BUFFER); &ret, ACPI_TYPE_BUFFER);
if (status != AE_OK) { if (status != AE_OK) {
dev_warn(dev, "%s: ACPI exception: %s\n", __func__, dev_warn(dev, "GITM[%#llx] ACPI exception: %s\n", id,
acpi_format_exception(status)); acpi_format_exception(status));
return -EIO; return ERR_PTR(-EIO);
}
obj = ret.pointer;
/* Sanity check */
if (obj->buffer.length < 8) {
dev_warn(dev, "Unexpected ASBF length: %u\n",
obj->buffer.length);
ACPI_FREE(obj);
return ERR_PTR(-EIO);
} }
return obj;
}
/* Return buffer format: static union acpi_object *atk_sitm(struct atk_data *data,
* [0-3] "value" is valid flag struct atk_acpi_input_buf *buf)
* [4-7] value {
*/ struct device *dev = &data->acpi_dev->dev;
if (!(tmp.value & 0xffffffff)) { struct acpi_object_list params;
union acpi_object tmp;
struct acpi_buffer ret;
union acpi_object *obj;
acpi_status status;
tmp.type = ACPI_TYPE_BUFFER;
tmp.buffer.pointer = (u8 *)buf;
tmp.buffer.length = sizeof(*buf);
params.count = 1;
params.pointer = &tmp;
ret.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->write_handle, NULL, &params,
&ret, ACPI_TYPE_BUFFER);
if (status != AE_OK) {
dev_warn(dev, "SITM[%#x] ACPI exception: %s\n", buf->id,
acpi_format_exception(status));
return ERR_PTR(-EIO);
}
obj = ret.pointer;
/* Sanity check */
if (obj->buffer.length < 8) {
dev_warn(dev, "Unexpected ASBF length: %u\n",
obj->buffer.length);
ACPI_FREE(obj);
return ERR_PTR(-EIO);
}
return obj;
}
static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
{
struct atk_data *data = sensor->data;
struct device *dev = &data->acpi_dev->dev;
union acpi_object *obj;
struct atk_acpi_ret_buffer *buf;
int err = 0;
obj = atk_gitm(data, sensor->id);
if (IS_ERR(obj))
return PTR_ERR(obj);
buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
if (buf->flags == 0) {
/* The reading is not valid, possible causes: /* The reading is not valid, possible causes:
* - sensor failure * - sensor failure
* - enumeration was FUBAR (and we didn't notice) * - enumeration was FUBAR (and we didn't notice)
*/ */
dev_info(dev, "Failure: %#llx\n", tmp.value); dev_warn(dev, "Read failed, sensor = %#llx\n", sensor->id);
return -EIO; err = -EIO;
goto out;
} }
*value = (tmp.value & 0xffffffff00000000ULL) >> 32; *value = buf->value;
out:
return 0; ACPI_FREE(obj);
return err;
} }
static int atk_read_value(struct atk_sensor_data *sensor, u64 *value) static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
...@@ -713,42 +828,140 @@ static int atk_enumerate_old_hwmon(struct atk_data *data) ...@@ -713,42 +828,140 @@ static int atk_enumerate_old_hwmon(struct atk_data *data)
return ret; return ret;
} }
static int atk_enumerate_new_hwmon(struct atk_data *data) static int atk_ec_present(struct atk_data *data)
{ {
struct device *dev = &data->acpi_dev->dev; struct device *dev = &data->acpi_dev->dev;
struct acpi_buffer buf;
acpi_status ret;
struct acpi_object_list params;
union acpi_object id;
union acpi_object *pack; union acpi_object *pack;
int err; union acpi_object *ec;
int ret;
int i; int i;
dev_dbg(dev, "Enumerating hwmon sensors\n"); pack = atk_ggrp(data, ATK_MUX_MGMT);
if (IS_ERR(pack)) {
if (PTR_ERR(pack) == -ENOENT) {
/* The MGMT class does not exists - that's ok */
dev_dbg(dev, "Class %#llx not found\n", ATK_MUX_MGMT);
return 0;
}
return PTR_ERR(pack);
}
id.type = ACPI_TYPE_INTEGER; /* Search the EC */
id.integer.value = ATK_MUX_HWMON; ec = NULL;
params.count = 1; for (i = 0; i < pack->package.count; i++) {
params.pointer = &id; union acpi_object *obj = &pack->package.elements[i];
union acpi_object *id;
buf.length = ACPI_ALLOCATE_BUFFER; if (obj->type != ACPI_TYPE_PACKAGE)
ret = acpi_evaluate_object_typed(data->enumerate_handle, NULL, &params, continue;
&buf, ACPI_TYPE_PACKAGE);
if (ret != AE_OK) { id = &obj->package.elements[0];
dev_warn(dev, METHOD_ENUMERATE ": ACPI exception: %s\n", if (id->type != ACPI_TYPE_INTEGER)
acpi_format_exception(ret)); continue;
return -ENODEV;
if (id->integer.value == ATK_EC_ID) {
ec = obj;
break;
}
} }
/* Result must be a package */ ret = (ec != NULL);
pack = buf.pointer; if (!ret)
/* The system has no EC */
dev_dbg(dev, "EC not found\n");
if (pack->package.count < 1) { ACPI_FREE(pack);
dev_dbg(dev, "%s: hwmon package is too small: %d\n", __func__, return ret;
pack->package.count); }
err = -EINVAL;
goto out; static int atk_ec_enabled(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *obj;
struct atk_acpi_ret_buffer *buf;
int err;
obj = atk_gitm(data, ATK_EC_ID);
if (IS_ERR(obj)) {
dev_err(dev, "Unable to query EC status\n");
return PTR_ERR(obj);
}
buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
if (buf->flags == 0) {
dev_err(dev, "Unable to query EC status\n");
err = -EIO;
} else {
err = (buf->value != 0);
dev_dbg(dev, "EC is %sabled\n",
err ? "en" : "dis");
}
ACPI_FREE(obj);
return err;
}
static int atk_ec_ctl(struct atk_data *data, int enable)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *obj;
struct atk_acpi_input_buf sitm;
struct atk_acpi_ret_buffer *ec_ret;
int err = 0;
sitm.id = ATK_EC_ID;
sitm.param1 = enable;
sitm.param2 = 0;
obj = atk_sitm(data, &sitm);
if (IS_ERR(obj)) {
dev_err(dev, "Failed to %sable the EC\n",
enable ? "en" : "dis");
return PTR_ERR(obj);
} }
ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
if (ec_ret->flags == 0) {
dev_err(dev, "Failed to %sable the EC\n",
enable ? "en" : "dis");
err = -EIO;
} else {
dev_info(dev, "EC %sabled\n",
enable ? "en" : "dis");
}
ACPI_FREE(obj);
return err;
}
static int atk_enumerate_new_hwmon(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *pack;
int err;
int i;
err = atk_ec_present(data);
if (err < 0)
return err;
if (err) {
err = atk_ec_enabled(data);
if (err < 0)
return err;
/* If the EC was disabled we will disable it again on unload */
data->disable_ec = err;
err = atk_ec_ctl(data, 1);
if (err) {
data->disable_ec = false;
return err;
}
}
dev_dbg(dev, "Enumerating hwmon sensors\n");
pack = atk_ggrp(data, ATK_MUX_HWMON);
if (IS_ERR(pack))
return PTR_ERR(pack);
for (i = 0; i < pack->package.count; i++) { for (i = 0; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i]; union acpi_object *obj = &pack->package.elements[i];
...@@ -758,8 +971,7 @@ static int atk_enumerate_new_hwmon(struct atk_data *data) ...@@ -758,8 +971,7 @@ static int atk_enumerate_new_hwmon(struct atk_data *data)
err = data->voltage_count + data->temperature_count + data->fan_count; err = data->voltage_count + data->temperature_count + data->fan_count;
out: ACPI_FREE(pack);
ACPI_FREE(buf.pointer);
return err; return err;
} }
...@@ -895,6 +1107,15 @@ static int atk_check_new_if(struct atk_data *data) ...@@ -895,6 +1107,15 @@ static int atk_check_new_if(struct atk_data *data)
} }
data->read_handle = ret; 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;
}
data->write_handle = ret;
return 0; return 0;
} }
...@@ -915,6 +1136,7 @@ static int atk_add(struct acpi_device *device) ...@@ -915,6 +1136,7 @@ static int atk_add(struct acpi_device *device)
data->acpi_dev = device; data->acpi_dev = device;
data->atk_handle = device->handle; data->atk_handle = device->handle;
INIT_LIST_HEAD(&data->sensor_list); INIT_LIST_HEAD(&data->sensor_list);
data->disable_ec = false;
buf.length = ACPI_ALLOCATE_BUFFER; buf.length = ACPI_ALLOCATE_BUFFER;
ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL, ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL,
...@@ -973,6 +1195,8 @@ static int atk_add(struct acpi_device *device) ...@@ -973,6 +1195,8 @@ static int atk_add(struct acpi_device *device)
cleanup: cleanup:
atk_free_sensors(data); atk_free_sensors(data);
out: out:
if (data->disable_ec)
atk_ec_ctl(data, 0);
kfree(data); kfree(data);
return err; return err;
} }
...@@ -988,6 +1212,11 @@ static int atk_remove(struct acpi_device *device, int type) ...@@ -988,6 +1212,11 @@ static int atk_remove(struct acpi_device *device, int type)
atk_free_sensors(data); atk_free_sensors(data);
hwmon_device_unregister(data->hwmon_dev); hwmon_device_unregister(data->hwmon_dev);
if (data->disable_ec) {
if (atk_ec_ctl(data, 0))
dev_err(&device->dev, "Failed to disable EC\n");
}
kfree(data); kfree(data);
return 0; return 0;
......
...@@ -623,7 +623,12 @@ static int __devexit sht15_remove(struct platform_device *pdev) ...@@ -623,7 +623,12 @@ static int __devexit sht15_remove(struct platform_device *pdev)
} }
static struct platform_driver sht_drivers[] = { /*
* sht_drivers simultaneously refers to __devinit and __devexit function
* which causes spurious section mismatch warning. So use __refdata to
* get rid from this.
*/
static struct platform_driver __refdata sht_drivers[] = {
{ {
.driver = { .driver = {
.name = "sht10", .name = "sht10",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment