Skip to content

Commit

Permalink
Merge branch 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare…
Browse files Browse the repository at this point in the history
…-2.6

* 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6:
  i2c: Fix platform driver hotplug/coldplug
  i2c: New driver for the SuperH Mobile I2C bus controller
  i2c/scx200_acb: Don't use 0 as NULL pointer
  i2c-bfin-twi: Fix mismatch in add timer and delete timer
  i2c-bfin-twi: Just let i2c-bfin-twi driver depends on BLACKFIN
  i2c-bfin-twi: Use simpler comment headers and strip out information that is maintained in the scm's log
  i2c-bfin-twi: Cleanup driver descriptions, versions and some module useful information
  i2c-bfin-twi: Add missing pin mux operation
  i2c-bfin-twi: Add platform_resource interface to support multi-port TWI controllers
  i2c-bfin-twi: Add repeat start feature to avoid break of a bundle of i2c master xfer operation
  i2c: Remove trailing whitespaces in busses/Kconfig
  i2c: Replace remaining __FUNCTION__ occurrences
  i2c: Renesas SH7760 I2C master driver
  i2c-dev: Split i2cdev_ioctl
  i2c-ibm_iic: Support building as an of_platform driver
  i2c-ibm_iic: Change the log levels
  i2c: Add platform driver on top of the new pca-algorithm
  i2c-algo-pca: Extend for future drivers
  i2c-algo-pca: Remove trailing whitespaces and unnecessary UTF
  i2c: Remove the algorithm drivers from the config menu
  • Loading branch information
Linus Torvalds committed Apr 22, 2008
2 parents 7348672 + add8eda commit b24a314
Show file tree
Hide file tree
Showing 34 changed files with 2,313 additions and 575 deletions.
39 changes: 5 additions & 34 deletions drivers/i2c/algos/Kconfig
Original file line number Diff line number Diff line change
@@ -1,45 +1,16 @@
#
# Character device configuration
# I2C algorithm drivers configuration
#

menu "I2C Algorithms"

config I2C_ALGOBIT
tristate "I2C bit-banging interfaces"
help
This allows you to use a range of I2C adapters called bit-banging
adapters. Say Y if you own an I2C adapter belonging to this class
and then say Y to the specific driver for you adapter below.

This support is also available as a module. If so, the module
will be called i2c-algo-bit.
tristate

config I2C_ALGOPCF
tristate "I2C PCF 8584 interfaces"
help
This allows you to use a range of I2C adapters called PCF adapters.
Say Y if you own an I2C adapter belonging to this class and then say
Y to the specific driver for you adapter below.

This support is also available as a module. If so, the module
will be called i2c-algo-pcf.
tristate

config I2C_ALGOPCA
tristate "I2C PCA 9564 interfaces"
help
This allows you to use a range of I2C adapters called PCA adapters.
Say Y if you own an I2C adapter belonging to this class and then say
Y to the specific driver for you adapter below.

This support is also available as a module. If so, the module
will be called i2c-algo-pca.
tristate

config I2C_ALGO_SGI
tristate "I2C SGI interfaces"
tristate
depends on SGI_IP22 || SGI_IP32 || X86_VISWS
help
Supports the SGI interfaces like the ones found on SGI Indy VINO
or SGI O2 MACE.

endmenu

126 changes: 63 additions & 63 deletions drivers/i2c/algos/i2c-algo-pca.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters
* 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
Expand All @@ -21,30 +22,26 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-pca.h>
#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)
#define DEB3(fmt, args...) do { if (i2c_debug>=3) printk(fmt, ## args); } while(0)

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.
Expand Down Expand Up @@ -99,7 +96,7 @@ static void pca_stop(struct i2c_algo_pca_data *adap)
*
* returns after the address has been sent
*/
static void pca_address(struct i2c_algo_pca_data *adap,
static void pca_address(struct i2c_algo_pca_data *adap,
struct i2c_msg *msg)
{
int sta = pca_get_con(adap);
Expand All @@ -108,9 +105,9 @@ static void pca_address(struct i2c_algo_pca_data *adap,
addr = ( (0x7f & msg->addr) << 1 );
if (msg->flags & I2C_M_RD )
addr |= 1;
DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n",
DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n",
msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr);

pca_outw(adap, I2C_PCA_DAT, addr);

sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
Expand All @@ -124,7 +121,7 @@ static void pca_address(struct i2c_algo_pca_data *adap,
*
* Returns after the byte has been transmitted
*/
static void pca_tx_byte(struct i2c_algo_pca_data *adap,
static void pca_tx_byte(struct i2c_algo_pca_data *adap,
__u8 b)
{
int sta = pca_get_con(adap);
Expand All @@ -142,19 +139,19 @@ static void pca_tx_byte(struct i2c_algo_pca_data *adap,
*
* returns immediately.
*/
static void pca_rx_byte(struct i2c_algo_pca_data *adap,
static void pca_rx_byte(struct i2c_algo_pca_data *adap,
__u8 *b, int ack)
{
*b = pca_inw(adap, I2C_PCA_DAT);
DEB2("=== READ %#04x %s\n", *b, ack ? "ACK" : "NACK");
}

/*
/*
* Setup ACK or NACK for next received byte and wait for it to arrive.
*
* Returns after next byte has arrived.
*/
static void pca_rx_ack(struct i2c_algo_pca_data *adap,
static void pca_rx_ack(struct i2c_algo_pca_data *adap,
int ack)
{
int sta = pca_get_con(adap);
Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -203,14 +191,14 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
for (curmsg = 0; curmsg < num; curmsg++) {
int addr, i;
msg = &msgs[curmsg];

addr = (0x7f & msg->addr) ;

if (msg->flags & I2C_M_RD )
printk(KERN_INFO " [%02d] RD %d bytes from %#02x [%#02x, ...]\n",
printk(KERN_INFO " [%02d] RD %d bytes from %#02x [%#02x, ...]\n",
curmsg, msg->len, addr, (addr<<1) | 1);
else {
printk(KERN_INFO " [%02d] WR %d bytes to %#02x [%#02x%s",
printk(KERN_INFO " [%02d] WR %d bytes to %#02x [%#02x%s",
curmsg, msg->len, addr, addr<<1,
msg->len == 0 ? "" : ", ");
for(i=0; i < msg->len; i++)
Expand All @@ -237,7 +225,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
case 0x10: /* A repeated start condition has been transmitted */
pca_address(adap, msg);
break;

case 0x18: /* SLA+W has been transmitted; ACK has been received */
case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */
if (numbytes < msg->len) {
Expand Down Expand Up @@ -287,7 +275,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */
DEB2("Arbitration lost\n");
goto out;

case 0x58: /* Data byte has been received; NOT ACK has been returned */
if ( numbytes == msg->len - 1 ) {
pca_rx_byte(adap, &msg->buf[numbytes], 0);
Expand Down Expand Up @@ -317,16 +305,16 @@ 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;
}

}

ret = curmsg;
out:
DEB1(KERN_CRIT "}}} transfered %d/%d messages. "
"status is %#04x. control is %#04x\n",
"status is %#04x. control is %#04x\n",
curmsg, num, pca_status(adap),
pca_get_con(adap));
return ret;
Expand All @@ -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);
udelay(500); /* 500 µs for oscilator to stabilise */
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
/*
* 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 <icampbell@arcom.com>");
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, "
"Wolfram Sang <w.sang@pengutronix.de>");
MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm");
MODULE_LICENSE("GPL");

Expand Down
26 changes: 0 additions & 26 deletions drivers/i2c/algos/i2c-algo-pca.h

This file was deleted.

Loading

0 comments on commit b24a314

Please sign in to comment.