diff options
| author | Wolfram Sang <w.sang@pengutronix.de> | 2008-04-22 16:16:46 -0400 |
|---|---|---|
| committer | Jean Delvare <khali@hyperion.delvare> | 2008-04-22 16:16:46 -0400 |
| commit | c01b0831057381c7f6e0bfb3634bac8c5f7fb256 (patch) | |
| tree | 43fb4c2d626df0c32f3196c81062592ab60ccd12 /drivers/i2c/algos | |
| parent | 3d4382913f9a86f0d9ff47740feb427415fe7234 (diff) | |
i2c-algo-pca: Extend for future drivers
The separation between algorithm and adapter was unsharp at places. This was
partly hidden by the fact, that the ISA-driver allowed just one instance and
had all private data in static variables. This patch makes neccessary
preparations to add a platform driver on top of the algorithm, while still
supporting ISA. Note: Due to lack of hardware, the ISA-driver could not be
tested except that it builds.
Concerning the core struct i2c_algo_pca_data:
- A private data field was added, all hardware dependant data may go here.
Similar to other algorithms, now a pointer to this data is passed to the
adapter's functions. In order to make as less changes as possible to the
ISA-driver, it leaves the private data empty and still only uses its static
variables.
- A "reset_chip" function pointer was added; such a functionality must come
from the adapter, not the algorithm.
- use a variable "i2c_clock" instead of a function pointer "get_clock",
allowing for write access to a default in case a wrong value was supplied.
In the algorithm-file:
- move "i2c-pca-algo.h" into "linux/i2c-algo-pca.h"
- now using per_instance timeout values (i2c_adap->timeout)
- error messages specify the device, not only the driver name
- restructure initialization to easily support "i2c_add_numbered_adapter"
- drop "retries" and "own" (i2c address) as they were unused
(The state-machine for I2C-communication was not touched.)
In the ISA-driver:
- adapt to new algorithm
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c/algos')
| -rw-r--r-- | drivers/i2c/algos/i2c-algo-pca.c | 88 | ||||
| -rw-r--r-- | drivers/i2c/algos/i2c-algo-pca.h | 26 |
2 files changed, 44 insertions, 70 deletions
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index ebec91d71e1e..e954a20b97a6 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters | 2 | * i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters |
| 3 | * Copyright (C) 2004 Arcom Control Systems | 3 | * Copyright (C) 2004 Arcom Control Systems |
| 4 | * Copyright (C) 2008 Pengutronix | ||
| 4 | * | 5 | * |
| 5 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
| @@ -21,14 +22,10 @@ | |||
| 21 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 22 | #include <linux/moduleparam.h> | 23 | #include <linux/moduleparam.h> |
| 23 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
| 24 | #include <linux/slab.h> | ||
| 25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
| 26 | #include <linux/errno.h> | 26 | #include <linux/errno.h> |
| 27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
| 28 | #include <linux/i2c-algo-pca.h> | 28 | #include <linux/i2c-algo-pca.h> |
| 29 | #include "i2c-algo-pca.h" | ||
| 30 | |||
| 31 | #define DRIVER "i2c-algo-pca" | ||
| 32 | 29 | ||
| 33 | #define DEB1(fmt, args...) do { if (i2c_debug>=1) printk(fmt, ## args); } while(0) | 30 | #define DEB1(fmt, args...) do { if (i2c_debug>=1) printk(fmt, ## args); } while(0) |
| 34 | #define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0) | 31 | #define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0) |
| @@ -36,15 +33,15 @@ | |||
| 36 | 33 | ||
| 37 | static int i2c_debug; | 34 | static int i2c_debug; |
| 38 | 35 | ||
| 39 | #define pca_outw(adap, reg, val) adap->write_byte(adap, reg, val) | 36 | #define pca_outw(adap, reg, val) adap->write_byte(adap->data, reg, val) |
| 40 | #define pca_inw(adap, reg) adap->read_byte(adap, reg) | 37 | #define pca_inw(adap, reg) adap->read_byte(adap->data, reg) |
| 41 | 38 | ||
| 42 | #define pca_status(adap) pca_inw(adap, I2C_PCA_STA) | 39 | #define pca_status(adap) pca_inw(adap, I2C_PCA_STA) |
| 43 | #define pca_clock(adap) adap->get_clock(adap) | 40 | #define pca_clock(adap) adap->i2c_clock |
| 44 | #define pca_own(adap) adap->get_own(adap) | ||
| 45 | #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) | 41 | #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) |
| 46 | #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) | 42 | #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) |
| 47 | #define pca_wait(adap) adap->wait_for_interrupt(adap) | 43 | #define pca_wait(adap) adap->wait_for_completion(adap->data) |
| 44 | #define pca_reset(adap) adap->reset_chip(adap->data) | ||
| 48 | 45 | ||
| 49 | /* | 46 | /* |
| 50 | * Generate a start condition on the i2c bus. | 47 | * Generate a start condition on the i2c bus. |
| @@ -168,15 +165,6 @@ static void pca_rx_ack(struct i2c_algo_pca_data *adap, | |||
| 168 | pca_wait(adap); | 165 | pca_wait(adap); |
| 169 | } | 166 | } |
| 170 | 167 | ||
| 171 | /* | ||
| 172 | * Reset the i2c bus / SIO | ||
| 173 | */ | ||
| 174 | static void pca_reset(struct i2c_algo_pca_data *adap) | ||
| 175 | { | ||
| 176 | /* apparently only an external reset will do it. not a lot can be done */ | ||
| 177 | printk(KERN_ERR DRIVER ": Haven't figured out how to do a reset yet\n"); | ||
| 178 | } | ||
| 179 | |||
| 180 | static int pca_xfer(struct i2c_adapter *i2c_adap, | 168 | static int pca_xfer(struct i2c_adapter *i2c_adap, |
| 181 | struct i2c_msg *msgs, | 169 | struct i2c_msg *msgs, |
| 182 | int num) | 170 | int num) |
| @@ -187,7 +175,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, | |||
| 187 | int numbytes = 0; | 175 | int numbytes = 0; |
| 188 | int state; | 176 | int state; |
| 189 | int ret; | 177 | int ret; |
| 190 | int timeout = 100; | 178 | int timeout = i2c_adap->timeout; |
| 191 | 179 | ||
| 192 | while ((state = pca_status(adap)) != 0xf8 && timeout--) { | 180 | while ((state = pca_status(adap)) != 0xf8 && timeout--) { |
| 193 | msleep(10); | 181 | msleep(10); |
| @@ -317,7 +305,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, | |||
| 317 | pca_reset(adap); | 305 | pca_reset(adap); |
| 318 | goto out; | 306 | goto out; |
| 319 | default: | 307 | default: |
| 320 | printk(KERN_ERR DRIVER ": unhandled SIO state 0x%02x\n", state); | 308 | dev_err(&i2c_adap->dev, "unhandled SIO state 0x%02x\n", state); |
| 321 | break; | 309 | break; |
| 322 | } | 310 | } |
| 323 | 311 | ||
| @@ -337,53 +325,65 @@ static u32 pca_func(struct i2c_adapter *adap) | |||
| 337 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | 325 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; |
| 338 | } | 326 | } |
| 339 | 327 | ||
| 340 | static int pca_init(struct i2c_algo_pca_data *adap) | 328 | static const struct i2c_algorithm pca_algo = { |
| 329 | .master_xfer = pca_xfer, | ||
| 330 | .functionality = pca_func, | ||
| 331 | }; | ||
| 332 | |||
| 333 | static int pca_init(struct i2c_adapter *adap) | ||
| 341 | { | 334 | { |
| 342 | static int freqs[] = {330,288,217,146,88,59,44,36}; | 335 | static int freqs[] = {330,288,217,146,88,59,44,36}; |
| 343 | int own, clock; | 336 | int clock; |
| 337 | struct i2c_algo_pca_data *pca_data = adap->algo_data; | ||
| 338 | |||
| 339 | if (pca_data->i2c_clock > 7) { | ||
| 340 | printk(KERN_WARNING "%s: Invalid I2C clock speed selected. Trying default.\n", | ||
| 341 | adap->name); | ||
| 342 | pca_data->i2c_clock = I2C_PCA_CON_59kHz; | ||
| 343 | } | ||
| 344 | |||
| 345 | adap->algo = &pca_algo; | ||
| 344 | 346 | ||
| 345 | own = pca_own(adap); | 347 | pca_reset(pca_data); |
| 346 | clock = pca_clock(adap); | ||
| 347 | DEB1(KERN_INFO DRIVER ": own address is %#04x\n", own); | ||
| 348 | DEB1(KERN_INFO DRIVER ": clock freqeuncy is %dkHz\n", freqs[clock]); | ||
| 349 | 348 | ||
| 350 | pca_outw(adap, I2C_PCA_ADR, own << 1); | 349 | clock = pca_clock(pca_data); |
| 350 | DEB1(KERN_INFO "%s: Clock frequency is %dkHz\n", adap->name, freqs[clock]); | ||
| 351 | 351 | ||
| 352 | pca_set_con(adap, I2C_PCA_CON_ENSIO | clock); | 352 | pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock); |
| 353 | udelay(500); /* 500 us for oscilator to stabilise */ | 353 | udelay(500); /* 500 us for oscilator to stabilise */ |
| 354 | 354 | ||
| 355 | return 0; | 355 | return 0; |
| 356 | } | 356 | } |
| 357 | 357 | ||
| 358 | static const struct i2c_algorithm pca_algo = { | ||
| 359 | .master_xfer = pca_xfer, | ||
| 360 | .functionality = pca_func, | ||
| 361 | }; | ||
| 362 | |||
| 363 | /* | 358 | /* |
| 364 | * registering functions to load algorithms at runtime | 359 | * registering functions to load algorithms at runtime |
| 365 | */ | 360 | */ |
| 366 | int i2c_pca_add_bus(struct i2c_adapter *adap) | 361 | int i2c_pca_add_bus(struct i2c_adapter *adap) |
| 367 | { | 362 | { |
| 368 | struct i2c_algo_pca_data *pca_adap = adap->algo_data; | ||
| 369 | int rval; | 363 | int rval; |
| 370 | 364 | ||
| 371 | /* register new adapter to i2c module... */ | 365 | rval = pca_init(adap); |
| 372 | adap->algo = &pca_algo; | 366 | if (rval) |
| 367 | return rval; | ||
| 373 | 368 | ||
| 374 | adap->timeout = 100; /* default values, should */ | 369 | return i2c_add_adapter(adap); |
| 375 | adap->retries = 3; /* be replaced by defines */ | 370 | } |
| 371 | EXPORT_SYMBOL(i2c_pca_add_bus); | ||
| 376 | 372 | ||
| 377 | if ((rval = pca_init(pca_adap))) | 373 | int i2c_pca_add_numbered_bus(struct i2c_adapter *adap) |
| 378 | return rval; | 374 | { |
| 375 | int rval; | ||
| 379 | 376 | ||
| 380 | rval = i2c_add_adapter(adap); | 377 | rval = pca_init(adap); |
| 378 | if (rval) | ||
| 379 | return rval; | ||
| 381 | 380 | ||
| 382 | return rval; | 381 | return i2c_add_numbered_adapter(adap); |
| 383 | } | 382 | } |
| 384 | EXPORT_SYMBOL(i2c_pca_add_bus); | 383 | EXPORT_SYMBOL(i2c_pca_add_numbered_bus); |
| 385 | 384 | ||
| 386 | MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>"); | 385 | MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, " |
| 386 | "Wolfram Sang <w.sang@pengutronix.de>"); | ||
| 387 | MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm"); | 387 | MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm"); |
| 388 | MODULE_LICENSE("GPL"); | 388 | MODULE_LICENSE("GPL"); |
| 389 | 389 | ||
diff --git a/drivers/i2c/algos/i2c-algo-pca.h b/drivers/i2c/algos/i2c-algo-pca.h deleted file mode 100644 index 2fee07e05211..000000000000 --- a/drivers/i2c/algos/i2c-algo-pca.h +++ /dev/null | |||
| @@ -1,26 +0,0 @@ | |||
| 1 | #ifndef I2C_PCA9564_H | ||
| 2 | #define I2C_PCA9564_H 1 | ||
| 3 | |||
| 4 | #define I2C_PCA_STA 0x00 /* STATUS Read Only */ | ||
| 5 | #define I2C_PCA_TO 0x00 /* TIMEOUT Write Only */ | ||
| 6 | #define I2C_PCA_DAT 0x01 /* DATA Read/Write */ | ||
| 7 | #define I2C_PCA_ADR 0x02 /* OWN ADR Read/Write */ | ||
| 8 | #define I2C_PCA_CON 0x03 /* CONTROL Read/Write */ | ||
| 9 | |||
| 10 | #define I2C_PCA_CON_AA 0x80 /* Assert Acknowledge */ | ||
| 11 | #define I2C_PCA_CON_ENSIO 0x40 /* Enable */ | ||
| 12 | #define I2C_PCA_CON_STA 0x20 /* Start */ | ||
| 13 | #define I2C_PCA_CON_STO 0x10 /* Stop */ | ||
| 14 | #define I2C_PCA_CON_SI 0x08 /* Serial Interrupt */ | ||
| 15 | #define I2C_PCA_CON_CR 0x07 /* Clock Rate (MASK) */ | ||
| 16 | |||
| 17 | #define I2C_PCA_CON_330kHz 0x00 | ||
| 18 | #define I2C_PCA_CON_288kHz 0x01 | ||
| 19 | #define I2C_PCA_CON_217kHz 0x02 | ||
| 20 | #define I2C_PCA_CON_146kHz 0x03 | ||
| 21 | #define I2C_PCA_CON_88kHz 0x04 | ||
| 22 | #define I2C_PCA_CON_59kHz 0x05 | ||
| 23 | #define I2C_PCA_CON_44kHz 0x06 | ||
| 24 | #define I2C_PCA_CON_36kHz 0x07 | ||
| 25 | |||
| 26 | #endif /* I2C_PCA9564_H */ | ||
