aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/algos/i2c-algo-pca.c
diff options
context:
space:
mode:
authorWolfram Sang <w.sang@pengutronix.de>2008-04-22 16:16:46 -0400
committerJean Delvare <khali@hyperion.delvare>2008-04-22 16:16:46 -0400
commitc01b0831057381c7f6e0bfb3634bac8c5f7fb256 (patch)
tree43fb4c2d626df0c32f3196c81062592ab60ccd12 /drivers/i2c/algos/i2c-algo-pca.c
parent3d4382913f9a86f0d9ff47740feb427415fe7234 (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/i2c-algo-pca.c')
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c88
1 files changed, 44 insertions, 44 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
37static int i2c_debug; 34static 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 */
174static 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
180static int pca_xfer(struct i2c_adapter *i2c_adap, 168static 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
340static int pca_init(struct i2c_algo_pca_data *adap) 328static const struct i2c_algorithm pca_algo = {
329 .master_xfer = pca_xfer,
330 .functionality = pca_func,
331};
332
333static 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
358static 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 */
366int i2c_pca_add_bus(struct i2c_adapter *adap) 361int 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}
371EXPORT_SYMBOL(i2c_pca_add_bus);
376 372
377 if ((rval = pca_init(pca_adap))) 373int 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}
384EXPORT_SYMBOL(i2c_pca_add_bus); 383EXPORT_SYMBOL(i2c_pca_add_numbered_bus);
385 384
386MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>"); 385MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, "
386 "Wolfram Sang <w.sang@pengutronix.de>");
387MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm"); 387MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm");
388MODULE_LICENSE("GPL"); 388MODULE_LICENSE("GPL");
389 389