From: Sean MacLennan <smaclennan@pikatech.com>
To: linuxppc-dev@ozlabs.org
Subject: [PATCH] Hwmon for Taco
Date: Sat, 05 Jan 2008 00:11:50 -0500 [thread overview]
Message-ID: <477F1196.7000109@pikatech.com> (raw)
[-- 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");
next reply other threads:[~2008-01-05 5:11 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-01-05 5:11 Sean MacLennan [this message]
2008-01-05 7:22 ` [PATCH] Hwmon for Taco 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=477F1196.7000109@pikatech.com \
--to=smaclennan@pikatech.com \
--cc=linuxppc-dev@ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.