From: Anish Patel <anish.mailing.list@gmail.com>
To: lm-sensors@vger.kernel.org
Subject: [lm-sensors] driver for emc1023
Date: Mon, 17 Jan 2011 19:18:36 +0000 [thread overview]
Message-ID: <4D34960C.8070303@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 381 bytes --]
here is the driver for the emc1023 and the makefile patch.
i've spent a couple hours now trying to figure out how to create a patch
for a new file, and can't find anything.
if someone would care to point me in the right direction i'll resubmit,
but at this point i am tired of trying to figure this out.
Doc/SubmittingDrivers and SubmittingPatches is no help on how to do this.
[-- Attachment #2: emc1023.c --]
[-- Type: text/x-c, Size: 9528 bytes --]
/* emc1023.c
*
* Copyright (C) 2011 Anish K. Patel <anishs.online.junk@gmail.com>
* based heavily on tmp401.c
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
* Driver for the SMSC EMC1023 SMBUS temperature sensor IC.
* examples taken from datasheet
*
* legacy format (LF)
* registers for temperature store them in an 11bit value,
* 2's complement form
* the high byte holds the sign and the whole number part
* the low byte holds the fraction in the upper 3 bits.
* goes from -63.125 to 127.875
* bit 7 - 0.500
* bit 6 - 0.250
* bit 5 - 0.125
* temp data junk bits hex
* ie Diode fault = 10000000000|00000 400
* -63 = 11000001000|00000 608
* -63.875 = 11000000001|00000 601
* 0 = 00000000000|00000 000
* 1 = 00000001000|00000 008
* 127 = 01111111000|00000 3F8
* 127.875 = 01111111111|00000 3FF
*
* for the extend format (EF) add 64d to read the data
*
*
* todo - clean up the fraction part, implement EF temp
* *possibly make EF reporting default with module flag
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x48,0x49,0x4c,0x4d, I2C_CLIENT_END };
enum chips { emc1023_1 , emc1023_2, emc1023_3, emc1023_4 };
/*
* The EMC1023 registers, note some registers have different addresses for
* reading and writing
* device id - seems to be the 8,9,c,d corresponding to address of IC
* ie devid 0x08 ic addr 0x48, etc
*/
#define EMC1023_ONE_SHOT_CMD 0x0F
#define EMC1023_RMT1_IF_RW 0x27
#define EMC1023_RMT2_IF_RW 0x28
#define EMC1023_STATUS 0x02
#define EMC1023_CONFIG_READ 0x03
#define EMC1023_CONFIG_WRITE 0x09
#define EMC1023_DEVICE_ID_REG 0xED
#define EMC1023_MANUFACTURER_ID_REG 0xFE
#define EMC1023_PRODUCT_ID_REG 0xFF
#define EMC1023_MANUFACTURER_ID 0x5D
#define EMC1023_DEVICE_ID_1 0x0C
#define EMC1023_DEVICE_ID_2 0x0D
#define EMC1023_DEVICE_ID_3 0x08
#define EMC1023_DEVICE_ID_4 0x09
static const u8 EMC1023_DEVICE_ID[] = { 0x08, 0x09,
0x0c, 0x0d };
static const u8 EMC1023_LF_TEMP_HIGH_BYTE[3] = { 0x00, 0x01, 0xF8 };
static const u8 EMC1023_LF_TEMP_LOW_BYTE[3] = { 0x23, 0x10, 0xF9 };
static const u8 EMC1023_EF_TEMP_HIGH_BYTE[2] = { 0xFA, 0XFC };
static const u8 EMC1023_EF_TEMP_LOW_BYTE[2] = { 0xFB, 0XFD };
/*
* Driver data (common to all clients)
*/
static const struct i2c_device_id emc1023_id[] = {
{ "emc1023_1", emc1023_1 },
{ "emc1023_2", emc1023_2 },
{ "emc1023_3", emc1023_3 },
{ "emc1023_4", emc1023_4 },
{ }
};
MODULE_DEVICE_TABLE(i2c, emc1023_id);
/*
* Client data (each client gets its own)
*/
struct emc1023_data {
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
enum chips kind;
/* register values */
u8 status;
u8 config;
u16 temp;
u8 temp_high[3];
u8 temp_low[3];
};
/*
* Sysfs attr show / store functions
*/
static int emc1023_register_to_temp(u8 reg_high,u8 reg_low)
{
int temphigh = reg_high;
//since we only need the top 3bits from reg_low shift over 5
//and then do the magic below to pop temp low with correct data
int templow = (reg_low >> 5);
if ( temphigh > 128 )
temphigh = ((temphigh % 128 ) - 128)*1000;
else
temphigh *= 1000;
//get fraction part and populate temp low with info (ugly)
templow =(((templow & 4 ) >> 2) * 500 ) +
(((templow & 2 ) >> 1) * 250 ) +
((templow & 1 ) * 125);
return (temphigh+templow);
}
static struct emc1023_data *emc1023_update_device_reg16(
struct i2c_client *client, struct emc1023_data *data)
{
int i;
for (i=0; i < 3; i++) {
data->temp_high[i] = i2c_smbus_read_byte_data(client,
EMC1023_LF_TEMP_HIGH_BYTE[i]);
data->temp_low[i] = i2c_smbus_read_byte_data(client,
EMC1023_LF_TEMP_LOW_BYTE[i]);
}
return data;
}
static struct emc1023_data *emc1023_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct emc1023_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
data->status = i2c_smbus_read_byte_data(client, EMC1023_STATUS);
data->config = i2c_smbus_read_byte_data(client, EMC1023_CONFIG_READ);
emc1023_update_device_reg16(client, data);
data->last_updated = jiffies;
data->valid = 1;
}
mutex_unlock(&data->update_lock);
return data;
}
static ssize_t show_temp_value(struct device *dev,
struct device_attribute *devattr, char *buf)
{
int index = to_sensor_dev_attr(devattr)->index;
struct emc1023_data *data = emc1023_update_device(dev);
return sprintf(buf, "%d\n",
emc1023_register_to_temp(data->temp_high[index], data->temp_low[index]));
}
/*static ssize_t show_status(struct device *dev,
struct device_attribute *devattr, char *buf)
{
//int mask = to_sensor_dev_attr(devattr)->index;
struct emc1023_data *data = emc1023_update_device(dev);
if ( (data->status >> 7) == 1 )
return sprintf(buf, "ready\n");
else
return sprintf(buf, "not ready\n");
}*/
static struct sensor_device_attribute emc1023_attr[] = {
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0),
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1),
SENSOR_ATTR(temp3_input, S_IRUGO, show_temp_value, NULL, 2),
};
/*
* Begin non sysfs callback code (aka Real code)
*/
static void emc1023_init_client(struct i2c_client *client)
{
int config;
/* Start conversions (disable shutdown if necessary) */
config = i2c_smbus_read_byte_data(client, EMC1023_CONFIG_READ);
if (config < 0) {
dev_warn(&client->dev, "Initialization failed!\n");
return;
}
}
static int emc1023_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
//int i=0;
struct i2c_adapter *adapter = client->adapter;
u8 reg;
enum chips kind;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
/* Detect and identify the chip */
reg = i2c_smbus_read_byte_data(client, EMC1023_MANUFACTURER_ID_REG);
if (reg != EMC1023_MANUFACTURER_ID)
return -ENODEV;
reg = i2c_smbus_read_byte_data(client, EMC1023_DEVICE_ID_REG);
//tried to cycle through array to match id.
/*for(i=0;i<4;i++)
if( reg == EMC1023_DEVICE_ID[i] )
{
kind = i;
break;
}*/
switch (reg) {
case EMC1023_DEVICE_ID_1:
kind = emc1023_1;
break;
case EMC1023_DEVICE_ID_2:
kind = emc1023_2;
break;
case EMC1023_DEVICE_ID_3:
kind = emc1023_3;
break;
case EMC1023_DEVICE_ID_4:
kind = emc1023_4;
break;
default:
return -ENODEV;
}
strlcpy(info->type, emc1023_id[kind].name, I2C_NAME_SIZE);
return 0;
}
static int emc1023_remove(struct i2c_client *client)
{
struct emc1023_data *data = i2c_get_clientdata(client);
int i;
if (data->hwmon_dev)
hwmon_device_unregister(data->hwmon_dev);
for (i = 0; i < ARRAY_SIZE(emc1023_attr); i++)
device_remove_file(&client->dev, &emc1023_attr[i].dev_attr);
kfree(data);
return 0;
}
static int emc1023_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int i, err = 0;
struct emc1023_data *data;
const char *names[] = { "EMC1023_1", "EMC1023_2", "EMC1023_3","EMC1023_4" };
data = kzalloc(sizeof(struct emc1023_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
data->kind = id->driver_data;
/* Initialize the EMC1023 chip */
emc1023_init_client(client);
/* Register sysfs hooks */
for (i = 0; i < ARRAY_SIZE(emc1023_attr); i++) {
err = device_create_file(&client->dev,
&emc1023_attr[i].dev_attr);
if (err)
goto exit_remove;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
data->hwmon_dev = NULL;
goto exit_remove;
}
dev_info(&client->dev, "Detected emc1023 %s chip\n", names[data->kind]);
return 0;
exit_remove:
emc1023_remove(client); /* will also free data for us */
return err;
}
static struct i2c_driver emc1023_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "emc1023",
},
.probe = emc1023_probe,
.remove = emc1023_remove,
.id_table = emc1023_id,
.detect = emc1023_detect,
.address_list = normal_i2c,
};
static int __init emc1023_init(void)
{
return i2c_add_driver(&emc1023_driver);
}
static void __exit emc1023_exit(void)
{
i2c_del_driver(&emc1023_driver);
}
MODULE_AUTHOR("Anish K Patel <anishp(at)win-ent!com!>");
MODULE_DESCRIPTION("SMSC emc1023 temperature sensor driver");
MODULE_LICENSE("GPL");
module_init(emc1023_init);
module_exit(emc1023_exit);
[-- Attachment #3: emc1023.patch --]
[-- Type: text/plain, Size: 1427 bytes --]
diff -uprN -X linux-2.6.36.2/Documentation/dontdiff linux-2.6.36.2/drivers/hwmon/Kconfig linux-new/drivers/hwmon/Kconfig
--- linux-2.6.36.2/drivers/hwmon/Kconfig 2010-10-20 16:30:22.000000000 -0400
+++ linux-new/drivers/hwmon/Kconfig 2011-01-17 12:21:12.292000226 -0500
@@ -310,6 +310,16 @@ config SENSORS_DS1621
This driver can also be built as a module. If so, the module
will be called ds1621.
+config SENSORS_EMC1023
+ tristate "SMSC emc1023 Thermal Sensor"
+ depends on I2C
+ help
+ If you say yes here you get support for the SMC1023 Thermal Sensor
+ monitoring chip
+
+ This driver can also be built as a module. If so, the module
+ will be called emc1023
+
config SENSORS_I5K_AMB
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
depends on PCI && EXPERIMENTAL
diff -uprN -X linux-2.6.36.2/Documentation/dontdiff linux-2.6.36.2/drivers/hwmon/Makefile linux-new/drivers/hwmon/Makefile
--- linux-2.6.36.2/drivers/hwmon/Makefile 2010-10-20 16:30:22.000000000 -0400
+++ linux-new/drivers/hwmon/Makefile 2011-01-17 11:44:16.799999396 -0500
@@ -107,6 +107,7 @@ obj-$(CONFIG_SENSORS_W83627EHF) += w8362
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
+obj-$(CONFIG_SENSORS_EMC1023) += emc1023.o
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
[-- Attachment #4: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
next reply other threads:[~2011-01-17 19:18 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-01-17 19:18 Anish Patel [this message]
2011-01-17 20:39 ` [lm-sensors] driver for emc1023 Guenter Roeck
2011-01-17 20:50 ` Jean Delvare
2011-01-17 21:13 ` Guenter Roeck
2011-01-17 22:13 ` Guenter Roeck
2011-01-17 22:23 ` Anish Patel
2011-01-17 22:39 ` Guenter Roeck
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=4D34960C.8070303@gmail.com \
--to=anish.mailing.list@gmail.com \
--cc=lm-sensors@vger.kernel.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.