Add a document describing how i2c clients on Linux 2.6 can be moved from the old to the new driver model. Signed-off-by: Ben Dooks <ben-linux@fluff.org>
		
			
				
	
	
		
			281 lines
		
	
	
	
		
			6.9 KiB
			
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
	
		
			6.9 KiB
			
		
	
	
	
		
			Text
		
	
	
	
	
	
Upgrading I2C Drivers to the new 2.6 Driver Model
 | 
						|
=================================================
 | 
						|
 | 
						|
Ben Dooks <ben-linux@fluff.org>
 | 
						|
 | 
						|
Introduction
 | 
						|
------------
 | 
						|
 | 
						|
This guide outlines how to alter existing Linux 2.6 client drivers from
 | 
						|
the old to the new new binding methods.
 | 
						|
 | 
						|
 | 
						|
Example old-style driver
 | 
						|
------------------------
 | 
						|
 | 
						|
 | 
						|
struct example_state {
 | 
						|
	struct i2c_client	client;
 | 
						|
	....
 | 
						|
};
 | 
						|
 | 
						|
static struct i2c_driver example_driver;
 | 
						|
 | 
						|
static unsigned short ignore[] = { I2C_CLIENT_END };
 | 
						|
static unsigned short normal_addr[] = { OUR_ADDR, I2C_CLIENT_END };
 | 
						|
 | 
						|
I2C_CLIENT_INSMOD;
 | 
						|
 | 
						|
static int example_attach(struct i2c_adapter *adap, int addr, int kind)
 | 
						|
{
 | 
						|
	struct example_state *state;
 | 
						|
	struct device *dev = &adap->dev;  /* to use for dev_ reports */
 | 
						|
	int ret;
 | 
						|
 | 
						|
	state = kzalloc(sizeof(struct example_state), GFP_KERNEL);
 | 
						|
	if (state == NULL) {
 | 
						|
		dev_err(dev, "failed to create our state\n");
 | 
						|
		return -ENOMEM;
 | 
						|
	}
 | 
						|
 | 
						|
	example->client.addr    = addr;
 | 
						|
	example->client.flags   = 0;
 | 
						|
	example->client.adapter = adap;
 | 
						|
 | 
						|
	i2c_set_clientdata(&state->i2c_client, state);
 | 
						|
	strlcpy(client->i2c_client.name, "example", I2C_NAME_SIZE);
 | 
						|
 | 
						|
	ret = i2c_attach_client(&state->i2c_client);
 | 
						|
	if (ret < 0) {
 | 
						|
		dev_err(dev, "failed to attach client\n");
 | 
						|
		kfree(state);
 | 
						|
		return ret;
 | 
						|
	}
 | 
						|
 | 
						|
	dev = &state->i2c_client.dev;
 | 
						|
 | 
						|
	/* rest of the initialisation goes here. */
 | 
						|
 | 
						|
	dev_info(dev, "example client created\n");
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int __devexit example_detach(struct i2c_client *client)
 | 
						|
{
 | 
						|
	struct example_state *state = i2c_get_clientdata(client);
 | 
						|
 | 
						|
	i2c_detach_client(client);
 | 
						|
	kfree(state);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int example_attach_adapter(struct i2c_adapter *adap)
 | 
						|
{
 | 
						|
	return i2c_probe(adap, &addr_data, example_attach);
 | 
						|
}
 | 
						|
 | 
						|
static struct i2c_driver example_driver = {
 | 
						|
 	.driver		= {
 | 
						|
		.owner		= THIS_MODULE,
 | 
						|
		.name		= "example",
 | 
						|
	},
 | 
						|
	.attach_adapter = example_attach_adapter,
 | 
						|
	.detach_client	= __devexit_p(example_detach),
 | 
						|
	.suspend	= example_suspend,
 | 
						|
	.resume		= example_resume,
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
Updating the client
 | 
						|
-------------------
 | 
						|
 | 
						|
The new style binding model will check against a list of supported
 | 
						|
devices and their associated address supplied by the code registering
 | 
						|
the busses. This means that the driver .attach_adapter and
 | 
						|
.detach_adapter methods can be removed, along with the addr_data,
 | 
						|
as follows:
 | 
						|
 | 
						|
- static struct i2c_driver example_driver;
 | 
						|
 | 
						|
- static unsigned short ignore[] = { I2C_CLIENT_END };
 | 
						|
- static unsigned short normal_addr[] = { OUR_ADDR, I2C_CLIENT_END };
 | 
						|
 | 
						|
- I2C_CLIENT_INSMOD;
 | 
						|
 | 
						|
- static int example_attach_adapter(struct i2c_adapter *adap)
 | 
						|
- {
 | 
						|
- 	return i2c_probe(adap, &addr_data, example_attach);
 | 
						|
- }
 | 
						|
 | 
						|
 static struct i2c_driver example_driver = {
 | 
						|
-	.attach_adapter = example_attach_adapter,
 | 
						|
-	.detach_client	= __devexit_p(example_detach),
 | 
						|
 }
 | 
						|
 | 
						|
Add the probe and remove methods to the i2c_driver, as so:
 | 
						|
 | 
						|
 static struct i2c_driver example_driver = {
 | 
						|
+	.probe		= example_probe,
 | 
						|
+	.remove		= __devexit_p(example_remove),
 | 
						|
 }
 | 
						|
 | 
						|
Change the example_attach method to accept the new parameters
 | 
						|
which include the i2c_client that it will be working with:
 | 
						|
 | 
						|
- static int example_attach(struct i2c_adapter *adap, int addr, int kind)
 | 
						|
+ static int example_probe(struct i2c_client *client,
 | 
						|
+			   const struct i2c_device_id *id)
 | 
						|
 | 
						|
Change the name of example_attach to example_probe to align it with the
 | 
						|
i2c_driver entry names. The rest of the probe routine will now need to be
 | 
						|
changed as the i2c_client has already been setup for use.
 | 
						|
 | 
						|
The necessary client fields have already been setup before
 | 
						|
the probe function is called, so the following client setup
 | 
						|
can be removed:
 | 
						|
 | 
						|
-	example->client.addr    = addr;
 | 
						|
-	example->client.flags   = 0;
 | 
						|
-	example->client.adapter = adap;
 | 
						|
-
 | 
						|
-	strlcpy(client->i2c_client.name, "example", I2C_NAME_SIZE);
 | 
						|
 | 
						|
The i2c_set_clientdata is now:
 | 
						|
 | 
						|
-	i2c_set_clientdata(&state->client, state);
 | 
						|
+	i2c_set_clientdata(client, state);
 | 
						|
 | 
						|
The call to i2c_attach_client is no longer needed, if the probe
 | 
						|
routine exits successfully, then the driver will be automatically
 | 
						|
attached by the core. Change the probe routine as so:
 | 
						|
 | 
						|
-	ret = i2c_attach_client(&state->i2c_client);
 | 
						|
-	if (ret < 0) {
 | 
						|
-		dev_err(dev, "failed to attach client\n");
 | 
						|
-		kfree(state);
 | 
						|
-		return ret;
 | 
						|
-	}
 | 
						|
 | 
						|
 | 
						|
Remove the storage of 'struct i2c_client' from the 'struct example_state'
 | 
						|
as we are provided with the i2c_client in our example_probe. Instead we
 | 
						|
store a pointer to it for when it is needed.
 | 
						|
 | 
						|
struct example_state {
 | 
						|
-	struct i2c_client	client;
 | 
						|
+	struct i2c_client	*client;
 | 
						|
 | 
						|
the new i2c client as so:
 | 
						|
 | 
						|
-	struct device *dev = &adap->dev;  /* to use for dev_ reports */
 | 
						|
+ 	struct device *dev = &i2c_client->dev;  /* to use for dev_ reports */
 | 
						|
 | 
						|
And remove the change after our client is attached, as the driver no
 | 
						|
longer needs to register a new client structure with the core:
 | 
						|
 | 
						|
-	dev = &state->i2c_client.dev;
 | 
						|
 | 
						|
In the probe routine, ensure that the new state has the client stored
 | 
						|
in it:
 | 
						|
 | 
						|
static int example_probe(struct i2c_client *i2c_client,
 | 
						|
			 const struct i2c_device_id *id)
 | 
						|
{
 | 
						|
	struct example_state *state;
 | 
						|
 	struct device *dev = &i2c_client->dev;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	state = kzalloc(sizeof(struct example_state), GFP_KERNEL);
 | 
						|
	if (state == NULL) {
 | 
						|
		dev_err(dev, "failed to create our state\n");
 | 
						|
		return -ENOMEM;
 | 
						|
	}
 | 
						|
 | 
						|
+	state->client = i2c_client;
 | 
						|
 | 
						|
Update the detach method, by changing the name to _remove and
 | 
						|
to delete the i2c_detach_client call. It is possible that you
 | 
						|
can also remove the ret variable as it is not not needed for
 | 
						|
any of the core functions.
 | 
						|
 | 
						|
- static int __devexit example_detach(struct i2c_client *client)
 | 
						|
+ static int __devexit example_remove(struct i2c_client *client)
 | 
						|
{
 | 
						|
	struct example_state *state = i2c_get_clientdata(client);
 | 
						|
 | 
						|
-	i2c_detach_client(client);
 | 
						|
 | 
						|
And finally ensure that we have the correct ID table for the i2c-core
 | 
						|
and other utilities:
 | 
						|
 | 
						|
+ struct i2c_device_id example_idtable[] = {
 | 
						|
+       { "example", 0 },
 | 
						|
+       { }
 | 
						|
+};
 | 
						|
+
 | 
						|
+MODULE_DEVICE_TABLE(i2c, example_idtable);
 | 
						|
 | 
						|
static struct i2c_driver example_driver = {
 | 
						|
 	.driver		= {
 | 
						|
		.owner		= THIS_MODULE,
 | 
						|
		.name		= "example",
 | 
						|
	},
 | 
						|
+	.id_table	= example_ids,
 | 
						|
 | 
						|
 | 
						|
Our driver should now look like this:
 | 
						|
 | 
						|
struct example_state {
 | 
						|
	struct i2c_client	*client;
 | 
						|
	....
 | 
						|
};
 | 
						|
 | 
						|
static int example_probe(struct i2c_client *client,
 | 
						|
		     	 const struct i2c_device_id *id)
 | 
						|
{
 | 
						|
	struct example_state *state;
 | 
						|
	struct device *dev = &client->dev;
 | 
						|
 | 
						|
	state = kzalloc(sizeof(struct example_state), GFP_KERNEL);
 | 
						|
	if (state == NULL) {
 | 
						|
		dev_err(dev, "failed to create our state\n");
 | 
						|
		return -ENOMEM;
 | 
						|
	}
 | 
						|
 | 
						|
	state->client = client;
 | 
						|
	i2c_set_clientdata(client, state);
 | 
						|
 | 
						|
	/* rest of the initialisation goes here. */
 | 
						|
 | 
						|
	dev_info(dev, "example client created\n");
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int __devexit example_remove(struct i2c_client *client)
 | 
						|
{
 | 
						|
	struct example_state *state = i2c_get_clientdata(client);
 | 
						|
 | 
						|
	kfree(state);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static struct i2c_device_id example_idtable[] = {
 | 
						|
	{ "example", 0 },
 | 
						|
	{ }
 | 
						|
};
 | 
						|
 | 
						|
MODULE_DEVICE_TABLE(i2c, example_idtable);
 | 
						|
 | 
						|
static struct i2c_driver example_driver = {
 | 
						|
 	.driver		= {
 | 
						|
		.owner		= THIS_MODULE,
 | 
						|
		.name		= "example",
 | 
						|
	},
 | 
						|
	.id_table	= example_idtable,
 | 
						|
	.probe		= example_probe,
 | 
						|
	.remove		= __devexit_p(example_remove),
 | 
						|
	.suspend	= example_suspend,
 | 
						|
	.resume		= example_resume,
 | 
						|
};
 |