From c01b0831057381c7f6e0bfb3634bac8c5f7fb256 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 22 Apr 2008 22:16:46 +0200 Subject: 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 Signed-off-by: Jean Delvare --- drivers/i2c/algos/i2c-algo-pca.c | 88 ++++++++++++++++++++-------------------- drivers/i2c/algos/i2c-algo-pca.h | 26 ------------ 2 files changed, 44 insertions(+), 70 deletions(-) delete mode 100644 drivers/i2c/algos/i2c-algo-pca.h (limited to 'drivers/i2c/algos') 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 @@ /* * i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters * Copyright (C) 2004 Arcom Control Systems + * Copyright (C) 2008 Pengutronix * * 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 @@ -21,14 +22,10 @@ #include #include #include -#include #include #include #include #include -#include "i2c-algo-pca.h" - -#define DRIVER "i2c-algo-pca" #define DEB1(fmt, args...) do { if (i2c_debug>=1) printk(fmt, ## args); } while(0) #define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0) @@ -36,15 +33,15 @@ static int i2c_debug; -#define pca_outw(adap, reg, val) adap->write_byte(adap, reg, val) -#define pca_inw(adap, reg) adap->read_byte(adap, reg) +#define pca_outw(adap, reg, val) adap->write_byte(adap->data, reg, val) +#define pca_inw(adap, reg) adap->read_byte(adap->data, reg) #define pca_status(adap) pca_inw(adap, I2C_PCA_STA) -#define pca_clock(adap) adap->get_clock(adap) -#define pca_own(adap) adap->get_own(adap) +#define pca_clock(adap) adap->i2c_clock #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) -#define pca_wait(adap) adap->wait_for_interrupt(adap) +#define pca_wait(adap) adap->wait_for_completion(adap->data) +#define pca_reset(adap) adap->reset_chip(adap->data) /* * Generate a start condition on the i2c bus. @@ -168,15 +165,6 @@ static void pca_rx_ack(struct i2c_algo_pca_data *adap, pca_wait(adap); } -/* - * Reset the i2c bus / SIO - */ -static void pca_reset(struct i2c_algo_pca_data *adap) -{ - /* apparently only an external reset will do it. not a lot can be done */ - printk(KERN_ERR DRIVER ": Haven't figured out how to do a reset yet\n"); -} - static int pca_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) @@ -187,7 +175,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, int numbytes = 0; int state; int ret; - int timeout = 100; + int timeout = i2c_adap->timeout; while ((state = pca_status(adap)) != 0xf8 && timeout--) { msleep(10); @@ -317,7 +305,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, pca_reset(adap); goto out; default: - printk(KERN_ERR DRIVER ": unhandled SIO state 0x%02x\n", state); + dev_err(&i2c_adap->dev, "unhandled SIO state 0x%02x\n", state); break; } @@ -337,53 +325,65 @@ static u32 pca_func(struct i2c_adapter *adap) return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } -static int pca_init(struct i2c_algo_pca_data *adap) +static const struct i2c_algorithm pca_algo = { + .master_xfer = pca_xfer, + .functionality = pca_func, +}; + +static int pca_init(struct i2c_adapter *adap) { static int freqs[] = {330,288,217,146,88,59,44,36}; - int own, clock; + int clock; + struct i2c_algo_pca_data *pca_data = adap->algo_data; + + if (pca_data->i2c_clock > 7) { + printk(KERN_WARNING "%s: Invalid I2C clock speed selected. Trying default.\n", + adap->name); + pca_data->i2c_clock = I2C_PCA_CON_59kHz; + } + + adap->algo = &pca_algo; - own = pca_own(adap); - clock = pca_clock(adap); - DEB1(KERN_INFO DRIVER ": own address is %#04x\n", own); - DEB1(KERN_INFO DRIVER ": clock freqeuncy is %dkHz\n", freqs[clock]); + pca_reset(pca_data); - pca_outw(adap, I2C_PCA_ADR, own << 1); + clock = pca_clock(pca_data); + DEB1(KERN_INFO "%s: Clock frequency is %dkHz\n", adap->name, freqs[clock]); - pca_set_con(adap, I2C_PCA_CON_ENSIO | clock); + pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock); udelay(500); /* 500 us for oscilator to stabilise */ return 0; } -static const struct i2c_algorithm pca_algo = { - .master_xfer = pca_xfer, - .functionality = pca_func, -}; - /* * registering functions to load algorithms at runtime */ int i2c_pca_add_bus(struct i2c_adapter *adap) { - struct i2c_algo_pca_data *pca_adap = adap->algo_data; int rval; - /* register new adapter to i2c module... */ - adap->algo = &pca_algo; + rval = pca_init(adap); + if (rval) + return rval; - adap->timeout = 100; /* default values, should */ - adap->retries = 3; /* be replaced by defines */ + return i2c_add_adapter(adap); +} +EXPORT_SYMBOL(i2c_pca_add_bus); - if ((rval = pca_init(pca_adap))) - return rval; +int i2c_pca_add_numbered_bus(struct i2c_adapter *adap) +{ + int rval; - rval = i2c_add_adapter(adap); + rval = pca_init(adap); + if (rval) + return rval; - return rval; + return i2c_add_numbered_adapter(adap); } -EXPORT_SYMBOL(i2c_pca_add_bus); +EXPORT_SYMBOL(i2c_pca_add_numbered_bus); -MODULE_AUTHOR("Ian Campbell "); +MODULE_AUTHOR("Ian Campbell , " + "Wolfram Sang "); MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm"); MODULE_LICENSE("GPL"); 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 @@ -#ifndef I2C_PCA9564_H -#define I2C_PCA9564_H 1 - -#define I2C_PCA_STA 0x00 /* STATUS Read Only */ -#define I2C_PCA_TO 0x00 /* TIMEOUT Write Only */ -#define I2C_PCA_DAT 0x01 /* DATA Read/Write */ -#define I2C_PCA_ADR 0x02 /* OWN ADR Read/Write */ -#define I2C_PCA_CON 0x03 /* CONTROL Read/Write */ - -#define I2C_PCA_CON_AA 0x80 /* Assert Acknowledge */ -#define I2C_PCA_CON_ENSIO 0x40 /* Enable */ -#define I2C_PCA_CON_STA 0x20 /* Start */ -#define I2C_PCA_CON_STO 0x10 /* Stop */ -#define I2C_PCA_CON_SI 0x08 /* Serial Interrupt */ -#define I2C_PCA_CON_CR 0x07 /* Clock Rate (MASK) */ - -#define I2C_PCA_CON_330kHz 0x00 -#define I2C_PCA_CON_288kHz 0x01 -#define I2C_PCA_CON_217kHz 0x02 -#define I2C_PCA_CON_146kHz 0x03 -#define I2C_PCA_CON_88kHz 0x04 -#define I2C_PCA_CON_59kHz 0x05 -#define I2C_PCA_CON_44kHz 0x06 -#define I2C_PCA_CON_36kHz 0x07 - -#endif /* I2C_PCA9564_H */ -- cgit v1.2.2