2011-04-15 11:01:05

by Wei Ni

[permalink] [raw]
Subject: [PATCH 0/3] hwmon (lm90) add some function for lm90.

From: Wei Ni <[email protected]>

*** BLURB HERE ***

Wei Ni (3):
hwmon: (lm90) Add suspend/resume support
hwmon (lm90) Support to configure nct1008 from platform data
hwmon (lm90) Add alarm function for nct1008

drivers/hwmon/lm90.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/nct1008.h | 39 +++++++++++
2 files changed, 200 insertions(+), 0 deletions(-)
create mode 100644 include/linux/nct1008.h


2011-04-15 11:04:07

by Wei Ni

[permalink] [raw]
Subject: [PATCH 1/3] hwmon: (lm90) Add suspend/resume support

From: Wei Ni <[email protected]>

This patch adds suspend/resume support.
Stop lm90 in suspend, and run it in resume.

Signed-off-by: Wei Ni <[email protected]>
---
drivers/hwmon/lm90.c | 36 ++++++++++++++++++++++++++++++++++++
1 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 2f94f95..1c2ee3f 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -1085,6 +1085,24 @@ static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec);
* Real code
*/

+static void lm90_enable(struct i2c_client *client)
+{
+ u8 value;
+
+ lm90_read_reg(client, LM90_REG_R_CONFIG1, &value);
+ value &= ~0x40;
+ i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, value);
+}
+
+static void lm90_disable(struct i2c_client *client)
+{
+ u8 value;
+
+ lm90_read_reg(client, LM90_REG_R_CONFIG1, &value);
+ value |= 0x40;
+ i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, value);
+}
+
/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm90_detect(struct i2c_client *new_client,
struct i2c_board_info *info)
@@ -1482,6 +1500,20 @@ static void lm90_alert(struct i2c_client *client, unsigned int flag)
}
}

+#ifdef CONFIG_PM
+static int lm90_suspend(struct i2c_client *client, pm_message_t state)
+{
+ lm90_disable(client);
+ return 0;
+}
+
+static int lm90_resume(struct i2c_client *client)
+{
+ lm90_enable(client);
+ return 0;
+}
+#endif
+
static struct i2c_driver lm90_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
@@ -1493,6 +1525,10 @@ static struct i2c_driver lm90_driver = {
.id_table = lm90_id,
.detect = lm90_detect,
.address_list = normal_i2c,
+#ifdef CONFIG_PM
+ .suspend = lm90_suspend,
+ .resume = lm90_resume,
+#endif
};

static int __init sensors_lm90_init(void)
--
1.7.0

2011-04-15 11:04:52

by Wei Ni

[permalink] [raw]
Subject: [PATCH 2/3] hwmon (lm90) Support to configure nct1008 from platform data

From: Wei Ni <[email protected]>

This patch add support to configure nct1008 from platform data.

Signed-off-by: Wei Ni <[email protected]>
---
drivers/hwmon/lm90.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/nct1008.h | 38 +++++++++++++++++++++++++++
2 files changed, 104 insertions(+), 0 deletions(-)
create mode 100644 include/linux/nct1008.h

diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 1c2ee3f..8b639b0 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -83,6 +83,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/nct1008.h>

/*
* Addresses to scan
@@ -1358,6 +1359,67 @@ static void lm90_init_client(struct i2c_client *client)
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
}

+static void lm90_configure_client(struct i2c_client *client)
+{
+ struct lm90_data *data = i2c_get_clientdata(client);
+ u8 value;
+ u16 value16;
+
+ if (strcmp(client->name, "nct1008")) {
+ struct nct1008_platform_data *pdata = client->dev.platform_data;
+
+ /*
+ * Initial Configuration - device is placed in standby and
+ * ALERT/THERM2 pin is configured as THERM2
+ */
+ lm90_read_reg(client, LM90_REG_R_CONFIG1, &value);
+ if (pdata->ext_range)
+ value |= 0x24;
+ else
+ value |= 0x20;
+ i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, value);
+
+ /* Check Temperature Range Select */
+ if (value & 0x04)
+ data->flags |= LM90_FLAG_ADT7461_EXT;
+
+ /* Temperature conversion rate */
+ value = pdata->conv_rate;
+ i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, value);
+
+ /* External temperature h/w shutdown limit */
+ value = temp_to_u8_adt7461(data, pdata->shutdown_ext_limit);
+ i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_CRIT,
+ value);
+
+ /* Local temperature h/w shutdown limit */
+ value = temp_to_u8_adt7461(data, pdata->shutdown_local_limit);
+ i2c_smbus_write_byte_data(client, LM90_REG_W_LOCAL_CRIT, value);
+
+ /* External Temperature Throttling limit */
+ value16 = temp_to_u16_adt7461(data, pdata->throttle_ext_limit);
+ i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_HIGHH,
+ value16 >> 8);
+ if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
+ i2c_smbus_write_byte_data(client,
+ LM90_REG_W_REMOTE_HIGHL,
+ value16 & 0xff);
+
+ /* Local Temperature Throttling limit */
+ value = pdata->ext_range ? 191 : 127;
+ i2c_smbus_write_byte_data(client, LM90_REG_W_LOCAL_HIGH, value);
+
+ /* Remote channel offset */
+ value = pdata->offset;
+ i2c_smbus_write_byte_data(client,
+ LM90_REG_W_REMOTE_OFFSH, value);
+
+ /* THERM hysteresis */
+ value = pdata->hysteresis;
+ i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, value);
+ }
+}
+
static int lm90_probe(struct i2c_client *new_client,
const struct i2c_device_id *id)
{
@@ -1393,6 +1455,10 @@ static int lm90_probe(struct i2c_client *new_client,
/* Initialize the LM90 chip */
lm90_init_client(new_client);

+ /* Configure the LM90 chip from platform_data */
+ if (new_client->dev.platform_data)
+ lm90_configure_client(new_client);
+
/* Register sysfs hooks */
err = sysfs_create_group(&new_client->dev.kobj, &lm90_group);
if (err)
diff --git a/include/linux/nct1008.h b/include/linux/nct1008.h
new file mode 100644
index 0000000..3a6ed69
--- /dev/null
+++ b/include/linux/nct1008.h
@@ -0,0 +1,38 @@
+/*
+ * include/linux/nct1008.h
+ *
+ * NCT1008, temperature monitoring device from ON Semiconductors
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_NCT1008_H
+#define _LINUX_NCT1008_H
+
+#include <linux/types.h>
+
+struct nct1008_platform_data {
+ bool ext_range;
+ u8 conv_rate;
+ u8 offset;
+ u8 hysteresis;
+ long shutdown_ext_limit;
+ long shutdown_local_limit;
+ long throttle_ext_limit;
+};
+
+#endif /* _LINUX_NCT1008_H */
--
1.7.0

2011-04-15 11:04:58

by Wei Ni

[permalink] [raw]
Subject: [PATCH 3/3] hwmon (lm90) Add alarm function for nct1008

From: Wei Ni <[email protected]>

This patch add alarm function for nct1008.

Signed-off-by: Wei Ni <[email protected]>
---
drivers/hwmon/lm90.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/nct1008.h | 1 +
2 files changed, 60 insertions(+), 0 deletions(-)

diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 8b639b0..11a0a9d 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -83,6 +83,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/interrupt.h>
#include <linux/nct1008.h>

/*
@@ -275,6 +276,8 @@ static const struct lm90_params lm90_params[] = {
struct lm90_data {
struct device *hwmon_dev;
struct mutex update_lock;
+ struct work_struct work;
+ struct i2c_client *client;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
int kind;
@@ -308,6 +311,7 @@ struct lm90_data {
7: remote 2 high limit (ma6695/96 only) */
u8 temp_hyst;
u16 alarms; /* bitvector (upper 8 bits for max6695/96) */
+ void (*alarm_fn)(int irq);
};

/*
@@ -1104,6 +1108,27 @@ static void lm90_disable(struct i2c_client *client)
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, value);
}

+static void lm90_work_func(struct work_struct *work)
+{
+ struct lm90_data *data = container_of(work, struct lm90_data, work);
+ int irq = data->client->irq;
+
+ mutex_lock(&data->update_lock);
+
+ if (data->alarm_fn)
+ data->alarm_fn(irq);
+
+ mutex_unlock(&data->update_lock);
+}
+
+static irqreturn_t lm90_irq(int irq, void *dev_id)
+{
+ struct lm90_data *data = dev_id;
+ schedule_work(&data->work);
+
+ return IRQ_HANDLED;
+}
+
/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm90_detect(struct i2c_client *new_client,
struct i2c_board_info *info)
@@ -1417,9 +1442,22 @@ static void lm90_configure_client(struct i2c_client *client)
/* THERM hysteresis */
value = pdata->hysteresis;
i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, value);
+
+ data->alarm_fn = pdata->alarm_fn;
}
}

+static int lm90_configure_irq(struct lm90_data *data)
+{
+ if (data->alarm_fn && data->client->irq) {
+ INIT_WORK(&data->work, lm90_work_func);
+ return request_irq(data->client->irq, lm90_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "lm90", data);
+ } else
+ return 0;
+}
+
static int lm90_probe(struct i2c_client *new_client,
const struct i2c_device_id *id)
{
@@ -1432,6 +1470,7 @@ static int lm90_probe(struct i2c_client *new_client,
err = -ENOMEM;
goto exit;
}
+ data->client = new_client;
i2c_set_clientdata(new_client, data);
mutex_init(&data->update_lock);

@@ -1459,6 +1498,10 @@ static int lm90_probe(struct i2c_client *new_client,
if (new_client->dev.platform_data)
lm90_configure_client(new_client);

+ err = lm90_configure_irq(data);
+ if (err)
+ goto exit_free;
+
/* Register sysfs hooks */
err = sysfs_create_group(&new_client->dev.kobj, &lm90_group);
if (err)
@@ -1499,6 +1542,9 @@ static int lm90_probe(struct i2c_client *new_client,
goto exit_remove_files;
}

+ if (data->alarm_fn && client->irq)
+ schedule_work(&data->work);
+
return 0;

exit_remove_files:
@@ -1513,6 +1559,8 @@ static int lm90_remove(struct i2c_client *client)
{
struct lm90_data *data = i2c_get_clientdata(client);

+ if (data->alarm_fn && client->irq)
+ cancel_work_sync(&data->work);
hwmon_device_unregister(data->hwmon_dev);
lm90_remove_files(client, data);

@@ -1569,13 +1617,24 @@ static void lm90_alert(struct i2c_client *client, unsigned int flag)
#ifdef CONFIG_PM
static int lm90_suspend(struct i2c_client *client, pm_message_t state)
{
+ if (client->irq)
+ disable_irq(client->irq);
lm90_disable(client);
+
return 0;
}

static int lm90_resume(struct i2c_client *client)
{
+ struct lm90_data *data = i2c_get_clientdata(client);
+
lm90_enable(client);
+ if (client->irq) {
+ enable_irq(client->irq);
+ if (data->alarm_fn)
+ schedule_work(&data->work);
+ }
+
return 0;
}
#endif
diff --git a/include/linux/nct1008.h b/include/linux/nct1008.h
index 3a6ed69..8e36860 100644
--- a/include/linux/nct1008.h
+++ b/include/linux/nct1008.h
@@ -33,6 +33,7 @@ struct nct1008_platform_data {
long shutdown_ext_limit;
long shutdown_local_limit;
long throttle_ext_limit;
+ void (*alarm_fn)(int irq);
};

#endif /* _LINUX_NCT1008_H */
--
1.7.0

2011-04-15 15:46:57

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH 2/3] hwmon (lm90) Support to configure nct1008 from platform data

On Fri, Apr 15, 2011 at 07:00:27AM -0400, [email protected] wrote:
> From: Wei Ni <[email protected]>
>
> This patch add support to configure nct1008 from platform data.
>

In my opinion those enhancments should not only be for nct1008 but
apply to all chips, ie be made generic. Not even supporting the functionally
identical chips does not make sense to me at all.

Guenter