All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Hwmon for Taco
@ 2008-01-05  5:11 Sean MacLennan
  2008-01-05  7:22 ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 11+ messages in thread
From: Sean MacLennan @ 2008-01-05  5:11 UTC (permalink / raw)
  To: linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 582 bytes --]

The taco has an fpga that controls the fan. It must be feed the current 
temperature from an ad7414 chip. This patch adds a patched ad7414 temp 
sensor from the ppc arch and adds a small driver (taco-dtm) to read the 
temperature and feed it to the fpga.

Without this driver, the taco will just run the fan at high speed all 
the time. I don't even know if this is a problem since cases for the 
taco are very rare and I don't have one. I have never actually heard the 
fan running in a case. Although I did see an early version of the fan 
spin up and spin down.

Cheers,
   Sean

[-- Attachment #2: hwmon.patch --]
[-- Type: text/plain, Size: 12490 bytes --]

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a0445be..2fda94d 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -57,6 +57,16 @@ config SENSORS_ABITUGURU3
 	  This driver can also be built as a module.  If so, the module
 	  will be called abituguru3.
 
+config SENSORS_AD7414
+	tristate "Analog Devices AD7414"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the Analog Devices
+	  AD7414 temperature monitoring chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called ad7414.
+
 config SENSORS_AD7418
 	tristate "Analog Devices AD7416, AD7417 and AD7418"
 	depends on I2C && EXPERIMENTAL
@@ -763,4 +773,13 @@ config HWMON_DEBUG_CHIP
 	  a problem with I2C support and want to see more of what is going
 	  on.
 
+config TACO_DTM
+	tristate "PIKA DTM (Dynamic Thermal Management)"
+	depends on HWMON && TACO
+	select SENSORS_AD7414
+	default y
+	help
+	  Say Y here if you have a PIKA Taco board. This driver is
+	  required for the DTM to work properly.
+
 endif # HWMON
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 55595f6..f993c5a 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_W83791D)	+= w83791d.o
 
 obj-$(CONFIG_SENSORS_ABITUGURU)	+= abituguru.o
 obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
+obj-$(CONFIG_SENSORS_AD7414)	+= ad7414.o
 obj-$(CONFIG_SENSORS_AD7418)	+= ad7418.o
 obj-$(CONFIG_SENSORS_ADM1021)	+= adm1021.o
 obj-$(CONFIG_SENSORS_ADM1025)	+= adm1025.o
@@ -69,6 +70,8 @@ obj-$(CONFIG_SENSORS_VT8231)	+= vt8231.o
 obj-$(CONFIG_SENSORS_W83627EHF)	+= w83627ehf.o
 obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l785ts.o
 
+obj-$(CONFIG_TACO_DTM)		+= taco-dtm.o
+
 ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
--- /dev/null	2005-11-20 22:22:37.000000000 -0500
+++ drivers/hwmon/ad7414.c	2008-01-04 15:26:08.000000000 -0500
@@ -0,0 +1,311 @@
+/*
+ * An hwmon driver for the Analog Devices AD7414
+ *
+ * Copyright 2006 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ *
+ * Based on ad7418.c
+ * Copyright 2006 Tower Technologies, Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+
+#define DRV_VERSION "0.2" // upped version for Pika mods
+
+/* straight from the datasheet */
+#define AD7414_TEMP_MIN (-55000)
+#define AD7414_TEMP_MAX 125000
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x48, 0x4a, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+/* AD7414 registers */
+#define AD7414_REG_TEMP		0x00
+#define AD7414_REG_CONF		0x01
+#define AD7414_REG_T_HIGH	0x02
+#define AD7414_REG_T_LOW	0x03
+
+struct ad7414_data {
+	struct i2c_client	client;
+	struct class_device	*class_dev;
+	struct mutex		lock;
+	char			valid;		/* !=0 if following fields are valid */
+	unsigned long		last_updated;	/* In jiffies */
+	u16			temp_input;	/* Register values */
+	u8			temp_max;
+	u8			temp_min;
+	u8			temp_alert;
+	u8			temp_max_flag;
+	u8			temp_min_flag;
+};
+
+static int ad7414_attach_adapter(struct i2c_adapter *adapter);
+static int ad7414_detect(struct i2c_adapter *adapter, int address, int kind);
+static int ad7414_detach_client(struct i2c_client *client);
+
+static struct i2c_driver ad7414_driver = {
+	.driver = {
+		.name	= "ad7414",
+	},
+	.attach_adapter	= ad7414_attach_adapter,
+	.detach_client	= ad7414_detach_client,
+};
+
+/*
+ * TEMP: 0.001C/bit (-55C to +125C)
+ * REG: (0.5C/bit, two's complement) << 7
+ */
+static inline int AD7414_TEMP_FROM_REG(u16 reg)
+{
+	/* use integer division instead of equivalent right shift to
+	 * guarantee arithmetic shift and preserve the sign
+	 */
+	return ((s16)reg / 128) * 500;
+}
+
+/* All registers are word-sized, except for the configuration registers.
+ * AD7414 uses a high-byte first convention, which is exactly opposite to
+ * the usual practice.
+ */
+static int ad7414_read(struct i2c_client *client, u8 reg)
+{
+	if (reg == AD7414_REG_TEMP)
+		return swab16(i2c_smbus_read_word_data(client, reg));
+	else
+		return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int ad7414_write(struct i2c_client *client, u8 reg, u16 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* PIKA Taco - we need to access the temperature in kernel mode. As a
+ * hack we store the device here. This works because we only have one
+ * ad7414 chip.
+ */
+static struct device *ad7414_dev;
+
+static void ad7414_init_client(struct i2c_client *client)
+{
+	/* TODO: anything to do here??? */
+	ad7414_dev = &client->dev;
+}
+
+static struct ad7414_data *ad7414_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ad7414_data *data = i2c_get_clientdata(client);
+
+	mutex_lock(&data->lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+		|| !data->valid) {
+		dev_dbg(&client->dev, "starting ad7414 update\n");
+
+		/* This is the difference - set one-shot.
+		 *
+		 * After fairly extensive testing it looks like the config
+		 * always returns 0x40. So since I was told to write 0x44, I
+		 * am not only following orders but save a read. The udelay is
+		 * required for the one shot.
+		 *
+		 * Turning this on doesn't seem to make a difference and it
+		 * will only be called every second so it looks like a
+		 * relatively harmless change.
+		 */
+		ad7414_write(client, AD7414_REG_CONF, 0x44);
+		udelay(29);
+		/* */
+
+		data->temp_input = ad7414_read(client, AD7414_REG_TEMP);
+		data->temp_alert = (data->temp_input >> 5) & 0x01;
+		data->temp_max_flag = (data->temp_input >> 4) & 0x01;
+		data->temp_min_flag = (data->temp_input >> 3) & 0x01;
+		data->temp_max = ad7414_read(client, AD7414_REG_T_HIGH);
+		data->temp_min = ad7414_read(client, AD7414_REG_T_LOW);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->lock);
+
+	return data;
+}
+
+int ad7414_get_temp(void)
+{
+	if(ad7414_dev) {
+		struct ad7414_data *data = ad7414_update_device(ad7414_dev);
+		return data->temp_input;
+	} else
+		return 0x1f4; // +125
+}
+EXPORT_SYMBOL(ad7414_get_temp);
+
+#define show(value) \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)		\
+{									\
+	struct ad7414_data *data = ad7414_update_device(dev);		\
+	return sprintf(buf, "%d\n", AD7414_TEMP_FROM_REG(data->value));	\
+}
+show(temp_input);
+
+#define show_8(value)	\
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)		\
+{								\
+	struct ad7414_data *data = ad7414_update_device(dev);	\
+	return sprintf(buf, "%d\n", data->value);		\
+}
+show_8(temp_max);
+show_8(temp_min);
+show_8(temp_alert);
+show_8(temp_max_flag);
+show_8(temp_min_flag);
+
+#define set(value, reg)	\
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)	\
+{								\
+	struct i2c_client *client = to_i2c_client(dev);		\
+	struct ad7414_data *data = i2c_get_clientdata(client);	\
+	int temp = simple_strtoul(buf, NULL, 10);		\
+								\
+	mutex_lock(&data->lock);				\
+	data->value = temp;					\
+	ad7414_write(client, reg, data->value);			\
+	mutex_unlock(&data->lock);				\
+	return count;						\
+}
+set(temp_max, AD7414_REG_T_HIGH);
+set(temp_min, AD7414_REG_T_LOW);
+
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min, set_temp_min);
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
+static DEVICE_ATTR(temp1_alert, S_IRUGO, show_temp_alert, NULL);
+static DEVICE_ATTR(temp1_max_flag, S_IRUGO, show_temp_max_flag, NULL);
+static DEVICE_ATTR(temp1_min_flag, S_IRUGO, show_temp_min_flag, NULL);
+
+static int ad7414_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON))
+		return 0;
+	return i2c_probe(adapter, &addr_data, ad7414_detect);
+}
+
+static struct attribute *ad7414_attributes[] = {
+	&dev_attr_temp1_input.attr,
+	&dev_attr_temp1_max.attr,
+	&dev_attr_temp1_min.attr,
+	&dev_attr_temp1_alert.attr,
+	&dev_attr_temp1_max_flag.attr,
+	&dev_attr_temp1_min_flag.attr,
+	NULL
+};
+
+static const struct attribute_group ad7414_group = {
+	.attrs = ad7414_attributes,
+};
+
+static int ad7414_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct ad7414_data *data;
+	int err = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+					I2C_FUNC_SMBUS_WORD_DATA))
+		goto exit;
+
+	if (!(data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	client = &data->client;
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &ad7414_driver;
+	client->flags = 0;
+
+	i2c_set_clientdata(client, data);
+
+	mutex_init(&data->lock);
+
+	/* TODO: not testing for AD7414 done yet... */
+
+	strlcpy(client->name, ad7414_driver.driver.name, I2C_NAME_SIZE);
+
+	if ((err = i2c_attach_client(client)))
+		goto exit_free;
+
+	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+	/* Initialize the AD7414 chip */
+	ad7414_init_client(client);
+
+	/* Register sysfs hooks */
+	if ((err = sysfs_create_group(&client->dev.kobj, &ad7414_group)))
+		goto exit_detach;
+
+	data->class_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->class_dev)) {
+		err = PTR_ERR(data->class_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	sysfs_remove_group(&client->dev.kobj, &ad7414_group);
+exit_detach:
+	i2c_detach_client(client);
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int ad7414_detach_client(struct i2c_client *client)
+{
+	struct ad7414_data *data = i2c_get_clientdata(client);
+	ad7414_dev = NULL;
+	hwmon_device_unregister(data->class_dev);
+	sysfs_remove_group(&client->dev.kobj, &ad7414_group);
+	i2c_detach_client(client);
+	kfree(data);
+	return 0;
+}
+
+static int __init ad7414_init(void)
+{
+	return i2c_add_driver(&ad7414_driver);
+}
+
+static void __exit ad7414_exit(void)
+{
+	i2c_del_driver(&ad7414_driver);
+}
+
+MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
+MODULE_DESCRIPTION("AD7414 driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ad7414_init);
+module_exit(ad7414_exit);
--- /dev/null	2005-11-20 22:22:37.000000000 -0500
+++ drivers/hwmon/taco-dtm.c	2008-01-05 00:06:21.000000000 -0500
@@ -0,0 +1,78 @@
+/*
+ *  drivers/hwmon/taco-dtm.c
+ *
+ *  Overview: On the Taco, the fpga controls the fan. This provides
+ *  the temperature to the fpga.
+ *
+ *  Copyright (c) 2008 PIKA Technologies
+ *    Sean MacLennan <smaclennan@pikatech.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;  either version 2 of the	License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+
+
+#define TACO_FPGA_BASE 0x80000000
+
+
+extern int ad7414_get_temp(void);
+
+static unsigned __iomem *dtm_fpga;
+static struct task_struct *dtm_thread;
+
+
+static int taco_dtm_thread(void *arg)
+{
+	while(!kthread_should_stop()) {
+		int temp = ad7414_get_temp();
+
+		// Write to FPGA
+		out_be32(dtm_fpga, temp);
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ);
+	}
+
+	return 0;
+}
+
+
+int __init taco_dtm_init_module(void)
+{
+	if((dtm_fpga = ioremap(TACO_FPGA_BASE + 0x20, 4)) == 0) {
+		printk("FPGA ioremap failed\n");
+		return -ENODEV;
+	}
+
+	dtm_thread = kthread_run(taco_dtm_thread, NULL, "taco-dtm");
+
+	if(IS_ERR(dtm_thread)) {
+		iounmap(dtm_fpga);
+		printk("Unable to start Taco DTM thread\n");
+		return PTR_ERR(dtm_thread);
+	}
+
+	return 0;
+}
+
+
+void __exit taco_dtm_exit_module(void)
+{
+	kthread_stop(dtm_thread);
+	iounmap(dtm_fpga);
+}
+
+
+module_init(taco_dtm_init_module);
+module_exit(taco_dtm_exit_module);
+
+MODULE_DESCRIPTION("PIKA DTM driver");
+MODULE_AUTHOR("Sean MacLennan");
+MODULE_LICENSE("GPL");

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] Hwmon for Taco
  2008-01-05  5:11 [PATCH] Hwmon for Taco Sean MacLennan
@ 2008-01-05  7:22 ` Benjamin Herrenschmidt
  2008-01-05 18:39   ` Sean MacLennan
  2008-01-08  6:30   ` Sean MacLennan
  0 siblings, 2 replies; 11+ messages in thread
From: Benjamin Herrenschmidt @ 2008-01-05  7:22 UTC (permalink / raw)
  To: Sean MacLennan; +Cc: linuxppc-dev


> +module_exit(ad7414_exit);
> --- /dev/null	2005-11-20 22:22:37.000000000 -0500
> +++ drivers/hwmon/taco-dtm.c	2008-01-05 00:06:21.000000000 -0500
> @@ -0,0 +1,78 @@
> +/*
> + *  drivers/hwmon/taco-dtm.c
> + *
> + *  Overview: On the Taco, the fpga controls the fan. This provides
> + *  the temperature to the fpga.
> + *
> + *  Copyright (c) 2008 PIKA Technologies
> + *    Sean MacLennan <smaclennan@pikatech.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;  either version 2 of the	License, or (at your
> + *  option) any later version.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kthread.h>
> +#include <linux/io.h>
> +
> +
> +#define TACO_FPGA_BASE 0x80000000

That should be in the device-tree...

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Hwmon for Taco
  2008-01-05  7:22 ` Benjamin Herrenschmidt
@ 2008-01-05 18:39   ` Sean MacLennan
  2008-01-08  6:30   ` Sean MacLennan
  1 sibling, 0 replies; 11+ messages in thread
From: Sean MacLennan @ 2008-01-05 18:39 UTC (permalink / raw)
  To: benh; +Cc: linuxppc-dev

Benjamin Herrenschmidt wrote:
>> +module_exit(ad7414_exit);
>> --- /dev/null	2005-11-20 22:22:37.000000000 -0500
>> +++ drivers/hwmon/taco-dtm.c	2008-01-05 00:06:21.000000000 -0500
>> @@ -0,0 +1,78 @@
>> +/*
>> + *  drivers/hwmon/taco-dtm.c
>> + *
>> + *  Overview: On the Taco, the fpga controls the fan. This provides
>> + *  the temperature to the fpga.
>> + *
>> + *  Copyright (c) 2008 PIKA Technologies
>> + *    Sean MacLennan <smaclennan@pikatech.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;  either version 2 of the	License, or (at your
>> + *  option) any later version.
>> + *
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/kthread.h>
>> +#include <linux/io.h>
>> +
>> +
>> +#define TACO_FPGA_BASE 0x80000000
>>     
>
> That should be in the device-tree...
>
> Cheers,
> Ben.
>
>
>   
It is in the device tree, I just forgot to update the driver to use it. 
Thanks.

Cheers,
    Sean

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Hwmon for Taco
  2008-01-05  7:22 ` Benjamin Herrenschmidt
  2008-01-05 18:39   ` Sean MacLennan
@ 2008-01-08  6:30   ` Sean MacLennan
  2008-01-08  6:59     ` Grant Likely
  1 sibling, 1 reply; 11+ messages in thread
From: Sean MacLennan @ 2008-01-08  6:30 UTC (permalink / raw)
  To: benh; +Cc: linuxppc-dev

Benjamin Herrenschmidt wrote:
> That should be in the device-tree...
>
> Cheers,
> Ben.
>
>   

Now in the device tree. The name of the file has changed.

Cheers,
    Sean

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a0445be..1f89186 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -57,6 +57,16 @@ config SENSORS_ABITUGURU3
       This driver can also be built as a module.  If so, the module
       will be called abituguru3.
 
+config SENSORS_AD7414
+    tristate "Analog Devices AD7414"
+    depends on I2C && EXPERIMENTAL
+    help
+      If you say yes here you get support for the Analog Devices
+      AD7414 temperature monitoring chip.
+
+      This driver can also be built as a module. If so, the module
+      will be called ad7414.
+
 config SENSORS_AD7418
     tristate "Analog Devices AD7416, AD7417 and AD7418"
     depends on I2C && EXPERIMENTAL
@@ -763,4 +773,13 @@ config HWMON_DEBUG_CHIP
       a problem with I2C support and want to see more of what is going
       on.
 
+config PIKA_DTM
+    tristate "PIKA DTM (Dynamic Thermal Management)"
+    depends on HWMON && WARP
+    select SENSORS_AD7414
+    default y
+    help
+      Say Y here if you have a PIKA Warp(tm) Appliance. This driver is
+      required for the DTM to work properly.
+
 endif # HWMON
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 55595f6..0c6ee71 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_W83791D)    += w83791d.o
 
 obj-$(CONFIG_SENSORS_ABITUGURU)    += abituguru.o
 obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
+obj-$(CONFIG_SENSORS_AD7414)    += ad7414.o
 obj-$(CONFIG_SENSORS_AD7418)    += ad7418.o
 obj-$(CONFIG_SENSORS_ADM1021)    += adm1021.o
 obj-$(CONFIG_SENSORS_ADM1025)    += adm1025.o
@@ -69,7 +70,8 @@ obj-$(CONFIG_SENSORS_VT8231)    += vt8231.o
 obj-$(CONFIG_SENSORS_W83627EHF)    += w83627ehf.o
 obj-$(CONFIG_SENSORS_W83L785TS)    += w83l785ts.o
 
+obj-$(CONFIG_PIKA_DTM)        += pika-dtm.o
+
 ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
-
--- /dev/null    2005-11-20 22:22:37.000000000 -0500
+++ drivers/hwmon/pika-dtm.c    2008-01-08 01:23:32.000000000 -0500
@@ -0,0 +1,87 @@
+/*
+ *  drivers/hwmon/pika-dtm.c
+ *
+ *  Overview: On the Warp, the fpga controls the fan. This provides
+ *  the temperature to the fpga.
+ *
+ *  Copyright (c) 2008 PIKA Technologies
+ *    Sean MacLennan <smaclennan@pikatech.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;  either version 2 of the    License, or 
(at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+
+
+extern int ad7414_get_temp(void);
+
+static unsigned __iomem *dtm_fpga;
+static struct task_struct *dtm_thread;
+
+
+static int pika_dtm_thread(void *arg)
+{
+    while(!kthread_should_stop()) {
+        int temp = ad7414_get_temp();
+
+        // Write to FPGA
+        out_be32(dtm_fpga, temp);
+
+        set_current_state(TASK_INTERRUPTIBLE);
+        schedule_timeout(HZ);
+    }
+
+    return 0;
+}
+
+
+int __init pika_dtm_init(void)
+{
+    struct device_node *np;
+    struct resource res;
+
+    if((np = of_find_compatible_node(NULL, NULL, "pika,fpga")) == NULL) {
+        printk(KERN_ERR __FILE__ ": Unable to find FPGA\n");
+        return -ENOENT;
+    }
+
+    /* We do not call of_iomap here since it would map in the entire
+     * fpga space, which is overkill for 4 bytes.
+     */
+    if(of_address_to_resource(np, 0, &res) ||
+       (dtm_fpga = ioremap(res.start + 0x20, 4)) == NULL) {
+        printk(KERN_ERR __FILE__ ": Unable to map FPGA\n");
+        return -ENOENT;
+    }
+
+    dtm_thread = kthread_run(pika_dtm_thread, NULL, "pika-dtm");
+
+    if(IS_ERR(dtm_thread)) {
+        iounmap(dtm_fpga);
+        printk(KERN_ERR __FILE__ ": Unable to start PIKA DTM thread\n");
+        return PTR_ERR(dtm_thread);
+    }
+
+    return 0;
+}
+module_init(pika_dtm_init);
+
+
+void __exit pika_dtm_exit(void)
+{
+    kthread_stop(dtm_thread);
+    iounmap(dtm_fpga);
+}
+module_exit(pika_dtm_exit);
+
+
+MODULE_DESCRIPTION("PIKA DTM driver");
+MODULE_AUTHOR("Sean MacLennan");
+MODULE_LICENSE("GPL");
--- /dev/null    2005-11-20 22:22:37.000000000 -0500
+++ drivers/hwmon/ad7414.c    2008-01-05 20:36:06.000000000 -0500
@@ -0,0 +1,296 @@
+/*
+ * An hwmon driver for the Analog Devices AD7414
+ *
+ * Copyright 2006 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ *
+ * Based on ad7418.c
+ * Copyright 2006 Tower Technologies, Alessandro Zummo 
<a.zummo@towertech.it>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+
+#define DRV_VERSION "0.2"
+
+/* straight from the datasheet */
+#define AD7414_TEMP_MIN (-55000)
+#define AD7414_TEMP_MAX 125000
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x48, 0x4a, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+/* AD7414 registers */
+#define AD7414_REG_TEMP        0x00
+#define AD7414_REG_CONF        0x01
+#define AD7414_REG_T_HIGH    0x02
+#define AD7414_REG_T_LOW    0x03
+
+struct ad7414_data {
+    struct i2c_client    client;
+    struct device    *dev;
+    struct mutex        lock;
+    char            valid;        /* !=0 if following fields are valid */
+    unsigned long        last_updated;    /* In jiffies */
+    u16            temp_input;    /* Register values */
+    u8            temp_max;
+    u8            temp_min;
+    u8            temp_alert;
+    u8            temp_max_flag;
+    u8            temp_min_flag;
+};
+
+static int ad7414_attach_adapter(struct i2c_adapter *adapter);
+static int ad7414_detect(struct i2c_adapter *adapter, int address, int 
kind);
+static int ad7414_detach_client(struct i2c_client *client);
+
+static struct i2c_driver ad7414_driver = {
+    .driver = {
+        .name    = "ad7414",
+    },
+    .attach_adapter    = ad7414_attach_adapter,
+    .detach_client    = ad7414_detach_client,
+};
+
+/*
+ * TEMP: 0.001C/bit (-55C to +125C)
+ * REG: (0.5C/bit, two's complement) << 7
+ */
+static inline int AD7414_TEMP_FROM_REG(u16 reg)
+{
+    /* use integer division instead of equivalent right shift to
+     * guarantee arithmetic shift and preserve the sign
+     */
+    return ((s16)reg / 128) * 500;
+}
+
+/* All registers are word-sized, except for the configuration registers.
+ * AD7414 uses a high-byte first convention, which is exactly opposite to
+ * the usual practice.
+ */
+static int ad7414_read(struct i2c_client *client, u8 reg)
+{
+    if (reg == AD7414_REG_TEMP)
+        return swab16(i2c_smbus_read_word_data(client, reg));
+    else
+        return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int ad7414_write(struct i2c_client *client, u8 reg, u16 value)
+{
+    return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* PIKA Taco - we need to access the temperature in kernel mode. As a
+ * hack we store the device here. This works because we only have one
+ * ad7414 chip.
+ */
+static struct device *ad7414_dev;
+
+static void ad7414_init_client(struct i2c_client *client)
+{
+    /* TODO: anything to do here??? */
+    ad7414_dev = &client->dev;
+}
+
+static struct ad7414_data *ad7414_update_device(struct device *dev)
+{
+    struct i2c_client *client = to_i2c_client(dev);
+    struct ad7414_data *data = i2c_get_clientdata(client);
+
+    mutex_lock(&data->lock);
+
+    if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+        || !data->valid) {
+        dev_dbg(&client->dev, "starting ad7414 update\n");
+
+        data->temp_input = ad7414_read(client, AD7414_REG_TEMP);
+        data->temp_alert = (data->temp_input >> 5) & 0x01;
+        data->temp_max_flag = (data->temp_input >> 4) & 0x01;
+        data->temp_min_flag = (data->temp_input >> 3) & 0x01;
+        data->temp_max = ad7414_read(client, AD7414_REG_T_HIGH);
+        data->temp_min = ad7414_read(client, AD7414_REG_T_LOW);
+
+        data->last_updated = jiffies;
+        data->valid = 1;
+    }
+
+    mutex_unlock(&data->lock);
+
+    return data;
+}
+
+int ad7414_get_temp(void)
+{
+    if(ad7414_dev) {
+        struct ad7414_data *data = ad7414_update_device(ad7414_dev);
+        return data->temp_input;
+    } else
+        return 0x1f4; // +125
+}
+EXPORT_SYMBOL(ad7414_get_temp);
+
+#define show(value) \
+static ssize_t show_##value(struct device *dev, struct device_attribute 
*attr, char *buf)        \
+{                                    \
+    struct ad7414_data *data = ad7414_update_device(dev);        \
+    return sprintf(buf, "%d\n", AD7414_TEMP_FROM_REG(data->value));    \
+}
+show(temp_input);
+
+#define show_8(value)    \
+static ssize_t show_##value(struct device *dev, struct device_attribute 
*attr, char *buf)        \
+{                                \
+    struct ad7414_data *data = ad7414_update_device(dev);    \
+    return sprintf(buf, "%d\n", data->value);        \
+}
+show_8(temp_max);
+show_8(temp_min);
+show_8(temp_alert);
+show_8(temp_max_flag);
+show_8(temp_min_flag);
+
+#define set(value, reg)    \
+static ssize_t set_##value(struct device *dev, struct device_attribute 
*attr, const char *buf, size_t count)    \
+{                                \
+    struct i2c_client *client = to_i2c_client(dev);        \
+    struct ad7414_data *data = i2c_get_clientdata(client);    \
+    int temp = simple_strtoul(buf, NULL, 10);        \
+                                \
+    mutex_lock(&data->lock);                \
+    data->value = temp;                    \
+    ad7414_write(client, reg, data->value);            \
+    mutex_unlock(&data->lock);                \
+    return count;                        \
+}
+set(temp_max, AD7414_REG_T_HIGH);
+set(temp_min, AD7414_REG_T_LOW);
+
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, 
set_temp_max);
+static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min, 
set_temp_min);
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
+static DEVICE_ATTR(temp1_alert, S_IRUGO, show_temp_alert, NULL);
+static DEVICE_ATTR(temp1_max_flag, S_IRUGO, show_temp_max_flag, NULL);
+static DEVICE_ATTR(temp1_min_flag, S_IRUGO, show_temp_min_flag, NULL);
+
+static int ad7414_attach_adapter(struct i2c_adapter *adapter)
+{
+    if (!(adapter->class & I2C_CLASS_HWMON))
+        return 0;
+    return i2c_probe(adapter, &addr_data, ad7414_detect);
+}
+
+static struct attribute *ad7414_attributes[] = {
+    &dev_attr_temp1_input.attr,
+    &dev_attr_temp1_max.attr,
+    &dev_attr_temp1_min.attr,
+    &dev_attr_temp1_alert.attr,
+    &dev_attr_temp1_max_flag.attr,
+    &dev_attr_temp1_min_flag.attr,
+    NULL
+};
+
+static const struct attribute_group ad7414_group = {
+    .attrs = ad7414_attributes,
+};
+
+static int ad7414_detect(struct i2c_adapter *adapter, int address, int 
kind)
+{
+    struct i2c_client *client;
+    struct ad7414_data *data;
+    int err = 0;
+
+    if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+                    I2C_FUNC_SMBUS_WORD_DATA))
+        goto exit;
+
+    if (!(data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL))) {
+        err = -ENOMEM;
+        goto exit;
+    }
+
+    client = &data->client;
+    client->addr = address;
+    client->adapter = adapter;
+    client->driver = &ad7414_driver;
+    client->flags = 0;
+
+    i2c_set_clientdata(client, data);
+
+    mutex_init(&data->lock);
+
+    /* TODO: not testing for AD7414 done yet... */
+
+    strlcpy(client->name, ad7414_driver.driver.name, I2C_NAME_SIZE);
+
+    if ((err = i2c_attach_client(client)))
+        goto exit_free;
+
+    dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+    /* Initialize the AD7414 chip */
+    ad7414_init_client(client);
+
+    /* Register sysfs hooks */
+    if ((err = sysfs_create_group(&client->dev.kobj, &ad7414_group)))
+        goto exit_detach;
+
+    data->dev = hwmon_device_register(&client->dev);
+    if (IS_ERR(data->dev)) {
+        err = PTR_ERR(data->dev);
+        goto exit_remove;
+    }
+
+    return 0;
+
+exit_remove:
+    sysfs_remove_group(&client->dev.kobj, &ad7414_group);
+exit_detach:
+    i2c_detach_client(client);
+exit_free:
+    kfree(data);
+exit:
+    return err;
+}
+
+static int ad7414_detach_client(struct i2c_client *client)
+{
+    struct ad7414_data *data = i2c_get_clientdata(client);
+    ad7414_dev = NULL;
+    hwmon_device_unregister(data->dev);
+    sysfs_remove_group(&client->dev.kobj, &ad7414_group);
+    i2c_detach_client(client);
+    kfree(data);
+    return 0;
+}
+
+static int __init ad7414_init(void)
+{
+    return i2c_add_driver(&ad7414_driver);
+}
+
+static void __exit ad7414_exit(void)
+{
+    i2c_del_driver(&ad7414_driver);
+}
+
+MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
+MODULE_DESCRIPTION("AD7414 driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ad7414_init);
+module_exit(ad7414_exit);

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] Hwmon for Taco
  2008-01-08  6:30   ` Sean MacLennan
@ 2008-01-08  6:59     ` Grant Likely
  2008-01-08 18:09       ` Sean MacLennan
  2008-01-08 18:30       ` Sean MacLennan
  0 siblings, 2 replies; 11+ messages in thread
From: Grant Likely @ 2008-01-08  6:59 UTC (permalink / raw)
  To: Sean MacLennan; +Cc: linuxppc-dev

On 1/7/08, Sean MacLennan <smaclennan@pikatech.com> wrote:
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index a0445be..1f89186 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -57,6 +57,16 @@ config SENSORS_ABITUGURU3
>        This driver can also be built as a module.  If so, the module
>        will be called abituguru3.
>
> +config SENSORS_AD7414
> +    tristate "Analog Devices AD7414"
> +    depends on I2C && EXPERIMENTAL
> +    help
> +      If you say yes here you get support for the Analog Devices
> +      AD7414 temperature monitoring chip.
> +
> +      This driver can also be built as a module. If so, the module
> +      will be called ad7414.
> +
>  config SENSORS_AD7418
>      tristate "Analog Devices AD7416, AD7417 and AD7418"
>      depends on I2C && EXPERIMENTAL
> @@ -763,4 +773,13 @@ config HWMON_DEBUG_CHIP
>        a problem with I2C support and want to see more of what is going
>        on.
>
> +config PIKA_DTM
> +    tristate "PIKA DTM (Dynamic Thermal Management)"
> +    depends on HWMON && WARP
> +    select SENSORS_AD7414

select is dangerous because it bypasses dependency checking.  Make it
'depends on' instead.

> +    default y
> +    help
> +      Say Y here if you have a PIKA Warp(tm) Appliance. This driver is
> +      required for the DTM to work properly.
> +

This patch should be split in 2; one for the AD7414 driver and one for
the thermal management driver.

>  endif # HWMON
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 55595f6..0c6ee71 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_W83791D)    += w83791d.o
>
>  obj-$(CONFIG_SENSORS_ABITUGURU)    += abituguru.o
>  obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
> +obj-$(CONFIG_SENSORS_AD7414)    += ad7414.o
>  obj-$(CONFIG_SENSORS_AD7418)    += ad7418.o
>  obj-$(CONFIG_SENSORS_ADM1021)    += adm1021.o
>  obj-$(CONFIG_SENSORS_ADM1025)    += adm1025.o
> @@ -69,7 +70,8 @@ obj-$(CONFIG_SENSORS_VT8231)    += vt8231.o
>  obj-$(CONFIG_SENSORS_W83627EHF)    += w83627ehf.o
>  obj-$(CONFIG_SENSORS_W83L785TS)    += w83l785ts.o
>
> +obj-$(CONFIG_PIKA_DTM)        += pika-dtm.o
> +
>  ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
>  EXTRA_CFLAGS += -DDEBUG
>  endif
> -
> --- /dev/null    2005-11-20 22:22:37.000000000 -0500
> +++ drivers/hwmon/pika-dtm.c    2008-01-08 01:23:32.000000000 -0500

This is *very* board specific and not very complex a driver.  It
should probably live with the platform code somewhere in
arch/powerpc/platforms.  You can use the machine_device_initcall()
hook to kick off the thread.

> @@ -0,0 +1,87 @@
> +/*
> + *  drivers/hwmon/pika-dtm.c
> + *
> + *  Overview: On the Warp, the fpga controls the fan. This provides
> + *  the temperature to the fpga.
> + *
> + *  Copyright (c) 2008 PIKA Technologies
> + *    Sean MacLennan <smaclennan@pikatech.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;  either version 2 of the    License, or
> (at your
> + *  option) any later version.

Your mailer chewed up the patch here (line wrap).

> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kthread.h>
> +#include <linux/io.h>
> +#include <linux/of_platform.h>
> +
> +
> +extern int ad7414_get_temp(void);

Bad!  Function decls must be in common header files.

> +
> +static unsigned __iomem *dtm_fpga;
> +static struct task_struct *dtm_thread;
> +
> +
> +static int pika_dtm_thread(void *arg)
> +{
> +    while(!kthread_should_stop()) {
> +        int temp = ad7414_get_temp();
> +
> +        // Write to FPGA

Style; use /* */, not //

> +        out_be32(dtm_fpga, temp);
> +
> +        set_current_state(TASK_INTERRUPTIBLE);
> +        schedule_timeout(HZ);
> +    }
> +
> +    return 0;
> +}
> +
> +
> +int __init pika_dtm_init(void)
> +{
> +    struct device_node *np;
> +    struct resource res;
> +
> +    if((np = of_find_compatible_node(NULL, NULL, "pika,fpga")) == NULL) {
> +        printk(KERN_ERR __FILE__ ": Unable to find FPGA\n");
> +        return -ENOENT;
> +    }
> +
> +    /* We do not call of_iomap here since it would map in the entire
> +     * fpga space, which is overkill for 4 bytes.
> +     */

iomapping is not expensive; just map the whole space (it's going to
map a minimum 4k page anyway).  The code will be easier to read if you
just use of_iomap().

> +    if(of_address_to_resource(np, 0, &res) ||
> +       (dtm_fpga = ioremap(res.start + 0x20, 4)) == NULL) {
> +        printk(KERN_ERR __FILE__ ": Unable to map FPGA\n");
> +        return -ENOENT;
> +    }
> +
> +    dtm_thread = kthread_run(pika_dtm_thread, NULL, "pika-dtm");
> +
> +    if(IS_ERR(dtm_thread)) {
> +        iounmap(dtm_fpga);
> +        printk(KERN_ERR __FILE__ ": Unable to start PIKA DTM thread\n");
> +        return PTR_ERR(dtm_thread);
> +    }
> +
> +    return 0;
> +}
> +module_init(pika_dtm_init);
> +
> +
> +void __exit pika_dtm_exit(void)
> +{
> +    kthread_stop(dtm_thread);
> +    iounmap(dtm_fpga);
> +}
> +module_exit(pika_dtm_exit);
> +
> +
> +MODULE_DESCRIPTION("PIKA DTM driver");
> +MODULE_AUTHOR("Sean MacLennan");
> +MODULE_LICENSE("GPL");
> --- /dev/null    2005-11-20 22:22:37.000000000 -0500
> +++ drivers/hwmon/ad7414.c    2008-01-05 20:36:06.000000000 -0500
> @@ -0,0 +1,296 @@
> +/*
> + * An hwmon driver for the Analog Devices AD7414
> + *
> + * Copyright 2006 Stefan Roese <sr@denx.de>, DENX Software Engineering
> + *
> + * Based on ad7418.c
> + * Copyright 2006 Tower Technologies, Alessandro Zummo
> <a.zummo@towertech.it>
> + *
> + * 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.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/jiffies.h>
> +#include <linux/i2c.h>
> +#include <linux/hwmon.h>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/delay.h>
> +
> +
> +#define DRV_VERSION "0.2"
> +
> +/* straight from the datasheet */
> +#define AD7414_TEMP_MIN (-55000)
> +#define AD7414_TEMP_MAX 125000
> +
> +/* Addresses to scan */
> +static unsigned short normal_i2c[] = { 0x48, 0x4a, I2C_CLIENT_END };
> +
> +/* Insmod parameters */
> +I2C_CLIENT_INSMOD;
> +
> +/* AD7414 registers */
> +#define AD7414_REG_TEMP        0x00
> +#define AD7414_REG_CONF        0x01
> +#define AD7414_REG_T_HIGH    0x02
> +#define AD7414_REG_T_LOW    0x03
> +
> +struct ad7414_data {
> +    struct i2c_client    client;
> +    struct device    *dev;
> +    struct mutex        lock;
> +    char            valid;        /* !=0 if following fields are valid */
> +    unsigned long        last_updated;    /* In jiffies */
> +    u16            temp_input;    /* Register values */
> +    u8            temp_max;
> +    u8            temp_min;
> +    u8            temp_alert;
> +    u8            temp_max_flag;
> +    u8            temp_min_flag;
> +};
> +
> +static int ad7414_attach_adapter(struct i2c_adapter *adapter);
> +static int ad7414_detect(struct i2c_adapter *adapter, int address, int
> kind);
> +static int ad7414_detach_client(struct i2c_client *client);
> +
> +static struct i2c_driver ad7414_driver = {
> +    .driver = {
> +        .name    = "ad7414",
> +    },
> +    .attach_adapter    = ad7414_attach_adapter,
> +    .detach_client    = ad7414_detach_client,
> +};
> +
> +/*
> + * TEMP: 0.001C/bit (-55C to +125C)
> + * REG: (0.5C/bit, two's complement) << 7
> + */
> +static inline int AD7414_TEMP_FROM_REG(u16 reg)
> +{
> +    /* use integer division instead of equivalent right shift to
> +     * guarantee arithmetic shift and preserve the sign
> +     */
> +    return ((s16)reg / 128) * 500;
> +}
> +
> +/* All registers are word-sized, except for the configuration registers.
> + * AD7414 uses a high-byte first convention, which is exactly opposite to
> + * the usual practice.
> + */
> +static int ad7414_read(struct i2c_client *client, u8 reg)
> +{
> +    if (reg == AD7414_REG_TEMP)
> +        return swab16(i2c_smbus_read_word_data(client, reg));
> +    else
> +        return i2c_smbus_read_byte_data(client, reg);
> +}
> +
> +static int ad7414_write(struct i2c_client *client, u8 reg, u16 value)
> +{
> +    return i2c_smbus_write_byte_data(client, reg, value);
> +}
> +
> +/* PIKA Taco - we need to access the temperature in kernel mode. As a
> + * hack we store the device here. This works because we only have one
> + * ad7414 chip.
> + */
> +static struct device *ad7414_dev;

Can you use a list_head instead?  That would allow multiple instances.

This driver shouldn't contain board specific code.

> +
> +static void ad7414_init_client(struct i2c_client *client)
> +{
> +    /* TODO: anything to do here??? */
> +    ad7414_dev = &client->dev;

ick.

> +}
> +
> +static struct ad7414_data *ad7414_update_device(struct device *dev)
> +{
> +    struct i2c_client *client = to_i2c_client(dev);
> +    struct ad7414_data *data = i2c_get_clientdata(client);
> +
> +    mutex_lock(&data->lock);
> +
> +    if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
> +        || !data->valid) {
> +        dev_dbg(&client->dev, "starting ad7414 update\n");
> +
> +        data->temp_input = ad7414_read(client, AD7414_REG_TEMP);
> +        data->temp_alert = (data->temp_input >> 5) & 0x01;
> +        data->temp_max_flag = (data->temp_input >> 4) & 0x01;
> +        data->temp_min_flag = (data->temp_input >> 3) & 0x01;
> +        data->temp_max = ad7414_read(client, AD7414_REG_T_HIGH);
> +        data->temp_min = ad7414_read(client, AD7414_REG_T_LOW);
> +
> +        data->last_updated = jiffies;
> +        data->valid = 1;
> +    }
> +
> +    mutex_unlock(&data->lock);
> +
> +    return data;
> +}
> +
> +int ad7414_get_temp(void)

maybe ad7414_get_temp(int index)?  Would allow for multiple instances.

> +{
> +    if(ad7414_dev) {
> +        struct ad7414_data *data = ad7414_update_device(ad7414_dev);
> +        return data->temp_input;
> +    } else
> +        return 0x1f4; // +125

Style; c++ comment

Cheers,
g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Hwmon for Taco
  2008-01-08  6:59     ` Grant Likely
@ 2008-01-08 18:09       ` Sean MacLennan
  2008-01-08 18:30       ` Sean MacLennan
  1 sibling, 0 replies; 11+ messages in thread
From: Sean MacLennan @ 2008-01-08 18:09 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev

Grant Likely wrote:
> This is *very* board specific and not very complex a driver.  It
> should probably live with the platform code somewhere in
> arch/powerpc/platforms.  You can use the machine_device_initcall()
> hook to kick off the thread.
>   
Doh, this is why I post to this list. The platform code already had an 
obvious place to put this, so I moved it there.

I will cleanup the ad7414.c driver and repost the patch.

Cheers,
   Sean

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Hwmon for Taco
  2008-01-08  6:59     ` Grant Likely
  2008-01-08 18:09       ` Sean MacLennan
@ 2008-01-08 18:30       ` Sean MacLennan
  2008-01-08 19:02         ` Josh Boyer
  1 sibling, 1 reply; 11+ messages in thread
From: Sean MacLennan @ 2008-01-08 18:30 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev

Ok, here is the ad7414 only. taco-dtm is no more!

Cheers,
   Sean

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a0445be..f14972a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -57,6 +57,16 @@ config SENSORS_ABITUGURU3
 	  This driver can also be built as a module.  If so, the module
 	  will be called abituguru3.
 
+config SENSORS_AD7414
+	tristate "Analog Devices AD7414"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the Analog Devices
+	  AD7414 temperature monitoring chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called ad7414.
+
 config SENSORS_AD7418
 	tristate "Analog Devices AD7416, AD7417 and AD7418"
 	depends on I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 55595f6..fa6066e 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_W83791D)	+= w83791d.o
 
 obj-$(CONFIG_SENSORS_ABITUGURU)	+= abituguru.o
 obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
+obj-$(CONFIG_SENSORS_AD7414)	+= ad7414.o
 obj-$(CONFIG_SENSORS_AD7418)	+= ad7418.o
 obj-$(CONFIG_SENSORS_ADM1021)	+= adm1021.o
 obj-$(CONFIG_SENSORS_ADM1025)	+= adm1025.o
@@ -72,4 +73,3 @@ obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l785ts.o
 ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
-
--- /dev/null	2005-11-20 22:22:37.000000000 -0500
+++ drivers/hwmon/ad7414.c	2008-01-08 02:43:24.000000000 -0500
@@ -0,0 +1,319 @@
+/*
+ * An hwmon driver for the Analog Devices AD7414
+ *
+ * Copyright 2006 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ *
+ * Based on ad7418.c
+ * Copyright 2006 Tower Technologies, Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+
+#define DRV_VERSION "0.2"
+
+/* straight from the datasheet */
+#define AD7414_TEMP_MIN (-55000)
+#define AD7414_TEMP_MAX 125000
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x48, 0x4a, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+/* AD7414 registers */
+#define AD7414_REG_TEMP		0x00
+#define AD7414_REG_CONF		0x01
+#define AD7414_REG_T_HIGH	0x02
+#define AD7414_REG_T_LOW	0x03
+
+struct ad7414_data {
+	struct i2c_client	client;
+	struct device	*dev;
+	struct mutex		lock;
+	char			valid;		/* !=0 if following fields are valid */
+	unsigned long		last_updated;	/* In jiffies */
+	u16			temp_input;	/* Register values */
+	u8			temp_max;
+	u8			temp_min;
+	u8			temp_alert;
+	u8			temp_max_flag;
+	u8			temp_min_flag;
+};
+
+
+struct ad7414_dev {
+	struct list_head list;
+	struct device *dev;
+};
+
+static LIST_HEAD(ad7414_dev_list);
+
+
+static int ad7414_attach_adapter(struct i2c_adapter *adapter);
+static int ad7414_detect(struct i2c_adapter *adapter, int address, int kind);
+static int ad7414_detach_client(struct i2c_client *client);
+
+static struct i2c_driver ad7414_driver = {
+	.driver = {
+		.name	= "ad7414",
+	},
+	.attach_adapter	= ad7414_attach_adapter,
+	.detach_client	= ad7414_detach_client,
+};
+
+/*
+ * TEMP: 0.001C/bit (-55C to +125C)
+ * REG: (0.5C/bit, two's complement) << 7
+ */
+static inline int AD7414_TEMP_FROM_REG(u16 reg)
+{
+	/* use integer division instead of equivalent right shift to
+	 * guarantee arithmetic shift and preserve the sign
+	 */
+	return ((s16)reg / 128) * 500;
+}
+
+/* All registers are word-sized, except for the configuration registers.
+ * AD7414 uses a high-byte first convention, which is exactly opposite to
+ * the usual practice.
+ */
+static int ad7414_read(struct i2c_client *client, u8 reg)
+{
+	if (reg == AD7414_REG_TEMP)
+		return swab16(i2c_smbus_read_word_data(client, reg));
+	else
+		return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int ad7414_write(struct i2c_client *client, u8 reg, u16 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static void ad7414_init_client(struct i2c_client *client)
+{
+	struct ad7414_dev *new;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if(new == NULL)
+		printk(KERN_ERR "ad7414_init_client: Unable to allocate memory\n");
+	else {
+		new->dev = &client->dev;
+		list_add_tail(&new->list, &ad7414_dev_list);
+	}
+}
+
+static struct ad7414_data *ad7414_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ad7414_data *data = i2c_get_clientdata(client);
+
+	mutex_lock(&data->lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+		|| !data->valid) {
+		dev_dbg(&client->dev, "starting ad7414 update\n");
+
+		data->temp_input = ad7414_read(client, AD7414_REG_TEMP);
+		data->temp_alert = (data->temp_input >> 5) & 0x01;
+		data->temp_max_flag = (data->temp_input >> 4) & 0x01;
+		data->temp_min_flag = (data->temp_input >> 3) & 0x01;
+		data->temp_max = ad7414_read(client, AD7414_REG_T_HIGH);
+		data->temp_min = ad7414_read(client, AD7414_REG_T_LOW);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->lock);
+
+	return data;
+}
+
+int ad7414_get_temp(int index)
+{
+	struct ad7414_dev *dev;
+
+	list_for_each_entry(dev, &ad7414_dev_list, list) {
+		if(index <= 0) {
+			struct ad7414_data *data = ad7414_update_device(dev->dev);
+			return data->temp_input;
+		}
+		--index;
+	}
+
+	return 0x1f4; /* +125 */
+}
+EXPORT_SYMBOL(ad7414_get_temp);
+
+#define show(value) \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)		\
+{									\
+	struct ad7414_data *data = ad7414_update_device(dev);		\
+	return sprintf(buf, "%d\n", AD7414_TEMP_FROM_REG(data->value));	\
+}
+show(temp_input);
+
+#define show_8(value)	\
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)		\
+{								\
+	struct ad7414_data *data = ad7414_update_device(dev);	\
+	return sprintf(buf, "%d\n", data->value);		\
+}
+show_8(temp_max);
+show_8(temp_min);
+show_8(temp_alert);
+show_8(temp_max_flag);
+show_8(temp_min_flag);
+
+#define set(value, reg)	\
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)	\
+{								\
+	struct i2c_client *client = to_i2c_client(dev);		\
+	struct ad7414_data *data = i2c_get_clientdata(client);	\
+	int temp = simple_strtoul(buf, NULL, 10);		\
+								\
+	mutex_lock(&data->lock);				\
+	data->value = temp;					\
+	ad7414_write(client, reg, data->value);			\
+	mutex_unlock(&data->lock);				\
+	return count;						\
+}
+set(temp_max, AD7414_REG_T_HIGH);
+set(temp_min, AD7414_REG_T_LOW);
+
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min, set_temp_min);
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
+static DEVICE_ATTR(temp1_alert, S_IRUGO, show_temp_alert, NULL);
+static DEVICE_ATTR(temp1_max_flag, S_IRUGO, show_temp_max_flag, NULL);
+static DEVICE_ATTR(temp1_min_flag, S_IRUGO, show_temp_min_flag, NULL);
+
+static int ad7414_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON))
+		return 0;
+	return i2c_probe(adapter, &addr_data, ad7414_detect);
+}
+
+static struct attribute *ad7414_attributes[] = {
+	&dev_attr_temp1_input.attr,
+	&dev_attr_temp1_max.attr,
+	&dev_attr_temp1_min.attr,
+	&dev_attr_temp1_alert.attr,
+	&dev_attr_temp1_max_flag.attr,
+	&dev_attr_temp1_min_flag.attr,
+	NULL
+};
+
+static const struct attribute_group ad7414_group = {
+	.attrs = ad7414_attributes,
+};
+
+static int ad7414_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct ad7414_data *data;
+	int err = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+					I2C_FUNC_SMBUS_WORD_DATA))
+		goto exit;
+
+	if (!(data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	client = &data->client;
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &ad7414_driver;
+	client->flags = 0;
+
+	i2c_set_clientdata(client, data);
+
+	mutex_init(&data->lock);
+
+	/* TODO: not testing for AD7414 done yet... */
+
+	strlcpy(client->name, ad7414_driver.driver.name, I2C_NAME_SIZE);
+
+	if ((err = i2c_attach_client(client)))
+		goto exit_free;
+
+	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+	/* Initialize the AD7414 chip */
+	ad7414_init_client(client);
+
+	/* Register sysfs hooks */
+	if ((err = sysfs_create_group(&client->dev.kobj, &ad7414_group)))
+		goto exit_detach;
+
+	data->dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->dev)) {
+		err = PTR_ERR(data->dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	sysfs_remove_group(&client->dev.kobj, &ad7414_group);
+exit_detach:
+	i2c_detach_client(client);
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int ad7414_detach_client(struct i2c_client *client)
+{
+	struct ad7414_data *data = i2c_get_clientdata(client);
+	struct ad7414_dev *dev;
+
+	list_for_each_entry(dev, &ad7414_dev_list, list)
+		if(dev->dev == &client->dev) {
+			list_del(&dev->list);
+			break;
+		}
+
+	hwmon_device_unregister(data->dev);
+	sysfs_remove_group(&client->dev.kobj, &ad7414_group);
+	i2c_detach_client(client);
+	kfree(data);
+	return 0;
+}
+
+static int __init ad7414_init(void)
+{
+	return i2c_add_driver(&ad7414_driver);
+}
+
+static void __exit ad7414_exit(void)
+{
+	i2c_del_driver(&ad7414_driver);
+}
+
+MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
+MODULE_DESCRIPTION("AD7414 driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ad7414_init);
+module_exit(ad7414_exit);

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] Hwmon for Taco
  2008-01-08 18:30       ` Sean MacLennan
@ 2008-01-08 19:02         ` Josh Boyer
  2008-01-08 19:27           ` Stefan Roese
  2008-01-08 20:13           ` Anton Vorontsov
  0 siblings, 2 replies; 11+ messages in thread
From: Josh Boyer @ 2008-01-08 19:02 UTC (permalink / raw)
  To: Sean MacLennan; +Cc: linuxppc-dev

On Tue, 08 Jan 2008 13:30:00 -0500
Sean MacLennan <smaclennan@pikatech.com> wrote:

> Ok, here is the ad7414 only. taco-dtm is no more!

Cool.  Couple more things.

1) This should go through the hwmon maintainer.  Send it to him.
(CC'ing this list is of course fine.)

2) You always need the Signed-off-by: for each patch you send

3) If you didn't author the code (this seems to come from Stefan), then
you need the Signed-off-by from the original author.

You're getting there :)  These are all "newbie" type mistakes so keep
plugging away.

josh

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Hwmon for Taco
  2008-01-08 19:02         ` Josh Boyer
@ 2008-01-08 19:27           ` Stefan Roese
  2008-01-08 20:13           ` Anton Vorontsov
  1 sibling, 0 replies; 11+ messages in thread
From: Stefan Roese @ 2008-01-08 19:27 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Sean MacLennan

On Tuesday 08 January 2008, Josh Boyer wrote:
> On Tue, 08 Jan 2008 13:30:00 -0500
>
> Sean MacLennan <smaclennan@pikatech.com> wrote:
> > Ok, here is the ad7414 only. taco-dtm is no more!
>
> Cool.  Couple more things.
>
> 1) This should go through the hwmon maintainer.  Send it to him.
> (CC'ing this list is of course fine.)
>
> 2) You always need the Signed-off-by: for each patch you send
>
> 3) If you didn't author the code (this seems to come from Stefan), then
> you need the Signed-off-by from the original author.

Yes, please add my Signed-off-by on top of yours. That will make clear that I 
originally wrote the code.

> You're getting there :)  These are all "newbie" type mistakes so keep
> plugging away.

Right. Keep up the good work.

Thanks.

Ciao,
Stefan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Hwmon for Taco
  2008-01-08 19:02         ` Josh Boyer
  2008-01-08 19:27           ` Stefan Roese
@ 2008-01-08 20:13           ` Anton Vorontsov
  2008-01-08 20:20             ` Josh Boyer
  1 sibling, 1 reply; 11+ messages in thread
From: Anton Vorontsov @ 2008-01-08 20:13 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev, Sean MacLennan

On Tue, Jan 08, 2008 at 01:02:51PM -0600, Josh Boyer wrote:
> On Tue, 08 Jan 2008 13:30:00 -0500
> Sean MacLennan <smaclennan@pikatech.com> wrote:
> 
> > Ok, here is the ad7414 only. taco-dtm is no more!
> 
> Cool.  Couple more things.
> 
> 1) This should go through the hwmon maintainer.  Send it to him.
> (CC'ing this list is of course fine.)
> 
> 2) You always need the Signed-off-by: for each patch you send
> 
> 3) If you didn't author the code (this seems to come from Stefan), then
> you need the Signed-off-by from the original author.

Nope. Signed-off-by means completely different thing. It isn't
copyright, it isn't authorship. It's an information (for the history)
whom to bother if code appeared to be either:
a) broken;
b) stolen from the closed source product;
c) patented (where applicable).

There are Copyright (c) and Author: strings in the files for the
credits. If original patch had these strings, then yes, you must
keep them.

But no one needs author's Signed-off-by, it having zero information
you're hinting about. More than that, there were precedents when
author insisted on removing his Signed-off-by from the modified
patch (when S-o-b used as a permit into someone's tree).

Btw, kernel.org is distributing linux tarballs without changelogs,
thus without Signed-off-by lines. Nobody complains.


Yes, it's common sense and politeness to keep Signed-off-by lines
intact (and the order of these lines), but it's not strict
requirement. "Based on the patch from ..." is the equivalent of
this politeness.

> You're getting there :)  These are all "newbie" type mistakes so keep
> plugging away.
> 
> josh

Good luck,

-- 
Anton Vorontsov
email: cbou@mail.ru
backup email: ya-cbou@yandex.ru
irc://irc.freenode.net/bd2

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Hwmon for Taco
  2008-01-08 20:13           ` Anton Vorontsov
@ 2008-01-08 20:20             ` Josh Boyer
  0 siblings, 0 replies; 11+ messages in thread
From: Josh Boyer @ 2008-01-08 20:20 UTC (permalink / raw)
  To: avorontsov; +Cc: linuxppc-dev, Sean MacLennan

On Tue, 8 Jan 2008 23:13:14 +0300
Anton Vorontsov <avorontsov@ru.mvista.com> wrote:

[snip mostly valid stuff]

> Yes, it's common sense and politeness to keep Signed-off-by lines
> intact (and the order of these lines), but it's not strict
> requirement. "Based on the patch from ..." is the equivalent of
> this politeness.

You took my statement slightly out of context (or I did a lousy job of
explaining for this case).

Basically, I _know_ that Stefan has S-o-b lines in his tree.  I _know_
he did most of the work, and I _know_ he's fairly agreeable to adding
his S-o-b line to patches he isn't pushing himself.

So I was simply asking if Sean could get Stefan to add his S-o-b as
well.  At the very least a "From:" would be warranted if Sean hasn't
change any code.  Then authorship would still be attributed to Stefan.

Yeah, it might be "politeness" but there's really no reason to be
impolite when all the parties involved are in the same discussion...

josh

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2008-01-08 20:20 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-01-05  5:11 [PATCH] Hwmon for Taco Sean MacLennan
2008-01-05  7:22 ` Benjamin Herrenschmidt
2008-01-05 18:39   ` Sean MacLennan
2008-01-08  6:30   ` Sean MacLennan
2008-01-08  6:59     ` Grant Likely
2008-01-08 18:09       ` Sean MacLennan
2008-01-08 18:30       ` Sean MacLennan
2008-01-08 19:02         ` Josh Boyer
2008-01-08 19:27           ` Stefan Roese
2008-01-08 20:13           ` Anton Vorontsov
2008-01-08 20:20             ` Josh Boyer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.