All of lore.kernel.org
 help / color / mirror / Atom feed
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

             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.