Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 91879
b: refs/heads/master
c: c01b083
h: refs/heads/master
i:
  91877: 4bf9088
  91875: 830d325
  91871: 843aa71
v: v3
  • Loading branch information
Wolfram Sang authored and Jean Delvare committed Apr 22, 2008
1 parent 985245f commit 6960711
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 108 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3d4382913f9a86f0d9ff47740feb427415fe7234
refs/heads/master: c01b0831057381c7f6e0bfb3634bac8c5f7fb256
88 changes: 44 additions & 44 deletions trunk/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
* 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 @@ -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 Down Expand Up @@ -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;
}

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);
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 <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 trunk/drivers/i2c/algos/i2c-algo-pca.h

This file was deleted.

51 changes: 19 additions & 32 deletions trunk/drivers/i2c/busses/i2c-pca-isa.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* i2c-pca-isa.c driver for PCA9564 on ISA boards
* 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 @@ -22,48 +23,29 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/wait.h>

#include <linux/isa.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-pca.h>

#include <asm/io.h>
#include <asm/irq.h>

#include "../algos/i2c-algo-pca.h"

#define DRIVER "i2c-pca-isa"
#define IO_SIZE 4

#undef DEBUG_IO
//#define DEBUG_IO

static unsigned long base = 0x330;
static int irq = 10;

/* Data sheet recommends 59kHz for 100kHz operation due to variation
* in the actual clock rate */
static int clock = I2C_PCA_CON_59kHz;

static int own = 0x55;

static wait_queue_head_t pca_wait;

static int pca_isa_getown(struct i2c_algo_pca_data *adap)
{
return (own);
}

static int pca_isa_getclock(struct i2c_algo_pca_data *adap)
{
return (clock);
}

static void
pca_isa_writebyte(struct i2c_algo_pca_data *adap, int reg, int val)
static void pca_isa_writebyte(void *pd, int reg, int val)
{
#ifdef DEBUG_IO
static char *names[] = { "T/O", "DAT", "ADR", "CON" };
Expand All @@ -72,8 +54,7 @@ pca_isa_writebyte(struct i2c_algo_pca_data *adap, int reg, int val)
outb(val, base+reg);
}

static int
pca_isa_readbyte(struct i2c_algo_pca_data *adap, int reg)
static int pca_isa_readbyte(void *pd, int reg)
{
int res = inb(base+reg);
#ifdef DEBUG_IO
Expand All @@ -85,38 +66,45 @@ pca_isa_readbyte(struct i2c_algo_pca_data *adap, int reg)
return res;
}

static int pca_isa_waitforinterrupt(struct i2c_algo_pca_data *adap)
static int pca_isa_waitforcompletion(void *pd)
{
int ret = 0;

if (irq > -1) {
ret = wait_event_interruptible(pca_wait,
pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI);
pca_isa_readbyte(pd, I2C_PCA_CON) & I2C_PCA_CON_SI);
} else {
while ((pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
while ((pca_isa_readbyte(pd, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
udelay(100);
}
return ret;
}

static void pca_isa_resetchip(void *pd)
{
/* apparently only an external reset will do it. not a lot can be done */
printk(KERN_WARNING DRIVER ": Haven't figured out how to do a reset yet\n");
}

static irqreturn_t pca_handler(int this_irq, void *dev_id) {
wake_up_interruptible(&pca_wait);
return IRQ_HANDLED;
}

static struct i2c_algo_pca_data pca_isa_data = {
.get_own = pca_isa_getown,
.get_clock = pca_isa_getclock,
/* .data intentionally left NULL, not needed with ISA */
.write_byte = pca_isa_writebyte,
.read_byte = pca_isa_readbyte,
.wait_for_interrupt = pca_isa_waitforinterrupt,
.wait_for_completion = pca_isa_waitforcompletion,
.reset_chip = pca_isa_resetchip,
};

static struct i2c_adapter pca_isa_ops = {
.owner = THIS_MODULE,
.id = I2C_HW_A_ISA,
.algo_data = &pca_isa_data,
.name = "PCA9564 ISA Adapter",
.timeout = 100,
};

static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
Expand Down Expand Up @@ -144,6 +132,7 @@ static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
}
}

pca_isa_data.i2c_clock = clock;
if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
dev_err(dev, "Failed to add i2c bus\n");
goto out_irq;
Expand Down Expand Up @@ -178,7 +167,7 @@ static struct isa_driver pca_isa_driver = {
.remove = __devexit_p(pca_isa_remove),
.driver = {
.owner = THIS_MODULE,
.name = "i2c-pca-isa",
.name = DRIVER,
}
};

Expand All @@ -204,7 +193,5 @@ MODULE_PARM_DESC(irq, "IRQ");
module_param(clock, int, 0);
MODULE_PARM_DESC(clock, "Clock rate as described in table 1 of PCA9564 datasheet");

module_param(own, int, 0); /* the driver can't do slave mode, so there's no real point in this */

module_init(pca_isa_init);
module_exit(pca_isa_exit);
37 changes: 32 additions & 5 deletions trunk/include/linux/i2c-algo-pca.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,41 @@
#ifndef _LINUX_I2C_ALGO_PCA_H
#define _LINUX_I2C_ALGO_PCA_H

/* Clock speeds for the bus */
#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

/* PCA9564 registers */
#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) */

struct i2c_algo_pca_data {
int (*get_own) (struct i2c_algo_pca_data *adap); /* Obtain own address */
int (*get_clock) (struct i2c_algo_pca_data *adap);
void (*write_byte) (struct i2c_algo_pca_data *adap, int reg, int val);
int (*read_byte) (struct i2c_algo_pca_data *adap, int reg);
int (*wait_for_interrupt) (struct i2c_algo_pca_data *adap);
void *data; /* private low level data */
void (*write_byte) (void *data, int reg, int val);
int (*read_byte) (void *data, int reg);
int (*wait_for_completion) (void *data);
void (*reset_chip) (void *data);
/* i2c_clock values are defined in linux/i2c-algo-pca.h */
unsigned int i2c_clock;
};

int i2c_pca_add_bus(struct i2c_adapter *);
int i2c_pca_add_numbered_bus(struct i2c_adapter *);

#endif /* _LINUX_I2C_ALGO_PCA_H */

0 comments on commit 6960711

Please sign in to comment.