From: Theuns Verwoerd <theuns@bluewatersys.com>
To: r.marek@sh.cvut.cz
Cc: linux-kernel@vger.kernel.org
Subject: [PATCH 001/001] I2C: AD7414 I2C chip driver for Linux-2.6.17.7
Date: Fri, 04 Aug 2006 11:53:04 +1200 [thread overview]
Message-ID: <44D28C60.1000304@bluewatersys.com> (raw)
AD7414 Temperature Sensor I2C driver. I2C chip driver for the Analog
Devices AD7414 device, exposes raw and decoded registers via sysfs.
Signed-off-by: Theuns Verwoerd <theuns.verwoerd@bluewatersys.com>
---
Tested on a custom EP9315-based board developed in-house. Fairly trivial
driver; really just exposes the raw registers and temperature reading
to userspace.
Patch is relative to stock Linux-2.6.17.7
[This is my first go at a kernel submission, so feel free to point out
anything
that should be done differently]
---
diff -uprN -X linux-2.6.17.7-vanilla/Documentation/dontdiff
linux-2.6.17.7-vanilla/drivers/i2c/chips/ad7414.c
linux-2.6.17.7/drivers/i2c/chips/ad7414.c
--- linux-2.6.17.7-vanilla/drivers/i2c/chips/ad7414.c 1970-01-01
12:00:00.000000000 +1200
+++ linux-2.6.17.7/drivers/i2c/chips/ad7414.c 2006-08-04
10:28:37.000000000 +1200
@@ -0,0 +1,283 @@
+/*
+ * AD7414 I2C Chip Driver
+ *
+ * Copyright (C) 2006 Theuns Verwoerd, Bluewater Systems
(theuns.verwoerd@bluewatersys.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, version 2 of the License.
+ *
+ * Simple I2C driver for Analog Devices AD7414 temperature sensor.
+ * Based on: lm75.c
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x4a, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(ad7414);
+
+/* AD7414 Registers */
+#define AD7414_REG_TEMP 0
+#define AD7414_REG_CONF 1
+#define AD7414_REG_TEMP_HIGH 2
+#define AD7414_REG_TEMP_LOW 3
+
+/* Each client has this additional data */
+struct ad7414_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+ struct mutex update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+ u16 temp_value; /* Register values */
+ u16 temp_config;
+ u16 temp_high;
+ u16 temp_low;
+};
+
+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 ad7414_data *ad7414_update_device(struct device *dev);
+static int ad7414_ADC_to_temp(int ADC);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ad7414_driver = {
+ .driver = {
+ .name = "ad7414",
+ },
+ .id = I2C_DRIVERID_AD7414,
+ .attach_adapter = ad7414_attach_adapter,
+ .detach_client = ad7414_detach_client,
+};
+
+#define show_raw(value) \
+static ssize_t show_raw_##value(struct device *dev, struct
device_attribute *attr, char *buf) \
+{ \
+ struct ad7414_data *data = ad7414_update_device(dev); \
+ \
+ return sprintf(buf, "0x%x\n", data->value); \
+}
+show_raw(temp_value);
+show_raw(temp_config);
+show_raw(temp_high);
+show_raw(temp_low);
+
+#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, "%dC\n", data->value); \
+}
+show(temp_high);
+show(temp_low);
+
+static ssize_t show_temp_value(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ad7414_data *data = ad7414_update_device(dev);
+ return sprintf(buf, "%d.%02uC %s%s%s\n",
+ ad7414_ADC_to_temp(data->temp_value) / 100,
+ abs(ad7414_ADC_to_temp(data->temp_value)) % 100,
+ data->temp_value & 0x20 ? "ALERT " : "",
+ data->temp_value & 0x10 ? "THIGH " : "",
+ data->temp_value & 0x20 ? "TLOW " : "");
+}
+
+static ssize_t show_temp_config(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ad7414_data *data = ad7414_update_device(dev);
+ return sprintf(buf, "0x%x %s%s%s%s%s%s%s\n", data->temp_config,
+ data->temp_config & 0x80 ? "POWEROFF " : "",
+ data->temp_config & 0x40 ? "NOFILTER " : "",
+ data->temp_config & 0x20 ? "NOALERT " : "",
+ data->temp_config & 0x10 ? "ALRTHIGH " : "ALRTLOW ",
+ data->temp_config & 0x08 ? "ALERTRST " : "",
+ data->temp_config & 0x04 ? "ONESHOT " : "",
+ data->temp_config & 0x03 ? "TESTMODE " : "");
+}
+
+#define set_raw(value, reg) \
+static ssize_t set_raw_##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 value = simple_strtoul(buf, NULL, 0); \
+ \
+ mutex_lock(&data->update_lock); \
+ data->value = value; \
+ i2c_smbus_write_byte_data(client, reg, value); \
+ mutex_unlock(&data->update_lock); \
+ return count; \
+}
+set_raw(temp_config, AD7414_REG_CONF);
+set_raw(temp_high, AD7414_REG_TEMP_HIGH);
+set_raw(temp_low, AD7414_REG_TEMP_LOW);
+
+static DEVICE_ATTR(raw_config, S_IWUSR | S_IRUGO, show_raw_temp_config,
+ set_raw_temp_config);
+static DEVICE_ATTR(raw_high, S_IWUSR | S_IRUGO, show_raw_temp_high,
+ set_raw_temp_high);
+static DEVICE_ATTR(raw_low, S_IWUSR | S_IRUGO, show_raw_temp_low,
+ set_raw_temp_low);
+static DEVICE_ATTR(raw_value, S_IRUGO, show_raw_temp_value, NULL);
+
+static DEVICE_ATTR(temp_config, S_IRUGO, show_temp_config, NULL);
+static DEVICE_ATTR(temp_high, S_IRUGO, show_temp_high, NULL);
+static DEVICE_ATTR(temp_low, S_IRUGO, show_temp_low, NULL);
+static DEVICE_ATTR(temp_value, S_IRUGO, show_temp_value, NULL);
+
+static int ad7414_ADC_to_temp(int ADC)
+{
+ /* ADC temp is D15..D6, two's complement, but it's only 10 bits */
+ ADC = ADC >> 6;
+ if (ADC > 0x200) {
+ return (((ADC & 0x1ff) - 512) * 100 / 4);
+ } else {
+ return (ADC * 100 / 4);
+ }
+}
+
+static int ad7414_read_value(struct i2c_client *client, u8 reg)
+{
+ int value = ~0;
+ switch (reg) {
+ case AD7414_REG_TEMP: /* 10-bit register, MSB first */
+ value = swab16(i2c_smbus_read_word_data(client, reg));
+ break;
+ default: /* 8-bit register */
+ value = i2c_smbus_read_byte_data(client, reg);
+ break;
+ }
+ return value;
+}
+
+static int ad7414_attach_adapter(struct i2c_adapter *adapter)
+{
+ return i2c_probe(adapter, &addr_data, ad7414_detect);
+}
+
+/* This function is called by i2c_probe */
+static int ad7414_detect(struct i2c_adapter *adapter, int address,
+ int kind)
+{
+ struct i2c_client *new_client = NULL;
+ struct ad7414_data *data = NULL;
+ int err = 0;
+
+ if (!i2c_check_functionality
+ (adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+ goto error;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ new_client = &data->client;
+ i2c_set_clientdata(new_client, data);
+ new_client->addr = address;
+ new_client->adapter = adapter;
+ new_client->driver = &ad7414_driver;
+ new_client->flags = 0;
+
+ /* Fill in the remaining client fields */
+ strncpy(new_client->name, "ad7414", I2C_NAME_SIZE);
+ data->valid = 0;
+ mutex_init(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+ err = i2c_attach_client(new_client);
+ if (err)
+ goto error;
+
+ /* Register sysfs files */
+ device_create_file(&new_client->dev, &dev_attr_raw_config);
+ device_create_file(&new_client->dev, &dev_attr_raw_high);
+ device_create_file(&new_client->dev, &dev_attr_raw_low);
+ device_create_file(&new_client->dev, &dev_attr_raw_value);
+
+ device_create_file(&new_client->dev, &dev_attr_temp_config);
+ device_create_file(&new_client->dev, &dev_attr_temp_high);
+ device_create_file(&new_client->dev, &dev_attr_temp_low);
+ device_create_file(&new_client->dev, &dev_attr_temp_value);
+
+ return 0;
+
+ error:
+ kfree(data);
+ return err;
+}
+
+static int ad7414_detach_client(struct i2c_client *client)
+{
+ struct ad7414_data *data = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ dev_err(&client->dev,
+ "Client deregistration failed, client not detached.\n");
+ return err;
+ }
+ kfree(data);
+ return 0;
+}
+
+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->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ dev_dbg(&client->dev, "Starting ad7414 update\n");
+
+ data->temp_value =
+ ad7414_read_value(client, AD7414_REG_TEMP);
+ data->temp_config =
+ ad7414_read_value(client, AD7414_REG_CONF);
+ data->temp_high =
+ ad7414_read_value(client, AD7414_REG_TEMP_HIGH);
+ data->temp_low =
+ ad7414_read_value(client, AD7414_REG_TEMP_LOW);
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+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("Theuns Verwoerd <theuns.verwoerd@bluewatersys.com>");
+MODULE_DESCRIPTION("AD7414 I2C driver");
+MODULE_LICENSE("GPL");
+
+module_init(ad7414_init);
+module_exit(ad7414_exit);
diff -uprN -X linux-2.6.17.7-vanilla/Documentation/dontdiff
linux-2.6.17.7-vanilla/drivers/i2c/chips/Kconfig
linux-2.6.17.7/drivers/i2c/chips/Kconfig
--- linux-2.6.17.7-vanilla/drivers/i2c/chips/Kconfig 2006-07-25
15:36:01.000000000 +1200
+++ linux-2.6.17.7/drivers/i2c/chips/Kconfig 2006-08-04
10:21:13.000000000 +1200
@@ -25,6 +25,16 @@ config SENSORS_DS1374
This driver can also be built as a module. If so, the module
will be called ds1374.
+config SENSORS_AD7414
+ tristate "Analog Devices AD7414-0 Temperature Sensor"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for Analog Devices
+ AD7414-0 temperature sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called ad7414.
+
config SENSORS_EEPROM
tristate "EEPROM reader"
depends on I2C && EXPERIMENTAL
diff -uprN -X linux-2.6.17.7-vanilla/Documentation/dontdiff
linux-2.6.17.7-vanilla/drivers/i2c/chips/Makefile
linux-2.6.17.7/drivers/i2c/chips/Makefile
--- linux-2.6.17.7-vanilla/drivers/i2c/chips/Makefile 2006-07-25
15:36:01.000000000 +1200
+++ linux-2.6.17.7/drivers/i2c/chips/Makefile 2006-08-04
10:18:48.000000000 +1200
@@ -12,6 +12,7 @@ obj-$(CONFIG_SENSORS_PCF8574) += pcf8574
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TPS65010) += tps65010.o
+obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
diff -uprN -X linux-2.6.17.7-vanilla/Documentation/dontdiff
linux-2.6.17.7-vanilla/include/linux/i2c-id.h
linux-2.6.17.7/include/linux/i2c-id.h
--- linux-2.6.17.7-vanilla/include/linux/i2c-id.h 2006-07-25
15:36:01.000000000 +1200
+++ linux-2.6.17.7/include/linux/i2c-id.h 2006-08-04
10:10:39.000000000 +1200
@@ -112,6 +112,7 @@
#define I2C_DRIVERID_X1205 82 /* Xicor/Intersil X1205 RTC */
#define I2C_DRIVERID_PCF8563 83 /* Philips PCF8563 RTC */
#define I2C_DRIVERID_RS5C372 84 /* Ricoh RS5C372 RTC */
+#define I2C_DRIVERID_AD7414 85 /* AD7414 I2C Chip Driver */
#define I2C_DRIVERID_I2CDEV 900
#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
next reply other threads:[~2006-08-03 23:53 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-08-03 23:53 Theuns Verwoerd [this message]
2006-08-04 3:23 ` [PATCH 001/001] I2C: AD7414 I2C chip driver for Linux-2.6.17.7 Randy.Dunlap
2006-08-06 11:31 ` Jean Delvare
2006-08-08 4:38 ` Theuns Verwoerd
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=44D28C60.1000304@bluewatersys.com \
--to=theuns@bluewatersys.com \
--cc=linux-kernel@vger.kernel.org \
--cc=r.marek@sh.cvut.cz \
/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.