Welcome to Linux Forums!

With a comprehensive Linux Forum, information on various types of Linux software and many Linux Reviews articles, we have all the knowledge you need a click away, or accessible via our knowledgeable members.

Linux Forum ArticlesLinux ForumsLinux Forum DownloadsLinux Hosts
Home|Register|FAQ|Member List|Calendar|Unanswered Posts|Forum Rules|Today's Posts|Advanced Search|
SEARCH FOR IN
Go Back   Linux Forums > GNU Linux Zone > Linux Programming & Scripting
Reload this Page I2C Linux Device Driver: writing device driver for 2 devices in a single driver
Linux Forums
Linux Forums
Welcome To The Linux Forums!
Welcome to Linux Forums. We pride ourselves in being one of the largest Linux communities on the web, we encourage you to REGISTER on our forums and participate in the community. There are over 150,000 members ready to answer your questions. JOINING US today will allow you to make new posts, get support, send messages to other members and submit downloads to our downloads directory and many other great features!

Linux Programming & Scripting C, Perl, PHP, Bash Scripts, anything programming or script related post in here!

Reply
 
Thread Tools Display Modes
Old 05-14-2008   #1 (permalink)
weiliang10
Just Joined!
 
Join Date: May 2008
Posts: 2
Question I2C Linux Device Driver: writing device driver for 2 devices in a single driver

I have a problem writing an I2C device driver and would greatly appreciate if someone could provide some enlightenment.

Here's a lowdown on the problem:

I have managed to write a device driver for a motion sensor that is using the I2C communication protocol to interface with a tablet PC running in Linux kernel 2.6.18. I am integrating a click button to this motion sensor using a Silabs MCU that will interface to the tablet pc using I2C as well but running on a different address (0x34) from the motion sensor.

My driver structure is very similar to the guide provided by Gregg Koah-Hartman in the Linux Journal website: I2C Drivers, Part II

ftp link for the driver file frm the linux journal website: ftp://ftp.ssc.com/pub/lj/listings/issue118/7252.tgz

The i2c driver code from the above ftp is as follows:
Code:
/*
 /*
 * Tiny I2C Chip Driver
 *
 * Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.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.
 *
 * This driver shows how to create a minimal I2C bus and algorithm driver.
 *
 * Compile this driver with:

	echo "obj-m := tiny_i2c_chip.o" > Makefile
	make -C <path/to/kernel/src> SUBDIRS=$PWD modules
 */

#define DEBUG 1

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>

/* Addresses to scan */
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
static unsigned short normal_i2c_range[] = { 0x00, 0xff, I2C_CLIENT_END };
static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };

/* Insmod parameters */
SENSORS_INSMOD_1(chip);

/* Each client has this additional data */
struct chip_data {
	struct semaphore update_lock;
	char valid;			/* !=0 if following fields are valid */
	unsigned long last_updated;	/* In jiffies */
	u16 temp_input;			/* Register values */
	u16 temp_max;
	u16 temp_hyst;
};

#define REG_TEMP_HYST	0x01
#define REG_TEMP_OS	0x02

static int chip_attach_adapter(struct i2c_adapter *adapter);
static int chip_detect(struct i2c_adapter *adapter, int address, int kind);
static int chip_detach_client(struct i2c_client *client);

/* This is the driver that will be inserted */
static struct i2c_driver chip_driver = {
	.owner		= THIS_MODULE,
	.name		= "tiny_chip",
	.flags		= I2C_DF_NOTIFY,
	.attach_adapter	= chip_attach_adapter,
	.detach_client	= chip_detach_client,
};


static void chip_update_client(struct i2c_client *client)
{
	struct chip_data *data = i2c_get_clientdata(client);

	down(&data->update_lock);
	dev_dbg(&client->dev, "%s\n", __FUNCTION__);
	++data->temp_input;
	++data->temp_max;
	++data->temp_hyst;
	data->last_updated = jiffies;
	data->valid = 1;
	up(&data->update_lock);
}

#define show(value)	\
static ssize_t show_##value(struct device *dev, char *buf)	\
{								\
	struct i2c_client *client = to_i2c_client(dev);		\
	struct chip_data *data = i2c_get_clientdata(client);	\
								\
	chip_update_client(client);				\
	return sprintf(buf, "%d\n", data->value);		\
}
show(temp_max);
show(temp_hyst);
show(temp_input);

#define set(value, reg)	\
static ssize_t set_##value(struct device *dev, const char *buf, size_t count)	\
{								\
	struct i2c_client *client = to_i2c_client(dev);		\
	struct chip_data *data = i2c_get_clientdata(client);	\
	int temp = simple_strtoul(buf, NULL, 10);		\
								\
	down(&data->update_lock);				\
	data->value = temp;					\
	up(&data->update_lock);					\
	return count;						\
}
set(temp_max, REG_TEMP_OS);
set(temp_hyst, REG_TEMP_HYST);

static DEVICE_ATTR(temp_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
static DEVICE_ATTR(temp_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
static DEVICE_ATTR(temp_input, S_IRUGO, show_temp_input, NULL);

static int chip_attach_adapter(struct i2c_adapter *adapter)
{
	return i2c_detect(adapter, &addr_data, chip_detect);
}

/* This function is called by i2c_detect */
static int chip_detect(struct i2c_adapter *adapter, int address, int kind)
{
	struct i2c_client *new_client = NULL;
	struct chip_data *data = NULL;
	int err = 0;

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
		goto error;

	new_client = kmalloc(sizeof(*new_client), GFP_KERNEL);
	if (!new_client) {
		err = -ENOMEM;
		goto error;
	}
	data = kmalloc(sizeof(*data), GFP_KERNEL);
	if (!data) {
		err = -ENOMEM;
		goto error;
	}
			
	memset(new_client, 0x00, sizeof(*new_client));
	memset(data, 0x00, sizeof(*data));

	i2c_set_clientdata(new_client, data);
	new_client->addr = address;
	new_client->adapter = adapter;
	new_client->driver = &chip_driver;
	new_client->flags = 0;

	/* Fill in the remaining client fields */
	strncpy(new_client->name, "tiny_chip", I2C_NAME_SIZE);
	data->valid = 0;
	init_MUTEX(&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_temp_max);
	device_create_file(&new_client->dev, &dev_attr_temp_min);
	device_create_file(&new_client->dev, &dev_attr_temp_input);

	return 0;

error:
	kfree(new_client);
	kfree(data);
	return err;
}

static int chip_detach_client(struct i2c_client *client)
{
	struct chip_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(client);
	kfree(data);
	return 0;
}

static int __init tiny_init(void)
{
	return i2c_add_driver(&chip_driver);
}

static void __exit tiny_exit(void)
{
	i2c_del_driver(&chip_driver);
}


MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");
MODULE_DESCRIPTION("Tiny i2c chip");
MODULE_LICENSE("GPL");

module_init(tiny_init);
module_exit(tiny_exit);

Question: What should i do to enable this driver to simultaneously support 2 devices on the I2C bus- i.e. the MCU and the motion sensor? Should i append another i2C_add_driver function at the function static int__init tiny_init(void) and subsequently reduplicate all functions involved in registering a new driver (e.g. static struct i2c_driver, i2c_detect, etc)?

Kindly advise and thanks in advance.
weiliang10 is offline   Reply With Quote
Old 05-14-2008   #2 (permalink)
wildpossum
Just Joined!
 
wildpossum's Avatar
 
Join Date: Apr 2008
Location: Sydney/Australia
Posts: 74
Send a message via Skype™ to wildpossum
A> I would suggest that you simply modify the udev rules to handle both devices. You don't need too nor should you duplicate code within any device driver.

B> Add a device major number so your driver knows which device type (I guess char type) to handle, and add to your driver a minor number scheme handling as per the "Linux Device Drivers" book. Chapter 13, USB Drivers by Corbet et al; Usualy it is available as a pdf book on some distros or you can find on the web to read at your lesiure. The 3rd edition was in 2005 so I suspect there may be a never edition available. It is a great read!

My understanding of USB handling is (and I quote somewhat from Pg 335):

* USB Code communicates with all USB devices using something called the URB (USB Request Blocks). A described struct found in include/linux/usb.h file. It is used to send/receive data to/from specific end points on a specific USB device(s) in an async manner.
A USB device driver may allocate many URB's for a single endpoint or may reuse a signle URB for amny different endpoints. This is the manner usually employed to talk to device(s) as you indicate you wish too.

There is just too much detail to go into here. Get a copy of the book (pdf) and enjoy the 35 pages on USB device driver alone.

Another book (I don't see ths on the web as aPDF though) is ISBN 9781931448024 "USB Complete" (3rd Edition) by Jan Axelson. An excellent book and probably a bible to keep around ~$40 USD. More of the authors info on USB is aailable at www.lun.com.

Better still, have a look at the /usr/src/linux/Documentation Kernel Doc directory for the latest on USB and of course the best source of information is the source code of device drivers that do the sort of thing your interested in doing yourself.

You can and your encoraged to - copy, modify and play with a derived work (as long as you add in the source code all the required licence information - generally just the usual GPL info) that is the essence of Open Source.

Hope your project works out. Unfortunately I can't add more because it is soooo... long ago when I played with my own derived works on USB.

Cheers. Grahame
__________________
Grahame
AMD Phenom(QuadCore), 8GB, 3ware RAID6 1.8TB, HD3850(512MB) ..etc.
wildpossum is offline   Reply With Quote
Old 05-15-2008   #3 (permalink)
weiliang10
Just Joined!
 
Join Date: May 2008
Posts: 2
Can I assume that the format for multiple device in USB and I2C are similar?

I have the Linux Device Driver book but unfortunately there are no references to I2C. I am looking to get the Essential Linux Device Driver book which hopefully has a topic that addresses this issue. Then again, that might take a while.
weiliang10 is offline   Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off


All times are GMT. The time now is 12:21 AM.

Powered by vBulletin 3.6.8 ©2000 - 2007, content relevant URLs by vBSEO, Property of Core Root.

Content Relevant URLs by vBSEO 3.0.0