Merge branch 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-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
This commit is contained in:
Коммит
b24a31442e
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -21,14 +22,10 @@
|
|||
#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)
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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++)
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 int freqs[] = {330,288,217,146,88,59,44,36};
|
||||
int own, clock;
|
||||
|
||||
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_outw(adap, I2C_PCA_ADR, own << 1);
|
||||
|
||||
pca_set_con(adap, I2C_PCA_CON_ENSIO | clock);
|
||||
udelay(500); /* 500 µs 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
|
||||
static int pca_init(struct i2c_adapter *adap)
|
||||
{
|
||||
static int freqs[] = {330,288,217,146,88,59,44,36};
|
||||
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;
|
||||
|
||||
pca_reset(pca_data);
|
||||
|
||||
clock = pca_clock(pca_data);
|
||||
DEB1(KERN_INFO "%s: Clock frequency is %dkHz\n", adap->name, freqs[clock]);
|
||||
|
||||
pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock);
|
||||
udelay(500); /* 500 us for oscilator to stabilise */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
adap->timeout = 100; /* default values, should */
|
||||
adap->retries = 3; /* be replaced by defines */
|
||||
|
||||
if ((rval = pca_init(pca_adap)))
|
||||
rval = pca_init(adap);
|
||||
if (rval)
|
||||
return rval;
|
||||
|
||||
rval = i2c_add_adapter(adap);
|
||||
|
||||
return rval;
|
||||
return i2c_add_adapter(adap);
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_pca_add_bus);
|
||||
|
||||
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
|
||||
int i2c_pca_add_numbered_bus(struct i2c_adapter *adap)
|
||||
{
|
||||
int rval;
|
||||
|
||||
rval = pca_init(adap);
|
||||
if (rval)
|
||||
return rval;
|
||||
|
||||
return i2c_add_numbered_adapter(adap);
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_pca_add_numbered_bus);
|
||||
|
||||
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, "
|
||||
"Wolfram Sang <w.sang@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -100,9 +100,12 @@ config I2C_AU1550
|
|||
|
||||
config I2C_BLACKFIN_TWI
|
||||
tristate "Blackfin TWI I2C support"
|
||||
depends on BF534 || BF536 || BF537
|
||||
depends on BLACKFIN
|
||||
help
|
||||
This is the TWI I2C device driver for Blackfin 534/536/537/54x.
|
||||
This is the TWI I2C device driver for Blackfin BF522, BF525,
|
||||
BF527, BF534, BF536, BF537 and BF54x. For other Blackfin processors,
|
||||
please don't use this driver.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-bfin-twi.
|
||||
|
||||
|
@ -135,7 +138,7 @@ config I2C_ELEKTOR
|
|||
This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
|
||||
such an adapter.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-elektor.
|
||||
|
||||
config I2C_GPIO
|
||||
|
@ -190,7 +193,7 @@ config I2C_I810
|
|||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
810/815 family of mainboard I2C interfaces. Specifically, the
|
||||
810/815 family of mainboard I2C interfaces. Specifically, the
|
||||
following versions of the chipset are supported:
|
||||
i810AA
|
||||
i810AB
|
||||
|
@ -246,10 +249,10 @@ config I2C_PIIX4
|
|||
|
||||
config I2C_IBM_IIC
|
||||
tristate "IBM PPC 4xx on-chip I2C interface"
|
||||
depends on IBM_OCP
|
||||
depends on 4xx
|
||||
help
|
||||
Say Y here if you want to use IIC peripheral found on
|
||||
embedded IBM PPC 4xx based systems.
|
||||
Say Y here if you want to use IIC peripheral found on
|
||||
embedded IBM PPC 4xx based systems.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-ibm_iic.
|
||||
|
@ -269,7 +272,7 @@ config I2C_IXP2000
|
|||
depends on ARCH_IXP2000
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
Say Y here if you have an Intel IXP2000 (2400, 2800, 2850) based
|
||||
Say Y here if you have an Intel IXP2000 (2400, 2800, 2850) based
|
||||
system and are using GPIO lines for an I2C bus.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
|
@ -354,7 +357,7 @@ config I2C_PARPORT
|
|||
on the parport driver. This is meant for embedded systems. Don't say
|
||||
Y here if you intend to say Y or M there.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-parport.
|
||||
|
||||
config I2C_PARPORT_LIGHT
|
||||
|
@ -372,12 +375,12 @@ config I2C_PARPORT_LIGHT
|
|||
the clean but heavy parport handling is not an option. The
|
||||
drawback is a reduced portability and the impossibility to
|
||||
daisy-chain other parallel port devices.
|
||||
|
||||
|
||||
Don't say Y here if you said Y or M to i2c-parport. Saying M to
|
||||
both is possible but both modules should not be loaded at the same
|
||||
time.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-parport-light.
|
||||
|
||||
config I2C_PASEMI
|
||||
|
@ -401,7 +404,7 @@ config I2C_PROSAVAGE
|
|||
|
||||
This driver is deprecated in favor of the savagefb driver.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-prosavage.
|
||||
|
||||
config I2C_S3C2410
|
||||
|
@ -417,7 +420,7 @@ config I2C_SAVAGE4
|
|||
depends on PCI
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
If you say yes to this option, support will be included for the
|
||||
S3 Savage 4 I2C interface.
|
||||
|
||||
This driver is deprecated in favor of the savagefb driver.
|
||||
|
@ -452,7 +455,7 @@ config SCx200_I2C
|
|||
|
||||
If you don't know what to do here, say N.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
This support is also available as a module. If so, the module
|
||||
will be called scx200_i2c.
|
||||
|
||||
This driver is deprecated and will be dropped soon. Use i2c-gpio
|
||||
|
@ -483,14 +486,14 @@ config SCx200_ACB
|
|||
|
||||
If you don't know what to do here, say N.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
This support is also available as a module. If so, the module
|
||||
will be called scx200_acb.
|
||||
|
||||
config I2C_SIS5595
|
||||
tristate "SiS 5595"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS5595 SMBus (a subset of I2C) interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
|
@ -500,7 +503,7 @@ config I2C_SIS630
|
|||
tristate "SiS 630/730"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS630 and SiS730 SMBus (a subset of I2C) interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
|
@ -632,9 +635,9 @@ config I2C_PCA_ISA
|
|||
select I2C_ALGOPCA
|
||||
default n
|
||||
help
|
||||
This driver supports ISA boards using the Philips PCA 9564
|
||||
Parallel bus to I2C bus controller
|
||||
|
||||
This driver supports ISA boards using the Philips PCA9564
|
||||
parallel bus to I2C bus controller.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-pca-isa.
|
||||
|
||||
|
@ -643,6 +646,17 @@ config I2C_PCA_ISA
|
|||
delays when I2C/SMBus chip drivers are loaded (e.g. at boot
|
||||
time). If unsure, say N.
|
||||
|
||||
config I2C_PCA_PLATFORM
|
||||
tristate "PCA9564 as platform device"
|
||||
select I2C_ALGOPCA
|
||||
default n
|
||||
help
|
||||
This driver supports a memory mapped Philips PCA9564
|
||||
parallel bus to I2C bus controller.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-pca-platform.
|
||||
|
||||
config I2C_MV64XXX
|
||||
tristate "Marvell mv64xxx I2C Controller"
|
||||
depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
|
||||
|
@ -672,4 +686,23 @@ config I2C_PMCMSP
|
|||
This driver can also be built as module. If so, the module
|
||||
will be called i2c-pmcmsp.
|
||||
|
||||
config I2C_SH7760
|
||||
tristate "Renesas SH7760 I2C Controller"
|
||||
depends on CPU_SUBTYPE_SH7760
|
||||
help
|
||||
This driver supports the 2 I2C interfaces on the Renesas SH7760.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sh7760.
|
||||
|
||||
config I2C_SH_MOBILE
|
||||
tristate "SuperH Mobile I2C Controller"
|
||||
depends on SUPERH
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface on the Renesas SH-Mobile processor.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sh_mobile.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -30,6 +30,7 @@ obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
|
|||
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
|
||||
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
|
||||
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
|
||||
obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
|
||||
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
|
||||
obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
|
||||
obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
|
||||
|
@ -37,6 +38,8 @@ obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
|
|||
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
|
||||
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
|
||||
obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
|
||||
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
|
||||
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
|
||||
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
|
||||
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
|
||||
obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
|
||||
|
|
|
@ -298,7 +298,7 @@ static int at91_i2c_resume(struct platform_device *pdev)
|
|||
#endif
|
||||
|
||||
/* work with "modprobe at91_i2c" from hotplugging or coldplugging */
|
||||
MODULE_ALIAS("at91_i2c");
|
||||
MODULE_ALIAS("platform:at91_i2c");
|
||||
|
||||
static struct platform_driver at91_i2c_driver = {
|
||||
.probe = at91_i2c_probe,
|
||||
|
|
|
@ -472,6 +472,7 @@ i2c_au1550_exit(void)
|
|||
MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
|
||||
MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:au1xpsc_smbus");
|
||||
|
||||
module_init (i2c_au1550_init);
|
||||
module_exit (i2c_au1550_exit);
|
||||
|
|
|
@ -1,25 +1,11 @@
|
|||
/*
|
||||
* drivers/i2c/busses/i2c-bfin-twi.c
|
||||
* Blackfin On-Chip Two Wire Interface Driver
|
||||
*
|
||||
* Description: Driver for Blackfin Two Wire Interface
|
||||
* Copyright 2005-2007 Analog Devices Inc.
|
||||
*
|
||||
* Author: sonicz <sonic.zhang@analog.com>
|
||||
* Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* Copyright (c) 2005-2007 Analog Devices, Inc.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -34,14 +20,16 @@
|
|||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#define POLL_TIMEOUT (2 * HZ)
|
||||
|
||||
/* SMBus mode*/
|
||||
#define TWI_I2C_MODE_STANDARD 0x01
|
||||
#define TWI_I2C_MODE_STANDARDSUB 0x02
|
||||
#define TWI_I2C_MODE_COMBINED 0x04
|
||||
#define TWI_I2C_MODE_STANDARD 1
|
||||
#define TWI_I2C_MODE_STANDARDSUB 2
|
||||
#define TWI_I2C_MODE_COMBINED 3
|
||||
#define TWI_I2C_MODE_REPEAT 4
|
||||
|
||||
struct bfin_twi_iface {
|
||||
int irq;
|
||||
|
@ -58,39 +46,74 @@ struct bfin_twi_iface {
|
|||
struct timer_list timeout_timer;
|
||||
struct i2c_adapter adap;
|
||||
struct completion complete;
|
||||
struct i2c_msg *pmsg;
|
||||
int msg_num;
|
||||
int cur_msg;
|
||||
void __iomem *regs_base;
|
||||
};
|
||||
|
||||
static struct bfin_twi_iface twi_iface;
|
||||
|
||||
#define DEFINE_TWI_REG(reg, off) \
|
||||
static inline u16 read_##reg(struct bfin_twi_iface *iface) \
|
||||
{ return bfin_read16(iface->regs_base + (off)); } \
|
||||
static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
|
||||
{ bfin_write16(iface->regs_base + (off), v); }
|
||||
|
||||
DEFINE_TWI_REG(CLKDIV, 0x00)
|
||||
DEFINE_TWI_REG(CONTROL, 0x04)
|
||||
DEFINE_TWI_REG(SLAVE_CTL, 0x08)
|
||||
DEFINE_TWI_REG(SLAVE_STAT, 0x0C)
|
||||
DEFINE_TWI_REG(SLAVE_ADDR, 0x10)
|
||||
DEFINE_TWI_REG(MASTER_CTL, 0x14)
|
||||
DEFINE_TWI_REG(MASTER_STAT, 0x18)
|
||||
DEFINE_TWI_REG(MASTER_ADDR, 0x1C)
|
||||
DEFINE_TWI_REG(INT_STAT, 0x20)
|
||||
DEFINE_TWI_REG(INT_MASK, 0x24)
|
||||
DEFINE_TWI_REG(FIFO_CTL, 0x28)
|
||||
DEFINE_TWI_REG(FIFO_STAT, 0x2C)
|
||||
DEFINE_TWI_REG(XMT_DATA8, 0x80)
|
||||
DEFINE_TWI_REG(XMT_DATA16, 0x84)
|
||||
DEFINE_TWI_REG(RCV_DATA8, 0x88)
|
||||
DEFINE_TWI_REG(RCV_DATA16, 0x8C)
|
||||
|
||||
static const u16 pin_req[2][3] = {
|
||||
{P_TWI0_SCL, P_TWI0_SDA, 0},
|
||||
{P_TWI1_SCL, P_TWI1_SDA, 0},
|
||||
};
|
||||
|
||||
static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
|
||||
{
|
||||
unsigned short twi_int_status = bfin_read_TWI_INT_STAT();
|
||||
unsigned short mast_stat = bfin_read_TWI_MASTER_STAT();
|
||||
unsigned short twi_int_status = read_INT_STAT(iface);
|
||||
unsigned short mast_stat = read_MASTER_STAT(iface);
|
||||
|
||||
if (twi_int_status & XMTSERV) {
|
||||
/* Transmit next data */
|
||||
if (iface->writeNum > 0) {
|
||||
bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
|
||||
write_XMT_DATA8(iface, *(iface->transPtr++));
|
||||
iface->writeNum--;
|
||||
}
|
||||
/* start receive immediately after complete sending in
|
||||
* combine mode.
|
||||
*/
|
||||
else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
|
||||
bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
|
||||
| MDIR | RSTART);
|
||||
} else if (iface->manual_stop)
|
||||
bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
|
||||
| STOP);
|
||||
else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | MDIR | RSTART);
|
||||
else if (iface->manual_stop)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | STOP);
|
||||
else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
|
||||
iface->cur_msg+1 < iface->msg_num)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | RSTART);
|
||||
SSYNC();
|
||||
/* Clear status */
|
||||
bfin_write_TWI_INT_STAT(XMTSERV);
|
||||
write_INT_STAT(iface, XMTSERV);
|
||||
SSYNC();
|
||||
}
|
||||
if (twi_int_status & RCVSERV) {
|
||||
if (iface->readNum > 0) {
|
||||
/* Receive next data */
|
||||
*(iface->transPtr) = bfin_read_TWI_RCV_DATA8();
|
||||
*(iface->transPtr) = read_RCV_DATA8(iface);
|
||||
if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
|
||||
/* Change combine mode into sub mode after
|
||||
* read first data.
|
||||
|
@ -105,28 +128,33 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
|
|||
iface->transPtr++;
|
||||
iface->readNum--;
|
||||
} else if (iface->manual_stop) {
|
||||
bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
|
||||
| STOP);
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | STOP);
|
||||
SSYNC();
|
||||
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
|
||||
iface->cur_msg+1 < iface->msg_num) {
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | RSTART);
|
||||
SSYNC();
|
||||
}
|
||||
/* Clear interrupt source */
|
||||
bfin_write_TWI_INT_STAT(RCVSERV);
|
||||
write_INT_STAT(iface, RCVSERV);
|
||||
SSYNC();
|
||||
}
|
||||
if (twi_int_status & MERR) {
|
||||
bfin_write_TWI_INT_STAT(MERR);
|
||||
bfin_write_TWI_INT_MASK(0);
|
||||
bfin_write_TWI_MASTER_STAT(0x3e);
|
||||
bfin_write_TWI_MASTER_CTL(0);
|
||||
write_INT_STAT(iface, MERR);
|
||||
write_INT_MASK(iface, 0);
|
||||
write_MASTER_STAT(iface, 0x3e);
|
||||
write_MASTER_CTL(iface, 0);
|
||||
SSYNC();
|
||||
iface->result = -1;
|
||||
iface->result = -EIO;
|
||||
/* if both err and complete int stats are set, return proper
|
||||
* results.
|
||||
*/
|
||||
if (twi_int_status & MCOMP) {
|
||||
bfin_write_TWI_INT_STAT(MCOMP);
|
||||
bfin_write_TWI_INT_MASK(0);
|
||||
bfin_write_TWI_MASTER_CTL(0);
|
||||
write_INT_STAT(iface, MCOMP);
|
||||
write_INT_MASK(iface, 0);
|
||||
write_MASTER_CTL(iface, 0);
|
||||
SSYNC();
|
||||
/* If it is a quick transfer, only address bug no data,
|
||||
* not an err, return 1.
|
||||
|
@ -143,7 +171,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
|
|||
return;
|
||||
}
|
||||
if (twi_int_status & MCOMP) {
|
||||
bfin_write_TWI_INT_STAT(MCOMP);
|
||||
write_INT_STAT(iface, MCOMP);
|
||||
SSYNC();
|
||||
if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
|
||||
if (iface->readNum == 0) {
|
||||
|
@ -152,28 +180,63 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
|
|||
*/
|
||||
iface->readNum = 1;
|
||||
iface->manual_stop = 1;
|
||||
bfin_write_TWI_MASTER_CTL(
|
||||
bfin_read_TWI_MASTER_CTL()
|
||||
| (0xff << 6));
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | (0xff << 6));
|
||||
} else {
|
||||
/* set the readd number in other
|
||||
* combine mode.
|
||||
*/
|
||||
bfin_write_TWI_MASTER_CTL(
|
||||
(bfin_read_TWI_MASTER_CTL() &
|
||||
write_MASTER_CTL(iface,
|
||||
(read_MASTER_CTL(iface) &
|
||||
(~(0xff << 6))) |
|
||||
( iface->readNum << 6));
|
||||
(iface->readNum << 6));
|
||||
}
|
||||
/* remove restart bit and enable master receive */
|
||||
bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() &
|
||||
~RSTART);
|
||||
bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
|
||||
MEN | MDIR);
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) & ~RSTART);
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | MEN | MDIR);
|
||||
SSYNC();
|
||||
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
|
||||
iface->cur_msg+1 < iface->msg_num) {
|
||||
iface->cur_msg++;
|
||||
iface->transPtr = iface->pmsg[iface->cur_msg].buf;
|
||||
iface->writeNum = iface->readNum =
|
||||
iface->pmsg[iface->cur_msg].len;
|
||||
/* Set Transmit device address */
|
||||
write_MASTER_ADDR(iface,
|
||||
iface->pmsg[iface->cur_msg].addr);
|
||||
if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD)
|
||||
iface->read_write = I2C_SMBUS_READ;
|
||||
else {
|
||||
iface->read_write = I2C_SMBUS_WRITE;
|
||||
/* Transmit first data */
|
||||
if (iface->writeNum > 0) {
|
||||
write_XMT_DATA8(iface,
|
||||
*(iface->transPtr++));
|
||||
iface->writeNum--;
|
||||
SSYNC();
|
||||
}
|
||||
}
|
||||
|
||||
if (iface->pmsg[iface->cur_msg].len <= 255)
|
||||
write_MASTER_CTL(iface,
|
||||
iface->pmsg[iface->cur_msg].len << 6);
|
||||
else {
|
||||
write_MASTER_CTL(iface, 0xff << 6);
|
||||
iface->manual_stop = 1;
|
||||
}
|
||||
/* remove restart bit and enable master receive */
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) & ~RSTART);
|
||||
write_MASTER_CTL(iface, read_MASTER_CTL(iface) |
|
||||
MEN | ((iface->read_write == I2C_SMBUS_READ) ?
|
||||
MDIR : 0));
|
||||
SSYNC();
|
||||
} else {
|
||||
iface->result = 1;
|
||||
bfin_write_TWI_INT_MASK(0);
|
||||
bfin_write_TWI_MASTER_CTL(0);
|
||||
write_INT_MASK(iface, 0);
|
||||
write_MASTER_CTL(iface, 0);
|
||||
SSYNC();
|
||||
complete(&iface->complete);
|
||||
}
|
||||
|
@ -221,91 +284,85 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
|
|||
{
|
||||
struct bfin_twi_iface *iface = adap->algo_data;
|
||||
struct i2c_msg *pmsg;
|
||||
int i, ret;
|
||||
int rc = 0;
|
||||
|
||||
if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
|
||||
if (!(read_CONTROL(iface) & TWI_ENA))
|
||||
return -ENXIO;
|
||||
|
||||
while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
|
||||
while (read_MASTER_STAT(iface) & BUSBUSY)
|
||||
yield();
|
||||
|
||||
iface->pmsg = msgs;
|
||||
iface->msg_num = num;
|
||||
iface->cur_msg = 0;
|
||||
|
||||
pmsg = &msgs[0];
|
||||
if (pmsg->flags & I2C_M_TEN) {
|
||||
dev_err(&adap->dev, "10 bits addr not supported!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
for (i = 0; rc >= 0 && i < num; i++) {
|
||||
pmsg = &msgs[i];
|
||||
if (pmsg->flags & I2C_M_TEN) {
|
||||
dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr "
|
||||
"not supported !\n");
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
iface->cur_mode = TWI_I2C_MODE_REPEAT;
|
||||
iface->manual_stop = 0;
|
||||
iface->transPtr = pmsg->buf;
|
||||
iface->writeNum = iface->readNum = pmsg->len;
|
||||
iface->result = 0;
|
||||
iface->timeout_count = 10;
|
||||
init_completion(&(iface->complete));
|
||||
/* Set Transmit device address */
|
||||
write_MASTER_ADDR(iface, pmsg->addr);
|
||||
|
||||
/* FIFO Initiation. Data in FIFO should be
|
||||
* discarded before start a new operation.
|
||||
*/
|
||||
write_FIFO_CTL(iface, 0x3);
|
||||
SSYNC();
|
||||
write_FIFO_CTL(iface, 0);
|
||||
SSYNC();
|
||||
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
iface->read_write = I2C_SMBUS_READ;
|
||||
else {
|
||||
iface->read_write = I2C_SMBUS_WRITE;
|
||||
/* Transmit first data */
|
||||
if (iface->writeNum > 0) {
|
||||
write_XMT_DATA8(iface, *(iface->transPtr++));
|
||||
iface->writeNum--;
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
iface->cur_mode = TWI_I2C_MODE_STANDARD;
|
||||
iface->manual_stop = 0;
|
||||
iface->transPtr = pmsg->buf;
|
||||
iface->writeNum = iface->readNum = pmsg->len;
|
||||
iface->result = 0;
|
||||
iface->timeout_count = 10;
|
||||
/* Set Transmit device address */
|
||||
bfin_write_TWI_MASTER_ADDR(pmsg->addr);
|
||||
|
||||
/* FIFO Initiation. Data in FIFO should be
|
||||
* discarded before start a new operation.
|
||||
*/
|
||||
bfin_write_TWI_FIFO_CTL(0x3);
|
||||
SSYNC();
|
||||
bfin_write_TWI_FIFO_CTL(0);
|
||||
SSYNC();
|
||||
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
iface->read_write = I2C_SMBUS_READ;
|
||||
else {
|
||||
iface->read_write = I2C_SMBUS_WRITE;
|
||||
/* Transmit first data */
|
||||
if (iface->writeNum > 0) {
|
||||
bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
|
||||
iface->writeNum--;
|
||||
SSYNC();
|
||||
}
|
||||
}
|
||||
|
||||
/* clear int stat */
|
||||
bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
|
||||
|
||||
/* Interrupt mask . Enable XMT, RCV interrupt */
|
||||
bfin_write_TWI_INT_MASK(MCOMP | MERR |
|
||||
((iface->read_write == I2C_SMBUS_READ)?
|
||||
RCVSERV : XMTSERV));
|
||||
SSYNC();
|
||||
|
||||
if (pmsg->len > 0 && pmsg->len <= 255)
|
||||
bfin_write_TWI_MASTER_CTL(pmsg->len << 6);
|
||||
else if (pmsg->len > 255) {
|
||||
bfin_write_TWI_MASTER_CTL(0xff << 6);
|
||||
iface->manual_stop = 1;
|
||||
} else
|
||||
break;
|
||||
|
||||
iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
|
||||
add_timer(&iface->timeout_timer);
|
||||
|
||||
/* Master enable */
|
||||
bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
|
||||
((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
|
||||
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
|
||||
SSYNC();
|
||||
|
||||
wait_for_completion(&iface->complete);
|
||||
|
||||
rc = iface->result;
|
||||
if (rc == 1)
|
||||
ret++;
|
||||
else if (rc == -1)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
/* clear int stat */
|
||||
write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
|
||||
|
||||
/* Interrupt mask . Enable XMT, RCV interrupt */
|
||||
write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
|
||||
SSYNC();
|
||||
|
||||
if (pmsg->len <= 255)
|
||||
write_MASTER_CTL(iface, pmsg->len << 6);
|
||||
else {
|
||||
write_MASTER_CTL(iface, 0xff << 6);
|
||||
iface->manual_stop = 1;
|
||||
}
|
||||
|
||||
iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
|
||||
add_timer(&iface->timeout_timer);
|
||||
|
||||
/* Master enable */
|
||||
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
|
||||
((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
|
||||
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
|
||||
SSYNC();
|
||||
|
||||
wait_for_completion(&iface->complete);
|
||||
|
||||
rc = iface->result;
|
||||
|
||||
if (rc == 1)
|
||||
return num;
|
||||
else
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -319,12 +376,11 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
|||
struct bfin_twi_iface *iface = adap->algo_data;
|
||||
int rc = 0;
|
||||
|
||||
if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
|
||||
if (!(read_CONTROL(iface) & TWI_ENA))
|
||||
return -ENXIO;
|
||||
|
||||
while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
|
||||
while (read_MASTER_STAT(iface) & BUSBUSY)
|
||||
yield();
|
||||
}
|
||||
|
||||
iface->writeNum = 0;
|
||||
iface->readNum = 0;
|
||||
|
@ -392,19 +448,20 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
|||
iface->read_write = read_write;
|
||||
iface->command = command;
|
||||
iface->timeout_count = 10;
|
||||
init_completion(&(iface->complete));
|
||||
|
||||
/* FIFO Initiation. Data in FIFO should be discarded before
|
||||
* start a new operation.
|
||||
*/
|
||||
bfin_write_TWI_FIFO_CTL(0x3);
|
||||
write_FIFO_CTL(iface, 0x3);
|
||||
SSYNC();
|
||||
bfin_write_TWI_FIFO_CTL(0);
|
||||
write_FIFO_CTL(iface, 0);
|
||||
|
||||
/* clear int stat */
|
||||
bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
|
||||
write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
|
||||
|
||||
/* Set Transmit device address */
|
||||
bfin_write_TWI_MASTER_ADDR(addr);
|
||||
write_MASTER_ADDR(iface, addr);
|
||||
SSYNC();
|
||||
|
||||
iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
|
||||
|
@ -412,60 +469,64 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
|||
|
||||
switch (iface->cur_mode) {
|
||||
case TWI_I2C_MODE_STANDARDSUB:
|
||||
bfin_write_TWI_XMT_DATA8(iface->command);
|
||||
bfin_write_TWI_INT_MASK(MCOMP | MERR |
|
||||
write_XMT_DATA8(iface, iface->command);
|
||||
write_INT_MASK(iface, MCOMP | MERR |
|
||||
((iface->read_write == I2C_SMBUS_READ) ?
|
||||
RCVSERV : XMTSERV));
|
||||
SSYNC();
|
||||
|
||||
if (iface->writeNum + 1 <= 255)
|
||||
bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
|
||||
write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
|
||||
else {
|
||||
bfin_write_TWI_MASTER_CTL(0xff << 6);
|
||||
write_MASTER_CTL(iface, 0xff << 6);
|
||||
iface->manual_stop = 1;
|
||||
}
|
||||
/* Master enable */
|
||||
bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
|
||||
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
|
||||
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
|
||||
break;
|
||||
case TWI_I2C_MODE_COMBINED:
|
||||
bfin_write_TWI_XMT_DATA8(iface->command);
|
||||
bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV);
|
||||
write_XMT_DATA8(iface, iface->command);
|
||||
write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
|
||||
SSYNC();
|
||||
|
||||
if (iface->writeNum > 0)
|
||||
bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
|
||||
write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
|
||||
else
|
||||
bfin_write_TWI_MASTER_CTL(0x1 << 6);
|
||||
write_MASTER_CTL(iface, 0x1 << 6);
|
||||
/* Master enable */
|
||||
bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
|
||||
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
|
||||
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
|
||||
break;
|
||||
default:
|
||||
bfin_write_TWI_MASTER_CTL(0);
|
||||
write_MASTER_CTL(iface, 0);
|
||||
if (size != I2C_SMBUS_QUICK) {
|
||||
/* Don't access xmit data register when this is a
|
||||
* read operation.
|
||||
*/
|
||||
if (iface->read_write != I2C_SMBUS_READ) {
|
||||
if (iface->writeNum > 0) {
|
||||
bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
|
||||
write_XMT_DATA8(iface,
|
||||
*(iface->transPtr++));
|
||||
if (iface->writeNum <= 255)
|
||||
bfin_write_TWI_MASTER_CTL(iface->writeNum << 6);
|
||||
write_MASTER_CTL(iface,
|
||||
iface->writeNum << 6);
|
||||
else {
|
||||
bfin_write_TWI_MASTER_CTL(0xff << 6);
|
||||
write_MASTER_CTL(iface,
|
||||
0xff << 6);
|
||||
iface->manual_stop = 1;
|
||||
}
|
||||
iface->writeNum--;
|
||||
} else {
|
||||
bfin_write_TWI_XMT_DATA8(iface->command);
|
||||
bfin_write_TWI_MASTER_CTL(1 << 6);
|
||||
write_XMT_DATA8(iface, iface->command);
|
||||
write_MASTER_CTL(iface, 1 << 6);
|
||||
}
|
||||
} else {
|
||||
if (iface->readNum > 0 && iface->readNum <= 255)
|
||||
bfin_write_TWI_MASTER_CTL(iface->readNum << 6);
|
||||
write_MASTER_CTL(iface,
|
||||
iface->readNum << 6);
|
||||
else if (iface->readNum > 255) {
|
||||
bfin_write_TWI_MASTER_CTL(0xff << 6);
|
||||
write_MASTER_CTL(iface, 0xff << 6);
|
||||
iface->manual_stop = 1;
|
||||
} else {
|
||||
del_timer(&iface->timeout_timer);
|
||||
|
@ -473,13 +534,13 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
|||
}
|
||||
}
|
||||
}
|
||||
bfin_write_TWI_INT_MASK(MCOMP | MERR |
|
||||
write_INT_MASK(iface, MCOMP | MERR |
|
||||
((iface->read_write == I2C_SMBUS_READ) ?
|
||||
RCVSERV : XMTSERV));
|
||||
SSYNC();
|
||||
|
||||
/* Master enable */
|
||||
bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
|
||||
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
|
||||
((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
|
||||
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
|
||||
break;
|
||||
|
@ -514,10 +575,10 @@ static struct i2c_algorithm bfin_twi_algorithm = {
|
|||
|
||||
static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
|
||||
struct bfin_twi_iface *iface = platform_get_drvdata(dev);
|
||||
|
||||
/* Disable TWI */
|
||||
bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA);
|
||||
write_CONTROL(iface, read_CONTROL(iface) & ~TWI_ENA);
|
||||
SSYNC();
|
||||
|
||||
return 0;
|
||||
|
@ -525,24 +586,52 @@ static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state)
|
|||
|
||||
static int i2c_bfin_twi_resume(struct platform_device *dev)
|
||||
{
|
||||
/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
|
||||
struct bfin_twi_iface *iface = platform_get_drvdata(dev);
|
||||
|
||||
/* Enable TWI */
|
||||
bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
|
||||
write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
|
||||
SSYNC();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_bfin_twi_probe(struct platform_device *dev)
|
||||
static int i2c_bfin_twi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bfin_twi_iface *iface = &twi_iface;
|
||||
struct bfin_twi_iface *iface;
|
||||
struct i2c_adapter *p_adap;
|
||||
struct resource *res;
|
||||
int rc;
|
||||
|
||||
iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
|
||||
if (!iface) {
|
||||
dev_err(&pdev->dev, "Cannot allocate memory\n");
|
||||
rc = -ENOMEM;
|
||||
goto out_error_nomem;
|
||||
}
|
||||
|
||||
spin_lock_init(&(iface->lock));
|
||||
init_completion(&(iface->complete));
|
||||
iface->irq = IRQ_TWI;
|
||||
|
||||
/* Find and map our resources */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
|
||||
rc = -ENOENT;
|
||||
goto out_error_get_res;
|
||||
}
|
||||
|
||||
iface->regs_base = ioremap(res->start, res->end - res->start + 1);
|
||||
if (iface->regs_base == NULL) {
|
||||
dev_err(&pdev->dev, "Cannot map IO\n");
|
||||
rc = -ENXIO;
|
||||
goto out_error_ioremap;
|
||||
}
|
||||
|
||||
iface->irq = platform_get_irq(pdev, 0);
|
||||
if (iface->irq < 0) {
|
||||
dev_err(&pdev->dev, "No IRQ specified\n");
|
||||
rc = -ENOENT;
|
||||
goto out_error_no_irq;
|
||||
}
|
||||
|
||||
init_timer(&(iface->timeout_timer));
|
||||
iface->timeout_timer.function = bfin_twi_timeout;
|
||||
|
@ -550,39 +639,63 @@ static int i2c_bfin_twi_probe(struct platform_device *dev)
|
|||
|
||||
p_adap = &iface->adap;
|
||||
p_adap->id = I2C_HW_BLACKFIN;
|
||||
p_adap->nr = dev->id;
|
||||
strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
|
||||
p_adap->nr = pdev->id;
|
||||
strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
|
||||
p_adap->algo = &bfin_twi_algorithm;
|
||||
p_adap->algo_data = iface;
|
||||
p_adap->class = I2C_CLASS_ALL;
|
||||
p_adap->dev.parent = &dev->dev;
|
||||
p_adap->dev.parent = &pdev->dev;
|
||||
|
||||
rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Can't setup pin mux!\n");
|
||||
goto out_error_pin_mux;
|
||||
}
|
||||
|
||||
rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
|
||||
IRQF_DISABLED, dev->name, iface);
|
||||
IRQF_DISABLED, pdev->name, iface);
|
||||
if (rc) {
|
||||
dev_err(&(p_adap->dev), "i2c-bfin-twi: can't get IRQ %d !\n",
|
||||
iface->irq);
|
||||
return -ENODEV;
|
||||
dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
|
||||
rc = -ENODEV;
|
||||
goto out_error_req_irq;
|
||||
}
|
||||
|
||||
/* Set TWI internal clock as 10MHz */
|
||||
bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
|
||||
write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
|
||||
|
||||
/* Set Twi interface clock as specified */
|
||||
bfin_write_TWI_CLKDIV((( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
|
||||
<< 8) | (( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
|
||||
write_CLKDIV(iface, ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
|
||||
<< 8) | ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
|
||||
& 0xFF));
|
||||
|
||||
/* Enable TWI */
|
||||
bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
|
||||
write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
|
||||
SSYNC();
|
||||
|
||||
rc = i2c_add_numbered_adapter(p_adap);
|
||||
if (rc < 0)
|
||||
free_irq(iface->irq, iface);
|
||||
else
|
||||
platform_set_drvdata(dev, iface);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "Can't add i2c adapter!\n");
|
||||
goto out_error_add_adapter;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, iface);
|
||||
|
||||
dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, "
|
||||
"regs_base@%p\n", iface->regs_base);
|
||||
|
||||
return 0;
|
||||
|
||||
out_error_add_adapter:
|
||||
free_irq(iface->irq, iface);
|
||||
out_error_req_irq:
|
||||
out_error_no_irq:
|
||||
peripheral_free_list(pin_req[pdev->id]);
|
||||
out_error_pin_mux:
|
||||
iounmap(iface->regs_base);
|
||||
out_error_ioremap:
|
||||
out_error_get_res:
|
||||
kfree(iface);
|
||||
out_error_nomem:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -594,6 +707,9 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev)
|
|||
|
||||
i2c_del_adapter(&(iface->adap));
|
||||
free_irq(iface->irq, iface);
|
||||
peripheral_free_list(pin_req[pdev->id]);
|
||||
iounmap(iface->regs_base);
|
||||
kfree(iface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -611,8 +727,6 @@ static struct platform_driver i2c_bfin_twi_driver = {
|
|||
|
||||
static int __init i2c_bfin_twi_init(void)
|
||||
{
|
||||
pr_info("I2C: Blackfin I2C TWI driver\n");
|
||||
|
||||
return platform_driver_register(&i2c_bfin_twi_driver);
|
||||
}
|
||||
|
||||
|
@ -621,9 +735,10 @@ static void __exit i2c_bfin_twi_exit(void)
|
|||
platform_driver_unregister(&i2c_bfin_twi_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
|
||||
MODULE_DESCRIPTION("I2C-Bus adapter routines for Blackfin TWI");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_bfin_twi_init);
|
||||
module_exit(i2c_bfin_twi_exit);
|
||||
|
||||
MODULE_AUTHOR("Bryan Wu, Sonic Zhang");
|
||||
MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:i2c-bfin-twi");
|
||||
|
|
|
@ -328,7 +328,7 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|||
int i;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev->dev, "%s: msgs: %d\n", __FUNCTION__, num);
|
||||
dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
|
||||
|
||||
ret = i2c_davinci_wait_bus_not_busy(dev, 1);
|
||||
if (ret < 0) {
|
||||
|
@ -342,7 +342,7 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(dev->dev, "%s:%d ret: %d\n", __FUNCTION__, __LINE__, ret);
|
||||
dev_dbg(dev->dev, "%s:%d ret: %d\n", __func__, __LINE__, ret);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
@ -364,7 +364,7 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
|
|||
u16 w;
|
||||
|
||||
while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) {
|
||||
dev_dbg(dev->dev, "%s: stat=0x%x\n", __FUNCTION__, stat);
|
||||
dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
|
||||
if (count++ == 100) {
|
||||
dev_warn(dev->dev, "Too much work in one IRQ\n");
|
||||
break;
|
||||
|
@ -553,6 +553,9 @@ static int davinci_i2c_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* work with hotplug and coldplug */
|
||||
MODULE_ALIAS("platform:i2c_davinci");
|
||||
|
||||
static struct platform_driver davinci_i2c_driver = {
|
||||
.probe = davinci_i2c_probe,
|
||||
.remove = davinci_i2c_remove,
|
||||
|
|
|
@ -220,3 +220,4 @@ module_exit(i2c_gpio_exit);
|
|||
MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
|
||||
MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:i2c-gpio");
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
* Copyright (c) 2003, 2004 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Copyright (c) 2008 PIKA Technologies
|
||||
* Sean MacLennan <smaclennan@pikatech.com>
|
||||
*
|
||||
* Based on original work by
|
||||
* Ian DaSilva <idasilva@mvista.com>
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
|
@ -39,12 +42,17 @@
|
|||
#include <asm/io.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
|
||||
#ifdef CONFIG_IBM_OCP
|
||||
#include <asm/ocp.h>
|
||||
#include <asm/ibm4xx.h>
|
||||
#else
|
||||
#include <linux/of_platform.h>
|
||||
#endif
|
||||
|
||||
#include "i2c-ibm_iic.h"
|
||||
|
||||
#define DRIVER_VERSION "2.1"
|
||||
#define DRIVER_VERSION "2.2"
|
||||
|
||||
MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -650,13 +658,14 @@ static inline u8 iic_clckdiv(unsigned int opb)
|
|||
opb /= 1000000;
|
||||
|
||||
if (opb < 20 || opb > 150){
|
||||
printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n",
|
||||
printk(KERN_WARNING "ibm-iic: invalid OPB clock frequency %u MHz\n",
|
||||
opb);
|
||||
opb = opb < 20 ? 20 : 150;
|
||||
}
|
||||
return (u8)((opb + 9) / 10 - 1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IBM_OCP
|
||||
/*
|
||||
* Register single IIC interface
|
||||
*/
|
||||
|
@ -672,7 +681,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
|
|||
ocp->def->index);
|
||||
|
||||
if (!(dev = kzalloc(sizeof(*dev), GFP_KERNEL))) {
|
||||
printk(KERN_CRIT "ibm-iic%d: failed to allocate device data\n",
|
||||
printk(KERN_ERR "ibm-iic%d: failed to allocate device data\n",
|
||||
ocp->def->index);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -687,7 +696,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
|
|||
}
|
||||
|
||||
if (!(dev->vaddr = ioremap(ocp->def->paddr, sizeof(struct iic_regs)))){
|
||||
printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n",
|
||||
printk(KERN_ERR "ibm-iic%d: failed to ioremap device registers\n",
|
||||
dev->idx);
|
||||
ret = -ENXIO;
|
||||
goto fail2;
|
||||
|
@ -745,7 +754,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
|
|||
adap->nr = dev->idx >= 0 ? dev->idx : 0;
|
||||
|
||||
if ((ret = i2c_add_numbered_adapter(adap)) < 0) {
|
||||
printk(KERN_CRIT "ibm-iic%d: failed to register i2c adapter\n",
|
||||
printk(KERN_ERR "ibm-iic%d: failed to register i2c adapter\n",
|
||||
dev->idx);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -778,7 +787,7 @@ static void __devexit iic_remove(struct ocp_device *ocp)
|
|||
struct ibm_iic_private* dev = (struct ibm_iic_private*)ocp_get_drvdata(ocp);
|
||||
BUG_ON(dev == NULL);
|
||||
if (i2c_del_adapter(&dev->adap)){
|
||||
printk(KERN_CRIT "ibm-iic%d: failed to delete i2c adapter :(\n",
|
||||
printk(KERN_ERR "ibm-iic%d: failed to delete i2c adapter :(\n",
|
||||
dev->idx);
|
||||
/* That's *very* bad, just shutdown IRQ ... */
|
||||
if (dev->irq >= 0){
|
||||
|
@ -828,5 +837,181 @@ static void __exit iic_exit(void)
|
|||
ocp_unregister_driver(&ibm_iic_driver);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_IBM_OCP */
|
||||
|
||||
static int __devinit iic_request_irq(struct of_device *ofdev,
|
||||
struct ibm_iic_private *dev)
|
||||
{
|
||||
struct device_node *np = ofdev->node;
|
||||
int irq;
|
||||
|
||||
if (iic_force_poll)
|
||||
return NO_IRQ;
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (irq == NO_IRQ) {
|
||||
dev_err(&ofdev->dev, "irq_of_parse_and_map failed\n");
|
||||
return NO_IRQ;
|
||||
}
|
||||
|
||||
/* Disable interrupts until we finish initialization, assumes
|
||||
* level-sensitive IRQ setup...
|
||||
*/
|
||||
iic_interrupt_mode(dev, 0);
|
||||
if (request_irq(irq, iic_handler, 0, "IBM IIC", dev)) {
|
||||
dev_err(&ofdev->dev, "request_irq %d failed\n", irq);
|
||||
/* Fallback to the polling mode */
|
||||
return NO_IRQ;
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register single IIC interface
|
||||
*/
|
||||
static int __devinit iic_probe(struct of_device *ofdev,
|
||||
const struct of_device_id *match)
|
||||
{
|
||||
struct device_node *np = ofdev->node;
|
||||
struct ibm_iic_private *dev;
|
||||
struct i2c_adapter *adap;
|
||||
const u32 *indexp, *freq;
|
||||
int ret;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
dev_err(&ofdev->dev, "failed to allocate device data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&ofdev->dev, dev);
|
||||
|
||||
indexp = of_get_property(np, "index", NULL);
|
||||
if (!indexp) {
|
||||
dev_err(&ofdev->dev, "no index specified\n");
|
||||
ret = -EINVAL;
|
||||
goto error_cleanup;
|
||||
}
|
||||
dev->idx = *indexp;
|
||||
|
||||
dev->vaddr = of_iomap(np, 0);
|
||||
if (dev->vaddr == NULL) {
|
||||
dev_err(&ofdev->dev, "failed to iomap device\n");
|
||||
ret = -ENXIO;
|
||||
goto error_cleanup;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&dev->wq);
|
||||
|
||||
dev->irq = iic_request_irq(ofdev, dev);
|
||||
if (dev->irq == NO_IRQ)
|
||||
dev_warn(&ofdev->dev, "using polling mode\n");
|
||||
|
||||
/* Board specific settings */
|
||||
if (iic_force_fast || of_get_property(np, "fast-mode", NULL))
|
||||
dev->fast_mode = 1;
|
||||
|
||||
freq = of_get_property(np, "clock-frequency", NULL);
|
||||
if (freq == NULL) {
|
||||
freq = of_get_property(np->parent, "clock-frequency", NULL);
|
||||
if (freq == NULL) {
|
||||
dev_err(&ofdev->dev, "Unable to get bus frequency\n");
|
||||
ret = -EINVAL;
|
||||
goto error_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
dev->clckdiv = iic_clckdiv(*freq);
|
||||
dev_dbg(&ofdev->dev, "clckdiv = %d\n", dev->clckdiv);
|
||||
|
||||
/* Initialize IIC interface */
|
||||
iic_dev_init(dev);
|
||||
|
||||
/* Register it with i2c layer */
|
||||
adap = &dev->adap;
|
||||
adap->dev.parent = &ofdev->dev;
|
||||
strlcpy(adap->name, "IBM IIC", sizeof(adap->name));
|
||||
i2c_set_adapdata(adap, dev);
|
||||
adap->id = I2C_HW_OCP;
|
||||
adap->class = I2C_CLASS_HWMON;
|
||||
adap->algo = &iic_algo;
|
||||
adap->timeout = 1;
|
||||
adap->nr = dev->idx;
|
||||
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
if (ret < 0) {
|
||||
dev_err(&ofdev->dev, "failed to register i2c adapter\n");
|
||||
goto error_cleanup;
|
||||
}
|
||||
|
||||
dev_info(&ofdev->dev, "using %s mode\n",
|
||||
dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
|
||||
|
||||
return 0;
|
||||
|
||||
error_cleanup:
|
||||
if (dev->irq != NO_IRQ) {
|
||||
iic_interrupt_mode(dev, 0);
|
||||
free_irq(dev->irq, dev);
|
||||
}
|
||||
|
||||
if (dev->vaddr)
|
||||
iounmap(dev->vaddr);
|
||||
|
||||
dev_set_drvdata(&ofdev->dev, NULL);
|
||||
kfree(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup initialized IIC interface
|
||||
*/
|
||||
static int __devexit iic_remove(struct of_device *ofdev)
|
||||
{
|
||||
struct ibm_iic_private *dev = dev_get_drvdata(&ofdev->dev);
|
||||
|
||||
dev_set_drvdata(&ofdev->dev, NULL);
|
||||
|
||||
i2c_del_adapter(&dev->adap);
|
||||
|
||||
if (dev->irq != NO_IRQ) {
|
||||
iic_interrupt_mode(dev, 0);
|
||||
free_irq(dev->irq, dev);
|
||||
}
|
||||
|
||||
iounmap(dev->vaddr);
|
||||
kfree(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ibm_iic_match[] = {
|
||||
{ .compatible = "ibm,iic-405ex", },
|
||||
{ .compatible = "ibm,iic-405gp", },
|
||||
{ .compatible = "ibm,iic-440gp", },
|
||||
{ .compatible = "ibm,iic-440gpx", },
|
||||
{ .compatible = "ibm,iic-440grx", },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct of_platform_driver ibm_iic_driver = {
|
||||
.name = "ibm-iic",
|
||||
.match_table = ibm_iic_match,
|
||||
.probe = iic_probe,
|
||||
.remove = __devexit_p(iic_remove),
|
||||
};
|
||||
|
||||
static int __init iic_init(void)
|
||||
{
|
||||
return of_register_platform_driver(&ibm_iic_driver);
|
||||
}
|
||||
|
||||
static void __exit iic_exit(void)
|
||||
{
|
||||
of_unregister_platform_driver(&ibm_iic_driver);
|
||||
}
|
||||
#endif /* CONFIG_IBM_OCP */
|
||||
|
||||
module_init(iic_init);
|
||||
module_exit(iic_exit);
|
||||
|
|
|
@ -550,3 +550,4 @@ module_exit (i2c_iop3xx_exit);
|
|||
MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>");
|
||||
MODULE_DESCRIPTION("IOP3xx iic algorithm and driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:IOP3xx-I2C");
|
||||
|
|
|
@ -164,4 +164,5 @@ module_exit(ixp2000_i2c_exit);
|
|||
MODULE_AUTHOR ("Deepak Saxena <dsaxena@plexity.net>");
|
||||
MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:IXP2000-I2C");
|
||||
|
||||
|
|
|
@ -392,6 +392,9 @@ static int fsl_i2c_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
};
|
||||
|
||||
/* work with hotplug and coldplug */
|
||||
MODULE_ALIAS("platform:fsl-i2c");
|
||||
|
||||
/* Structure for a device driver */
|
||||
static struct platform_driver fsl_i2c_driver = {
|
||||
.probe = fsl_i2c_probe,
|
||||
|
|
|
@ -312,6 +312,9 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* work with hotplug and coldplug */
|
||||
MODULE_ALIAS("platform:ocores-i2c");
|
||||
|
||||
static struct platform_driver ocores_i2c_driver = {
|
||||
.probe = ocores_i2c_probe,
|
||||
.remove = __devexit_p(ocores_i2c_remove),
|
||||
|
|
|
@ -693,3 +693,4 @@ module_exit(omap_i2c_exit_driver);
|
|||
MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
|
||||
MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:i2c_omap");
|
||||
|
|
|
@ -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
|
||||
|
@ -22,11 +23,9 @@
|
|||
#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>
|
||||
|
@ -34,13 +33,9 @@
|
|||
#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;
|
||||
|
||||
|
@ -48,22 +43,9 @@ static int irq = 10;
|
|||
* 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" };
|
||||
|
@ -72,44 +54,49 @@ 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
|
||||
{
|
||||
static char *names[] = { "STA", "DAT", "ADR", "CON" };
|
||||
static char *names[] = { "STA", "DAT", "ADR", "CON" };
|
||||
printk("*** read %s => %#04x\n", names[reg], res);
|
||||
}
|
||||
#endif
|
||||
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 = {
|
||||
|
@ -117,6 +104,7 @@ static struct i2c_adapter pca_isa_ops = {
|
|||
.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)
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* i2c_pca_platform.c
|
||||
*
|
||||
* Platform driver for the PCA9564 I2C controller.
|
||||
*
|
||||
* 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 version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c-algo-pca.h>
|
||||
#include <linux/i2c-pca-platform.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define res_len(r) ((r)->end - (r)->start + 1)
|
||||
|
||||
struct i2c_pca_pf_data {
|
||||
void __iomem *reg_base;
|
||||
int irq; /* if 0, use polling */
|
||||
int gpio;
|
||||
wait_queue_head_t wait;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_algo_pca_data algo_data;
|
||||
unsigned long io_base;
|
||||
unsigned long io_size;
|
||||
};
|
||||
|
||||
/* Read/Write functions for different register alignments */
|
||||
|
||||
static int i2c_pca_pf_readbyte8(void *pd, int reg)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c = pd;
|
||||
return ioread8(i2c->reg_base + reg);
|
||||
}
|
||||
|
||||
static int i2c_pca_pf_readbyte16(void *pd, int reg)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c = pd;
|
||||
return ioread8(i2c->reg_base + reg * 2);
|
||||
}
|
||||
|
||||
static int i2c_pca_pf_readbyte32(void *pd, int reg)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c = pd;
|
||||
return ioread8(i2c->reg_base + reg * 4);
|
||||
}
|
||||
|
||||
static void i2c_pca_pf_writebyte8(void *pd, int reg, int val)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c = pd;
|
||||
iowrite8(val, i2c->reg_base + reg);
|
||||
}
|
||||
|
||||
static void i2c_pca_pf_writebyte16(void *pd, int reg, int val)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c = pd;
|
||||
iowrite8(val, i2c->reg_base + reg * 2);
|
||||
}
|
||||
|
||||
static void i2c_pca_pf_writebyte32(void *pd, int reg, int val)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c = pd;
|
||||
iowrite8(val, i2c->reg_base + reg * 4);
|
||||
}
|
||||
|
||||
|
||||
static int i2c_pca_pf_waitforcompletion(void *pd)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c = pd;
|
||||
int ret = 0;
|
||||
|
||||
if (i2c->irq) {
|
||||
ret = wait_event_interruptible(i2c->wait,
|
||||
i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
|
||||
& I2C_PCA_CON_SI);
|
||||
} else {
|
||||
/*
|
||||
* Do polling...
|
||||
* XXX: Could get stuck in extreme cases!
|
||||
* Maybe add timeout, but using irqs is preferred anyhow.
|
||||
*/
|
||||
while ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
|
||||
& I2C_PCA_CON_SI) == 0)
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void i2c_pca_pf_dummyreset(void *pd)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c = pd;
|
||||
printk(KERN_WARNING "%s: No reset-pin found. Chip may get stuck!\n",
|
||||
i2c->adap.name);
|
||||
}
|
||||
|
||||
static void i2c_pca_pf_resetchip(void *pd)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c = pd;
|
||||
|
||||
gpio_set_value(i2c->gpio, 0);
|
||||
ndelay(100);
|
||||
gpio_set_value(i2c->gpio, 1);
|
||||
}
|
||||
|
||||
static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c = dev_id;
|
||||
|
||||
if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
wake_up_interruptible(&i2c->wait);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static int __devinit i2c_pca_pf_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c;
|
||||
struct resource *res;
|
||||
struct i2c_pca9564_pf_platform_data *platform_data =
|
||||
pdev->dev.platform_data;
|
||||
int ret = 0;
|
||||
int irq;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
/* If irq is 0, we do polling. */
|
||||
|
||||
if (res == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto e_print;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, res_len(res), res->name)) {
|
||||
ret = -ENOMEM;
|
||||
goto e_print;
|
||||
}
|
||||
|
||||
i2c = kzalloc(sizeof(struct i2c_pca_pf_data), GFP_KERNEL);
|
||||
if (!i2c) {
|
||||
ret = -ENOMEM;
|
||||
goto e_alloc;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
|
||||
i2c->reg_base = ioremap(res->start, res_len(res));
|
||||
if (!i2c->reg_base) {
|
||||
ret = -EIO;
|
||||
goto e_remap;
|
||||
}
|
||||
i2c->io_base = res->start;
|
||||
i2c->io_size = res_len(res);
|
||||
i2c->irq = irq;
|
||||
|
||||
i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
|
||||
i2c->adap.owner = THIS_MODULE;
|
||||
snprintf(i2c->adap.name, sizeof(i2c->adap.name), "PCA9564 at 0x%08lx",
|
||||
(unsigned long) res->start);
|
||||
i2c->adap.algo_data = &i2c->algo_data;
|
||||
i2c->adap.dev.parent = &pdev->dev;
|
||||
i2c->adap.timeout = platform_data->timeout;
|
||||
|
||||
i2c->algo_data.i2c_clock = platform_data->i2c_clock_speed;
|
||||
i2c->algo_data.data = i2c;
|
||||
|
||||
switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
|
||||
case IORESOURCE_MEM_32BIT:
|
||||
i2c->algo_data.write_byte = i2c_pca_pf_writebyte32;
|
||||
i2c->algo_data.read_byte = i2c_pca_pf_readbyte32;
|
||||
break;
|
||||
case IORESOURCE_MEM_16BIT:
|
||||
i2c->algo_data.write_byte = i2c_pca_pf_writebyte16;
|
||||
i2c->algo_data.read_byte = i2c_pca_pf_readbyte16;
|
||||
break;
|
||||
case IORESOURCE_MEM_8BIT:
|
||||
default:
|
||||
i2c->algo_data.write_byte = i2c_pca_pf_writebyte8;
|
||||
i2c->algo_data.read_byte = i2c_pca_pf_readbyte8;
|
||||
break;
|
||||
}
|
||||
|
||||
i2c->algo_data.wait_for_completion = i2c_pca_pf_waitforcompletion;
|
||||
|
||||
i2c->gpio = platform_data->gpio;
|
||||
i2c->algo_data.reset_chip = i2c_pca_pf_dummyreset;
|
||||
|
||||
/* Use gpio_is_valid() when in mainline */
|
||||
if (i2c->gpio > -1) {
|
||||
ret = gpio_request(i2c->gpio, i2c->adap.name);
|
||||
if (ret == 0) {
|
||||
gpio_direction_output(i2c->gpio, 1);
|
||||
i2c->algo_data.reset_chip = i2c_pca_pf_resetchip;
|
||||
} else {
|
||||
printk(KERN_WARNING "%s: Registering gpio failed!\n",
|
||||
i2c->adap.name);
|
||||
i2c->gpio = ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (irq) {
|
||||
ret = request_irq(irq, i2c_pca_pf_handler,
|
||||
IRQF_TRIGGER_FALLING, i2c->adap.name, i2c);
|
||||
if (ret)
|
||||
goto e_reqirq;
|
||||
}
|
||||
|
||||
if (i2c_pca_add_numbered_bus(&i2c->adap) < 0) {
|
||||
ret = -ENODEV;
|
||||
goto e_adapt;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
printk(KERN_INFO "%s registered.\n", i2c->adap.name);
|
||||
|
||||
return 0;
|
||||
|
||||
e_adapt:
|
||||
if (irq)
|
||||
free_irq(irq, i2c);
|
||||
e_reqirq:
|
||||
if (i2c->gpio > -1)
|
||||
gpio_free(i2c->gpio);
|
||||
|
||||
iounmap(i2c->reg_base);
|
||||
e_remap:
|
||||
kfree(i2c);
|
||||
e_alloc:
|
||||
release_mem_region(res->start, res_len(res));
|
||||
e_print:
|
||||
printk(KERN_ERR "Registering PCA9564 FAILED! (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit i2c_pca_pf_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_pca_pf_data *i2c = platform_get_drvdata(pdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
|
||||
if (i2c->irq)
|
||||
free_irq(i2c->irq, i2c);
|
||||
|
||||
if (i2c->gpio > -1)
|
||||
gpio_free(i2c->gpio);
|
||||
|
||||
iounmap(i2c->reg_base);
|
||||
release_mem_region(i2c->io_base, i2c->io_size);
|
||||
kfree(i2c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver i2c_pca_pf_driver = {
|
||||
.probe = i2c_pca_pf_probe,
|
||||
.remove = __devexit_p(i2c_pca_pf_remove),
|
||||
.driver = {
|
||||
.name = "i2c-pca-platform",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init i2c_pca_pf_init(void)
|
||||
{
|
||||
return platform_driver_register(&i2c_pca_pf_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_pca_pf_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&i2c_pca_pf_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("I2C-PCA9564 platform driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_pca_pf_init);
|
||||
module_exit(i2c_pca_pf_exit);
|
||||
|
|
@ -467,7 +467,7 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
|
|||
(cmd->read_len == 0 || cmd->write_len == 0))) {
|
||||
dev_err(&pmcmsptwi_adapter.dev,
|
||||
"%s: Cannot transfer less than 1 byte\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -475,7 +475,7 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
|
|||
cmd->write_len > MSP_MAX_BYTES_PER_RW) {
|
||||
dev_err(&pmcmsptwi_adapter.dev,
|
||||
"%s: Cannot transfer more than %d bytes\n",
|
||||
__FUNCTION__, MSP_MAX_BYTES_PER_RW);
|
||||
__func__, MSP_MAX_BYTES_PER_RW);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -627,6 +627,9 @@ static struct i2c_adapter pmcmsptwi_adapter = {
|
|||
.name = DRV_NAME,
|
||||
};
|
||||
|
||||
/* work with hotplug and coldplug */
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
||||
static struct platform_driver pmcmsptwi_driver = {
|
||||
.probe = pmcmsptwi_probe,
|
||||
.remove = __devexit_p(pmcmsptwi_remove),
|
||||
|
|
|
@ -76,7 +76,7 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
|
|||
{
|
||||
struct i2c_pnx_algo_data *alg_data = adap->algo_data;
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __FUNCTION__,
|
||||
dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __func__,
|
||||
slave_addr, alg_data->mif.mode);
|
||||
|
||||
/* Check for 7 bit slave addresses only */
|
||||
|
@ -110,14 +110,14 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
|
|||
iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi,
|
||||
I2C_REG_STS(alg_data));
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): sending %#x\n", __FUNCTION__,
|
||||
dev_dbg(&adap->dev, "%s(): sending %#x\n", __func__,
|
||||
(slave_addr << 1) | start_bit | alg_data->mif.mode);
|
||||
|
||||
/* Write the slave address, START bit and R/W bit */
|
||||
iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode,
|
||||
I2C_REG_TX(alg_data));
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): exit\n", __FUNCTION__);
|
||||
dev_dbg(&adap->dev, "%s(): exit\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
|
|||
long timeout = 1000;
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
|
||||
__FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
|
||||
__func__, ioread32(I2C_REG_STS(alg_data)));
|
||||
|
||||
/* Write a STOP bit to TX FIFO */
|
||||
iowrite32(0xff | stop_bit, I2C_REG_TX(alg_data));
|
||||
|
@ -149,7 +149,7 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
|
|||
}
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
|
||||
__FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
|
||||
__func__, ioread32(I2C_REG_STS(alg_data)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,7 +164,7 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
|
|||
u32 val;
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
|
||||
__FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
|
||||
__func__, ioread32(I2C_REG_STS(alg_data)));
|
||||
|
||||
if (alg_data->mif.len > 0) {
|
||||
/* We still have something to talk about... */
|
||||
|
@ -179,7 +179,7 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
|
|||
alg_data->mif.len--;
|
||||
iowrite32(val, I2C_REG_TX(alg_data));
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __FUNCTION__,
|
||||
dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __func__,
|
||||
val, alg_data->mif.len + 1);
|
||||
|
||||
if (alg_data->mif.len == 0) {
|
||||
|
@ -197,7 +197,7 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
|
|||
del_timer_sync(&alg_data->mif.timer);
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
|
||||
complete(&alg_data->mif.complete);
|
||||
}
|
||||
|
@ -213,13 +213,13 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
|
|||
/* Stop timer. */
|
||||
del_timer_sync(&alg_data->mif.timer);
|
||||
dev_dbg(&adap->dev, "%s(): Waking up xfer routine after "
|
||||
"zero-xfer.\n", __FUNCTION__);
|
||||
"zero-xfer.\n", __func__);
|
||||
|
||||
complete(&alg_data->mif.complete);
|
||||
}
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
|
||||
__FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
|
||||
__func__, ioread32(I2C_REG_STS(alg_data)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -237,14 +237,14 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
|
|||
u32 ctl = 0;
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
|
||||
__FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
|
||||
__func__, ioread32(I2C_REG_STS(alg_data)));
|
||||
|
||||
/* Check, whether there is already data,
|
||||
* or we didn't 'ask' for it yet.
|
||||
*/
|
||||
if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) {
|
||||
dev_dbg(&adap->dev, "%s(): Write dummy data to fill "
|
||||
"Rx-fifo...\n", __FUNCTION__);
|
||||
"Rx-fifo...\n", __func__);
|
||||
|
||||
if (alg_data->mif.len == 1) {
|
||||
/* Last byte, do not acknowledge next rcv. */
|
||||
|
@ -276,7 +276,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
|
|||
if (alg_data->mif.len > 0) {
|
||||
val = ioread32(I2C_REG_RX(alg_data));
|
||||
*alg_data->mif.buf++ = (u8) (val & 0xff);
|
||||
dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __FUNCTION__, val,
|
||||
dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __func__, val,
|
||||
alg_data->mif.len);
|
||||
|
||||
alg_data->mif.len--;
|
||||
|
@ -300,7 +300,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
|
|||
}
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
|
||||
__FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
|
||||
__func__, ioread32(I2C_REG_STS(alg_data)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -312,7 +312,7 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
|
|||
struct i2c_pnx_algo_data *alg_data = adap->algo_data;
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n",
|
||||
__FUNCTION__,
|
||||
__func__,
|
||||
ioread32(I2C_REG_STS(alg_data)),
|
||||
ioread32(I2C_REG_CTL(alg_data)),
|
||||
alg_data->mif.mode);
|
||||
|
@ -336,7 +336,7 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
|
|||
/* Slave did not acknowledge, generate a STOP */
|
||||
dev_dbg(&adap->dev, "%s(): "
|
||||
"Slave did not acknowledge, generating a STOP.\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
i2c_pnx_stop(adap);
|
||||
|
||||
/* Disable master interrupts. */
|
||||
|
@ -375,7 +375,7 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
|
|||
iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data));
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n",
|
||||
__FUNCTION__, ioread32(I2C_REG_STS(alg_data)),
|
||||
__func__, ioread32(I2C_REG_STS(alg_data)),
|
||||
ioread32(I2C_REG_CTL(alg_data)));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -447,7 +447,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||
u32 stat = ioread32(I2C_REG_STS(alg_data));
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n",
|
||||
__FUNCTION__, num, ioread32(I2C_REG_STS(alg_data)));
|
||||
__func__, num, ioread32(I2C_REG_STS(alg_data)));
|
||||
|
||||
bus_reset_if_active(adap);
|
||||
|
||||
|
@ -473,7 +473,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||
alg_data->mif.ret = 0;
|
||||
alg_data->last = (i == num - 1);
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __FUNCTION__,
|
||||
dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __func__,
|
||||
alg_data->mif.mode,
|
||||
alg_data->mif.len);
|
||||
|
||||
|
@ -498,7 +498,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||
if (!(rc = alg_data->mif.ret))
|
||||
completed++;
|
||||
dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n",
|
||||
__FUNCTION__, rc);
|
||||
__func__, rc);
|
||||
|
||||
/* Clear TDI and AFI bits in case they are set. */
|
||||
if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) {
|
||||
|
@ -522,7 +522,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||
alg_data->mif.len = 0;
|
||||
|
||||
dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n",
|
||||
__FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
|
||||
__func__, ioread32(I2C_REG_STS(alg_data)));
|
||||
|
||||
if (completed != num)
|
||||
return ((rc < 0) ? rc : -EREMOTEIO);
|
||||
|
@ -563,7 +563,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
|
|||
|
||||
if (!i2c_pnx || !i2c_pnx->adapter) {
|
||||
dev_err(&pdev->dev, "%s: no platform data supplied\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -697,6 +697,7 @@ static void __exit i2c_adap_pnx_exit(void)
|
|||
MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev <source@mvista.com>");
|
||||
MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:pnx-i2c");
|
||||
|
||||
/* We need to make sure I2C is initialized before USB */
|
||||
subsys_initcall(i2c_adap_pnx_init);
|
||||
|
|
|
@ -263,6 +263,9 @@ static int __devexit i2c_powermac_probe(struct platform_device *dev)
|
|||
}
|
||||
|
||||
|
||||
/* work with hotplug and coldplug */
|
||||
MODULE_ALIAS("platform:i2c-powermac");
|
||||
|
||||
static struct platform_driver i2c_powermac_driver = {
|
||||
.probe = i2c_powermac_probe,
|
||||
.remove = __devexit_p(i2c_powermac_remove),
|
||||
|
|
|
@ -155,7 +155,7 @@ static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
|
|||
readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
|
||||
}
|
||||
|
||||
#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __FUNCTION__)
|
||||
#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __func__)
|
||||
#else
|
||||
#define i2c_debug 0
|
||||
|
||||
|
@ -1132,6 +1132,7 @@ static void __exit i2c_adap_pxa_exit(void)
|
|||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:pxa2xx-i2c");
|
||||
|
||||
module_init(i2c_adap_pxa_init);
|
||||
module_exit(i2c_adap_pxa_exit);
|
||||
|
|
|
@ -276,12 +276,12 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
|
|||
switch (i2c->state) {
|
||||
|
||||
case STATE_IDLE:
|
||||
dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __FUNCTION__);
|
||||
dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
|
||||
goto out;
|
||||
break;
|
||||
|
||||
case STATE_STOP:
|
||||
dev_err(i2c->dev, "%s: called in STATE_STOP\n", __FUNCTION__);
|
||||
dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
|
||||
s3c24xx_i2c_disable_irq(i2c);
|
||||
goto out_ack;
|
||||
|
||||
|
@ -948,3 +948,4 @@ module_exit(i2c_adap_s3c_exit);
|
|||
MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
|
||||
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:s3c2410-i2c");
|
||||
|
|
|
@ -0,0 +1,577 @@
|
|||
/*
|
||||
* I2C bus driver for the SH7760 I2C Interfaces.
|
||||
*
|
||||
* (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
|
||||
*
|
||||
* licensed under the terms outlined in the file COPYING.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/clock.h>
|
||||
#include <asm/i2c-sh7760.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* register offsets */
|
||||
#define I2CSCR 0x0 /* slave ctrl */
|
||||
#define I2CMCR 0x4 /* master ctrl */
|
||||
#define I2CSSR 0x8 /* slave status */
|
||||
#define I2CMSR 0xC /* master status */
|
||||
#define I2CSIER 0x10 /* slave irq enable */
|
||||
#define I2CMIER 0x14 /* master irq enable */
|
||||
#define I2CCCR 0x18 /* clock dividers */
|
||||
#define I2CSAR 0x1c /* slave address */
|
||||
#define I2CMAR 0x20 /* master address */
|
||||
#define I2CRXTX 0x24 /* data port */
|
||||
#define I2CFCR 0x28 /* fifo control */
|
||||
#define I2CFSR 0x2C /* fifo status */
|
||||
#define I2CFIER 0x30 /* fifo irq enable */
|
||||
#define I2CRFDR 0x34 /* rx fifo count */
|
||||
#define I2CTFDR 0x38 /* tx fifo count */
|
||||
|
||||
#define REGSIZE 0x3C
|
||||
|
||||
#define MCR_MDBS 0x80 /* non-fifo mode switch */
|
||||
#define MCR_FSCL 0x40 /* override SCL pin */
|
||||
#define MCR_FSDA 0x20 /* override SDA pin */
|
||||
#define MCR_OBPC 0x10 /* override pins */
|
||||
#define MCR_MIE 0x08 /* master if enable */
|
||||
#define MCR_TSBE 0x04
|
||||
#define MCR_FSB 0x02 /* force stop bit */
|
||||
#define MCR_ESG 0x01 /* en startbit gen. */
|
||||
|
||||
#define MSR_MNR 0x40 /* nack received */
|
||||
#define MSR_MAL 0x20 /* arbitration lost */
|
||||
#define MSR_MST 0x10 /* sent a stop */
|
||||
#define MSR_MDE 0x08
|
||||
#define MSR_MDT 0x04
|
||||
#define MSR_MDR 0x02
|
||||
#define MSR_MAT 0x01 /* slave addr xfer done */
|
||||
|
||||
#define MIE_MNRE 0x40 /* nack irq en */
|
||||
#define MIE_MALE 0x20 /* arblos irq en */
|
||||
#define MIE_MSTE 0x10 /* stop irq en */
|
||||
#define MIE_MDEE 0x08
|
||||
#define MIE_MDTE 0x04
|
||||
#define MIE_MDRE 0x02
|
||||
#define MIE_MATE 0x01 /* address sent irq en */
|
||||
|
||||
#define FCR_RFRST 0x02 /* reset rx fifo */
|
||||
#define FCR_TFRST 0x01 /* reset tx fifo */
|
||||
|
||||
#define FSR_TEND 0x04 /* last byte sent */
|
||||
#define FSR_RDF 0x02 /* rx fifo trigger */
|
||||
#define FSR_TDFE 0x01 /* tx fifo empty */
|
||||
|
||||
#define FIER_TEIE 0x04 /* tx fifo empty irq en */
|
||||
#define FIER_RXIE 0x02 /* rx fifo trig irq en */
|
||||
#define FIER_TXIE 0x01 /* tx fifo trig irq en */
|
||||
|
||||
#define FIFO_SIZE 16
|
||||
|
||||
struct cami2c {
|
||||
void __iomem *iobase;
|
||||
struct i2c_adapter adap;
|
||||
|
||||
/* message processing */
|
||||
struct i2c_msg *msg;
|
||||
#define IDF_SEND 1
|
||||
#define IDF_RECV 2
|
||||
#define IDF_STOP 4
|
||||
int flags;
|
||||
|
||||
#define IDS_DONE 1
|
||||
#define IDS_ARBLOST 2
|
||||
#define IDS_NACK 4
|
||||
int status;
|
||||
struct completion xfer_done;
|
||||
|
||||
int irq;
|
||||
struct resource *ioarea;
|
||||
};
|
||||
|
||||
static inline void OUT32(struct cami2c *cam, int reg, unsigned long val)
|
||||
{
|
||||
ctrl_outl(val, (unsigned long)cam->iobase + reg);
|
||||
}
|
||||
|
||||
static inline unsigned long IN32(struct cami2c *cam, int reg)
|
||||
{
|
||||
return ctrl_inl((unsigned long)cam->iobase + reg);
|
||||
}
|
||||
|
||||
static irqreturn_t sh7760_i2c_irq(int irq, void *ptr)
|
||||
{
|
||||
struct cami2c *id = ptr;
|
||||
struct i2c_msg *msg = id->msg;
|
||||
char *data = msg->buf;
|
||||
unsigned long msr, fsr, fier, len;
|
||||
|
||||
msr = IN32(id, I2CMSR);
|
||||
fsr = IN32(id, I2CFSR);
|
||||
|
||||
/* arbitration lost */
|
||||
if (msr & MSR_MAL) {
|
||||
OUT32(id, I2CMCR, 0);
|
||||
OUT32(id, I2CSCR, 0);
|
||||
OUT32(id, I2CSAR, 0);
|
||||
id->status |= IDS_DONE | IDS_ARBLOST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (msr & MSR_MNR) {
|
||||
/* NACK handling is very screwed up. After receiving a
|
||||
* NAK IRQ one has to wait a bit before writing to any
|
||||
* registers, or the ctl will lock up. After that delay
|
||||
* do a normal i2c stop. Then wait at least 1 ms before
|
||||
* attempting another transfer or ctl will stop working
|
||||
*/
|
||||
udelay(100); /* wait or risk ctl hang */
|
||||
OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
|
||||
OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
|
||||
OUT32(id, I2CFIER, 0);
|
||||
OUT32(id, I2CMIER, MIE_MSTE);
|
||||
OUT32(id, I2CSCR, 0);
|
||||
OUT32(id, I2CSAR, 0);
|
||||
id->status |= IDS_NACK;
|
||||
msr &= ~MSR_MAT;
|
||||
fsr = 0;
|
||||
/* In some cases the MST bit is also set. */
|
||||
}
|
||||
|
||||
/* i2c-stop was sent */
|
||||
if (msr & MSR_MST) {
|
||||
id->status |= IDS_DONE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* i2c slave addr was sent; set to "normal" operation */
|
||||
if (msr & MSR_MAT)
|
||||
OUT32(id, I2CMCR, MCR_MIE);
|
||||
|
||||
fier = IN32(id, I2CFIER);
|
||||
|
||||
if (fsr & FSR_RDF) {
|
||||
len = IN32(id, I2CRFDR);
|
||||
if (msg->len <= len) {
|
||||
if (id->flags & IDF_STOP) {
|
||||
OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
|
||||
OUT32(id, I2CFIER, 0);
|
||||
/* manual says: wait >= 0.5 SCL times */
|
||||
udelay(5);
|
||||
/* next int should be MST */
|
||||
} else {
|
||||
id->status |= IDS_DONE;
|
||||
/* keep the RDF bit: ctrl holds SCL low
|
||||
* until the setup for the next i2c_msg
|
||||
* clears this bit.
|
||||
*/
|
||||
fsr &= ~FSR_RDF;
|
||||
}
|
||||
}
|
||||
while (msg->len && len) {
|
||||
*data++ = IN32(id, I2CRXTX);
|
||||
msg->len--;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (msg->len) {
|
||||
len = (msg->len >= FIFO_SIZE) ? FIFO_SIZE - 1
|
||||
: msg->len - 1;
|
||||
|
||||
OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xf) << 4));
|
||||
}
|
||||
|
||||
} else if (id->flags & IDF_SEND) {
|
||||
if ((fsr & FSR_TEND) && (msg->len < 1)) {
|
||||
if (id->flags & IDF_STOP) {
|
||||
OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
|
||||
} else {
|
||||
id->status |= IDS_DONE;
|
||||
/* keep the TEND bit: ctl holds SCL low
|
||||
* until the setup for the next i2c_msg
|
||||
* clears this bit.
|
||||
*/
|
||||
fsr &= ~FSR_TEND;
|
||||
}
|
||||
}
|
||||
if (fsr & FSR_TDFE) {
|
||||
while (msg->len && (IN32(id, I2CTFDR) < FIFO_SIZE)) {
|
||||
OUT32(id, I2CRXTX, *data++);
|
||||
msg->len--;
|
||||
}
|
||||
|
||||
if (msg->len < 1) {
|
||||
fier &= ~FIER_TXIE;
|
||||
OUT32(id, I2CFIER, fier);
|
||||
} else {
|
||||
len = (msg->len >= FIFO_SIZE) ? 2 : 0;
|
||||
OUT32(id, I2CFCR,
|
||||
FCR_RFRST | ((len & 3) << 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (id->status & IDS_DONE) {
|
||||
OUT32(id, I2CMIER, 0);
|
||||
OUT32(id, I2CFIER, 0);
|
||||
id->msg = NULL;
|
||||
complete(&id->xfer_done);
|
||||
}
|
||||
/* clear status flags and ctrl resumes work */
|
||||
OUT32(id, I2CMSR, ~msr);
|
||||
OUT32(id, I2CFSR, ~fsr);
|
||||
OUT32(id, I2CSSR, 0);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
/* prepare and start a master receive operation */
|
||||
static void sh7760_i2c_mrecv(struct cami2c *id)
|
||||
{
|
||||
int len;
|
||||
|
||||
id->flags |= IDF_RECV;
|
||||
|
||||
/* set the slave addr reg; otherwise rcv wont work! */
|
||||
OUT32(id, I2CSAR, 0xfe);
|
||||
OUT32(id, I2CMAR, (id->msg->addr << 1) | 1);
|
||||
|
||||
/* adjust rx fifo trigger */
|
||||
if (id->msg->len >= FIFO_SIZE)
|
||||
len = FIFO_SIZE - 1; /* trigger at fifo full */
|
||||
else
|
||||
len = id->msg->len - 1; /* trigger before all received */
|
||||
|
||||
OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
|
||||
OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xF) << 4));
|
||||
|
||||
OUT32(id, I2CMSR, 0);
|
||||
OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
|
||||
OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
|
||||
OUT32(id, I2CFIER, FIER_RXIE);
|
||||
}
|
||||
|
||||
/* prepare and start a master send operation */
|
||||
static void sh7760_i2c_msend(struct cami2c *id)
|
||||
{
|
||||
int len;
|
||||
|
||||
id->flags |= IDF_SEND;
|
||||
|
||||
/* set the slave addr reg; otherwise xmit wont work! */
|
||||
OUT32(id, I2CSAR, 0xfe);
|
||||
OUT32(id, I2CMAR, (id->msg->addr << 1) | 0);
|
||||
|
||||
/* adjust tx fifo trigger */
|
||||
if (id->msg->len >= FIFO_SIZE)
|
||||
len = 2; /* trig: 2 bytes left in TX fifo */
|
||||
else
|
||||
len = 0; /* trig: 8 bytes left in TX fifo */
|
||||
|
||||
OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
|
||||
OUT32(id, I2CFCR, FCR_RFRST | ((len & 3) << 2));
|
||||
|
||||
while (id->msg->len && IN32(id, I2CTFDR) < FIFO_SIZE) {
|
||||
OUT32(id, I2CRXTX, *(id->msg->buf));
|
||||
(id->msg->len)--;
|
||||
(id->msg->buf)++;
|
||||
}
|
||||
|
||||
OUT32(id, I2CMSR, 0);
|
||||
OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
|
||||
OUT32(id, I2CFSR, 0);
|
||||
OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
|
||||
OUT32(id, I2CFIER, FIER_TEIE | (id->msg->len ? FIER_TXIE : 0));
|
||||
}
|
||||
|
||||
static inline int sh7760_i2c_busy_check(struct cami2c *id)
|
||||
{
|
||||
return (IN32(id, I2CMCR) & MCR_FSDA);
|
||||
}
|
||||
|
||||
static int sh7760_i2c_master_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct cami2c *id = adap->algo_data;
|
||||
int i, retr;
|
||||
|
||||
if (sh7760_i2c_busy_check(id)) {
|
||||
dev_err(&adap->dev, "sh7760-i2c%d: bus busy!\n", adap->nr);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < num) {
|
||||
retr = adap->retries;
|
||||
retry:
|
||||
id->flags = ((i == (num-1)) ? IDF_STOP : 0);
|
||||
id->status = 0;
|
||||
id->msg = msgs;
|
||||
init_completion(&id->xfer_done);
|
||||
|
||||
if (msgs->flags & I2C_M_RD)
|
||||
sh7760_i2c_mrecv(id);
|
||||
else
|
||||
sh7760_i2c_msend(id);
|
||||
|
||||
wait_for_completion(&id->xfer_done);
|
||||
|
||||
if (id->status == 0) {
|
||||
num = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (id->status & IDS_NACK) {
|
||||
/* wait a bit or i2c module stops working */
|
||||
mdelay(1);
|
||||
num = -EREMOTEIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (id->status & IDS_ARBLOST) {
|
||||
if (retr--) {
|
||||
mdelay(2);
|
||||
goto retry;
|
||||
}
|
||||
num = -EREMOTEIO;
|
||||
break;
|
||||
}
|
||||
|
||||
msgs++;
|
||||
i++;
|
||||
}
|
||||
|
||||
id->msg = NULL;
|
||||
id->flags = 0;
|
||||
id->status = 0;
|
||||
|
||||
OUT32(id, I2CMCR, 0);
|
||||
OUT32(id, I2CMSR, 0);
|
||||
OUT32(id, I2CMIER, 0);
|
||||
OUT32(id, I2CFIER, 0);
|
||||
|
||||
/* reset slave module registers too: master mode enables slave
|
||||
* module for receive ops (ack, data). Without this reset,
|
||||
* eternal bus activity might be reported after NACK / ARBLOST.
|
||||
*/
|
||||
OUT32(id, I2CSCR, 0);
|
||||
OUT32(id, I2CSAR, 0);
|
||||
OUT32(id, I2CSSR, 0);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 sh7760_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm sh7760_i2c_algo = {
|
||||
.master_xfer = sh7760_i2c_master_xfer,
|
||||
.functionality = sh7760_i2c_func,
|
||||
};
|
||||
|
||||
/* calculate CCR register setting for a desired scl clock. SCL clock is
|
||||
* derived from I2C module clock (iclk) which in turn is derived from
|
||||
* peripheral module clock (mclk, usually around 33MHz):
|
||||
* iclk = mclk/(CDF + 1). iclk must be < 20MHz.
|
||||
* scl = iclk/(SCGD*8 + 20).
|
||||
*/
|
||||
static int __devinit calc_CCR(unsigned long scl_hz)
|
||||
{
|
||||
struct clk *mclk;
|
||||
unsigned long mck, m1, dff, odff, iclk;
|
||||
signed char cdf, cdfm;
|
||||
int scgd, scgdm, scgds;
|
||||
|
||||
mclk = clk_get(NULL, "module_clk");
|
||||
if (IS_ERR(mclk)) {
|
||||
return PTR_ERR(mclk);
|
||||
} else {
|
||||
mck = mclk->rate;
|
||||
clk_put(mclk);
|
||||
}
|
||||
|
||||
odff = scl_hz;
|
||||
scgdm = cdfm = m1 = 0;
|
||||
for (cdf = 3; cdf >= 0; cdf--) {
|
||||
iclk = mck / (1 + cdf);
|
||||
if (iclk >= 20000000)
|
||||
continue;
|
||||
scgds = ((iclk / scl_hz) - 20) >> 3;
|
||||
for (scgd = scgds; (scgd < 63) && scgd <= scgds + 1; scgd++) {
|
||||
m1 = iclk / (20 + (scgd << 3));
|
||||
dff = abs(scl_hz - m1);
|
||||
if (dff < odff) {
|
||||
odff = dff;
|
||||
cdfm = cdf;
|
||||
scgdm = scgd;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* fail if more than 25% off of requested SCL */
|
||||
if (odff > (scl_hz >> 2))
|
||||
return -EINVAL;
|
||||
|
||||
/* create a CCR register value */
|
||||
return ((scgdm << 2) | cdfm);
|
||||
}
|
||||
|
||||
static int __devinit sh7760_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sh7760_i2c_platdata *pd;
|
||||
struct resource *res;
|
||||
struct cami2c *id;
|
||||
int ret;
|
||||
|
||||
pd = pdev->dev.platform_data;
|
||||
if (!pd) {
|
||||
dev_err(&pdev->dev, "no platform_data!\n");
|
||||
ret = -ENODEV;
|
||||
goto out0;
|
||||
}
|
||||
|
||||
id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
|
||||
if (!id) {
|
||||
dev_err(&pdev->dev, "no mem for private data\n");
|
||||
ret = -ENOMEM;
|
||||
goto out0;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "no mmio resources\n");
|
||||
ret = -ENODEV;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
id->ioarea = request_mem_region(res->start, REGSIZE, pdev->name);
|
||||
if (!id->ioarea) {
|
||||
dev_err(&pdev->dev, "mmio already reserved\n");
|
||||
ret = -EBUSY;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
id->iobase = ioremap(res->start, REGSIZE);
|
||||
if (!id->iobase) {
|
||||
dev_err(&pdev->dev, "cannot ioremap\n");
|
||||
ret = -ENODEV;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
id->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
id->adap.nr = pdev->id;
|
||||
id->adap.algo = &sh7760_i2c_algo;
|
||||
id->adap.class = I2C_CLASS_ALL;
|
||||
id->adap.retries = 3;
|
||||
id->adap.algo_data = id;
|
||||
id->adap.dev.parent = &pdev->dev;
|
||||
snprintf(id->adap.name, sizeof(id->adap.name),
|
||||
"SH7760 I2C at %08lx", (unsigned long)res->start);
|
||||
|
||||
OUT32(id, I2CMCR, 0);
|
||||
OUT32(id, I2CMSR, 0);
|
||||
OUT32(id, I2CMIER, 0);
|
||||
OUT32(id, I2CMAR, 0);
|
||||
OUT32(id, I2CSIER, 0);
|
||||
OUT32(id, I2CSAR, 0);
|
||||
OUT32(id, I2CSCR, 0);
|
||||
OUT32(id, I2CSSR, 0);
|
||||
OUT32(id, I2CFIER, 0);
|
||||
OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
|
||||
OUT32(id, I2CFSR, 0);
|
||||
|
||||
ret = calc_CCR(pd->speed_khz * 1000);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "invalid SCL clock: %dkHz\n",
|
||||
pd->speed_khz);
|
||||
goto out3;
|
||||
}
|
||||
OUT32(id, I2CCCR, ret);
|
||||
|
||||
if (request_irq(id->irq, sh7760_i2c_irq, IRQF_DISABLED,
|
||||
SH7760_I2C_DEVNAME, id)) {
|
||||
dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
|
||||
ret = -EBUSY;
|
||||
goto out3;
|
||||
}
|
||||
|
||||
ret = i2c_add_numbered_adapter(&id->adap);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "reg adap failed: %d\n", ret);
|
||||
goto out4;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, id);
|
||||
|
||||
dev_info(&pdev->dev, "%d kHz mmio %08x irq %d\n",
|
||||
pd->speed_khz, res->start, id->irq);
|
||||
|
||||
return 0;
|
||||
|
||||
out4:
|
||||
free_irq(id->irq, id);
|
||||
out3:
|
||||
iounmap(id->iobase);
|
||||
out2:
|
||||
release_resource(id->ioarea);
|
||||
kfree(id->ioarea);
|
||||
out1:
|
||||
kfree(id);
|
||||
out0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit sh7760_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cami2c *id = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_del_adapter(&id->adap);
|
||||
free_irq(id->irq, id);
|
||||
iounmap(id->iobase);
|
||||
release_resource(id->ioarea);
|
||||
kfree(id->ioarea);
|
||||
kfree(id);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver sh7760_i2c_drv = {
|
||||
.driver = {
|
||||
.name = SH7760_I2C_DEVNAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = sh7760_i2c_probe,
|
||||
.remove = __devexit_p(sh7760_i2c_remove),
|
||||
};
|
||||
|
||||
static int __init sh7760_i2c_init(void)
|
||||
{
|
||||
return platform_driver_register(&sh7760_i2c_drv);
|
||||
}
|
||||
|
||||
static void __exit sh7760_i2c_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&sh7760_i2c_drv);
|
||||
}
|
||||
|
||||
module_init(sh7760_i2c_init);
|
||||
module_exit(sh7760_i2c_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("SH7760 I2C bus driver");
|
||||
MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* SuperH Mobile I2C Controller
|
||||
*
|
||||
* Copyright (C) 2008 Magnus Damm
|
||||
*
|
||||
* Portions of the code based on out-of-tree driver i2c-sh7343.c
|
||||
* Copyright (c) 2006 Carlos Munoz <carlos@kenati.com>
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
enum sh_mobile_i2c_op {
|
||||
OP_START = 0,
|
||||
OP_TX_ONLY,
|
||||
OP_TX_STOP,
|
||||
OP_TX_TO_RX,
|
||||
OP_RX_ONLY,
|
||||
OP_RX_STOP,
|
||||
};
|
||||
|
||||
struct sh_mobile_i2c_data {
|
||||
struct device *dev;
|
||||
void __iomem *reg;
|
||||
struct i2c_adapter adap;
|
||||
|
||||
struct clk *clk;
|
||||
u_int8_t iccl;
|
||||
u_int8_t icch;
|
||||
|
||||
spinlock_t lock;
|
||||
wait_queue_head_t wait;
|
||||
struct i2c_msg *msg;
|
||||
int pos;
|
||||
int sr;
|
||||
};
|
||||
|
||||
#define NORMAL_SPEED 100000 /* FAST_SPEED 400000 */
|
||||
|
||||
/* Register offsets */
|
||||
#define ICDR(pd) (pd->reg + 0x00)
|
||||
#define ICCR(pd) (pd->reg + 0x04)
|
||||
#define ICSR(pd) (pd->reg + 0x08)
|
||||
#define ICIC(pd) (pd->reg + 0x0c)
|
||||
#define ICCL(pd) (pd->reg + 0x10)
|
||||
#define ICCH(pd) (pd->reg + 0x14)
|
||||
|
||||
/* Register bits */
|
||||
#define ICCR_ICE 0x80
|
||||
#define ICCR_RACK 0x40
|
||||
#define ICCR_TRS 0x10
|
||||
#define ICCR_BBSY 0x04
|
||||
#define ICCR_SCP 0x01
|
||||
|
||||
#define ICSR_SCLM 0x80
|
||||
#define ICSR_SDAM 0x40
|
||||
#define SW_DONE 0x20
|
||||
#define ICSR_BUSY 0x10
|
||||
#define ICSR_AL 0x08
|
||||
#define ICSR_TACK 0x04
|
||||
#define ICSR_WAIT 0x02
|
||||
#define ICSR_DTE 0x01
|
||||
|
||||
#define ICIC_ALE 0x08
|
||||
#define ICIC_TACKE 0x04
|
||||
#define ICIC_WAITE 0x02
|
||||
#define ICIC_DTEE 0x01
|
||||
|
||||
static void activate_ch(struct sh_mobile_i2c_data *pd)
|
||||
{
|
||||
/* Make sure the clock is enabled */
|
||||
clk_enable(pd->clk);
|
||||
|
||||
/* Enable channel and configure rx ack */
|
||||
iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd));
|
||||
|
||||
/* Mask all interrupts */
|
||||
iowrite8(0, ICIC(pd));
|
||||
|
||||
/* Set the clock */
|
||||
iowrite8(pd->iccl, ICCL(pd));
|
||||
iowrite8(pd->icch, ICCH(pd));
|
||||
}
|
||||
|
||||
static void deactivate_ch(struct sh_mobile_i2c_data *pd)
|
||||
{
|
||||
/* Clear/disable interrupts */
|
||||
iowrite8(0, ICSR(pd));
|
||||
iowrite8(0, ICIC(pd));
|
||||
|
||||
/* Disable channel */
|
||||
iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd));
|
||||
|
||||
/* Disable clock */
|
||||
clk_disable(pd->clk);
|
||||
}
|
||||
|
||||
static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
|
||||
enum sh_mobile_i2c_op op, unsigned char data)
|
||||
{
|
||||
unsigned char ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(pd->dev, "op %d, data in 0x%02x\n", op, data);
|
||||
|
||||
spin_lock_irqsave(&pd->lock, flags);
|
||||
|
||||
switch (op) {
|
||||
case OP_START:
|
||||
iowrite8(0x94, ICCR(pd));
|
||||
break;
|
||||
case OP_TX_ONLY:
|
||||
iowrite8(data, ICDR(pd));
|
||||
break;
|
||||
case OP_TX_STOP:
|
||||
iowrite8(data, ICDR(pd));
|
||||
iowrite8(0x90, ICCR(pd));
|
||||
iowrite8(ICIC_ALE | ICIC_TACKE, ICIC(pd));
|
||||
break;
|
||||
case OP_TX_TO_RX:
|
||||
iowrite8(data, ICDR(pd));
|
||||
iowrite8(0x81, ICCR(pd));
|
||||
break;
|
||||
case OP_RX_ONLY:
|
||||
ret = ioread8(ICDR(pd));
|
||||
break;
|
||||
case OP_RX_STOP:
|
||||
ret = ioread8(ICDR(pd));
|
||||
iowrite8(0xc0, ICCR(pd));
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&pd->lock, flags);
|
||||
|
||||
dev_dbg(pd->dev, "op %d, data out 0x%02x\n", op, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct platform_device *dev = dev_id;
|
||||
struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
|
||||
struct i2c_msg *msg = pd->msg;
|
||||
unsigned char data, sr;
|
||||
int wakeup = 0;
|
||||
|
||||
sr = ioread8(ICSR(pd));
|
||||
pd->sr |= sr;
|
||||
|
||||
dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
|
||||
(msg->flags & I2C_M_RD) ? "read" : "write",
|
||||
pd->pos, msg->len);
|
||||
|
||||
if (sr & (ICSR_AL | ICSR_TACK)) {
|
||||
iowrite8(0, ICIC(pd)); /* disable interrupts */
|
||||
wakeup = 1;
|
||||
goto do_wakeup;
|
||||
}
|
||||
|
||||
if (pd->pos == msg->len) {
|
||||
i2c_op(pd, OP_RX_ONLY, 0);
|
||||
wakeup = 1;
|
||||
goto do_wakeup;
|
||||
}
|
||||
|
||||
if (pd->pos == -1) {
|
||||
data = (msg->addr & 0x7f) << 1;
|
||||
data |= (msg->flags & I2C_M_RD) ? 1 : 0;
|
||||
} else
|
||||
data = msg->buf[pd->pos];
|
||||
|
||||
if ((pd->pos == -1) || !(msg->flags & I2C_M_RD)) {
|
||||
if (msg->flags & I2C_M_RD)
|
||||
i2c_op(pd, OP_TX_TO_RX, data);
|
||||
else if (pd->pos == (msg->len - 1)) {
|
||||
i2c_op(pd, OP_TX_STOP, data);
|
||||
wakeup = 1;
|
||||
} else
|
||||
i2c_op(pd, OP_TX_ONLY, data);
|
||||
} else {
|
||||
if (pd->pos == (msg->len - 1))
|
||||
data = i2c_op(pd, OP_RX_STOP, 0);
|
||||
else
|
||||
data = i2c_op(pd, OP_RX_ONLY, 0);
|
||||
|
||||
msg->buf[pd->pos] = data;
|
||||
}
|
||||
pd->pos++;
|
||||
|
||||
do_wakeup:
|
||||
if (wakeup) {
|
||||
pd->sr |= SW_DONE;
|
||||
wake_up(&pd->wait);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
|
||||
{
|
||||
/* Initialize channel registers */
|
||||
iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd));
|
||||
|
||||
/* Enable channel and configure rx ack */
|
||||
iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd));
|
||||
|
||||
/* Set the clock */
|
||||
iowrite8(pd->iccl, ICCL(pd));
|
||||
iowrite8(pd->icch, ICCH(pd));
|
||||
|
||||
pd->msg = usr_msg;
|
||||
pd->pos = -1;
|
||||
pd->sr = 0;
|
||||
|
||||
/* Enable all interrupts except wait */
|
||||
iowrite8(ioread8(ICIC(pd)) | ICIC_ALE | ICIC_TACKE | ICIC_DTEE,
|
||||
ICIC(pd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
|
||||
struct i2c_msg *msg;
|
||||
int err = 0;
|
||||
u_int8_t val;
|
||||
int i, k, retry_count;
|
||||
|
||||
activate_ch(pd);
|
||||
|
||||
/* Process all messages */
|
||||
for (i = 0; i < num; i++) {
|
||||
msg = &msgs[i];
|
||||
|
||||
err = start_ch(pd, msg);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
i2c_op(pd, OP_START, 0);
|
||||
|
||||
/* The interrupt handler takes care of the rest... */
|
||||
k = wait_event_timeout(pd->wait,
|
||||
pd->sr & (ICSR_TACK | SW_DONE),
|
||||
5 * HZ);
|
||||
if (!k)
|
||||
dev_err(pd->dev, "Transfer request timed out\n");
|
||||
|
||||
retry_count = 10;
|
||||
again:
|
||||
val = ioread8(ICSR(pd));
|
||||
|
||||
dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr);
|
||||
|
||||
if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
|
||||
err = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* the interrupt handler may wake us up before the
|
||||
* transfer is finished, so poll the hardware
|
||||
* until we're done.
|
||||
*/
|
||||
|
||||
if (!(!(val & ICSR_BUSY) && (val & ICSR_SCLM) &&
|
||||
(val & ICSR_SDAM))) {
|
||||
msleep(1);
|
||||
if (retry_count--)
|
||||
goto again;
|
||||
|
||||
err = -EIO;
|
||||
dev_err(pd->dev, "Polling timed out\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
deactivate_ch(pd);
|
||||
|
||||
if (!err)
|
||||
err = num;
|
||||
return err;
|
||||
}
|
||||
|
||||
static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm sh_mobile_i2c_algorithm = {
|
||||
.functionality = sh_mobile_i2c_func,
|
||||
.master_xfer = sh_mobile_i2c_xfer,
|
||||
};
|
||||
|
||||
static void sh_mobile_i2c_setup_channel(struct platform_device *dev)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
|
||||
unsigned long peripheral_clk = clk_get_rate(pd->clk);
|
||||
u_int32_t num;
|
||||
u_int32_t denom;
|
||||
u_int32_t tmp;
|
||||
|
||||
spin_lock_init(&pd->lock);
|
||||
init_waitqueue_head(&pd->wait);
|
||||
|
||||
/* Calculate the value for iccl. From the data sheet:
|
||||
* iccl = (p clock / transfer rate) * (L / (L + H))
|
||||
* where L and H are the SCL low/high ratio (5/4 in this case).
|
||||
* We also round off the result.
|
||||
*/
|
||||
num = peripheral_clk * 5;
|
||||
denom = NORMAL_SPEED * 9;
|
||||
tmp = num * 10 / denom;
|
||||
if (tmp % 10 >= 5)
|
||||
pd->iccl = (u_int8_t)((num/denom) + 1);
|
||||
else
|
||||
pd->iccl = (u_int8_t)(num/denom);
|
||||
|
||||
/* Calculate the value for icch. From the data sheet:
|
||||
icch = (p clock / transfer rate) * (H / (L + H)) */
|
||||
num = peripheral_clk * 4;
|
||||
tmp = num * 10 / denom;
|
||||
if (tmp % 10 >= 5)
|
||||
pd->icch = (u_int8_t)((num/denom) + 1);
|
||||
else
|
||||
pd->icch = (u_int8_t)(num/denom);
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
|
||||
{
|
||||
struct resource *res;
|
||||
int ret = -ENXIO;
|
||||
int q, m;
|
||||
int k = 0;
|
||||
int n = 0;
|
||||
|
||||
while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
|
||||
for (n = res->start; hook && n <= res->end; n++) {
|
||||
if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED,
|
||||
dev->dev.bus_id, dev))
|
||||
goto rollback;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
if (hook)
|
||||
return k > 0 ? 0 : -ENOENT;
|
||||
|
||||
k--;
|
||||
ret = 0;
|
||||
|
||||
rollback:
|
||||
for (q = k; k >= 0; k--) {
|
||||
for (m = n; m >= res->start; m--)
|
||||
free_irq(m, dev);
|
||||
|
||||
res = platform_get_resource(dev, IORESOURCE_IRQ, k - 1);
|
||||
m = res->end;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_probe(struct platform_device *dev)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd;
|
||||
struct i2c_adapter *adap;
|
||||
struct resource *res;
|
||||
int size;
|
||||
int ret;
|
||||
|
||||
pd = kzalloc(sizeof(struct sh_mobile_i2c_data), GFP_KERNEL);
|
||||
if (pd == NULL) {
|
||||
dev_err(&dev->dev, "cannot allocate private data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pd->clk = clk_get(&dev->dev, "peripheral_clk");
|
||||
if (IS_ERR(pd->clk)) {
|
||||
dev_err(&dev->dev, "cannot get peripheral clock\n");
|
||||
ret = PTR_ERR(pd->clk);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = sh_mobile_i2c_hook_irqs(dev, 1);
|
||||
if (ret) {
|
||||
dev_err(&dev->dev, "cannot request IRQ\n");
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
pd->dev = &dev->dev;
|
||||
platform_set_drvdata(dev, pd);
|
||||
|
||||
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&dev->dev, "cannot find IO resource\n");
|
||||
ret = -ENOENT;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
size = (res->end - res->start) + 1;
|
||||
|
||||
pd->reg = ioremap(res->start, size);
|
||||
if (pd->reg == NULL) {
|
||||
dev_err(&dev->dev, "cannot map IO\n");
|
||||
ret = -ENXIO;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
/* setup the private data */
|
||||
adap = &pd->adap;
|
||||
i2c_set_adapdata(adap, pd);
|
||||
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->algo = &sh_mobile_i2c_algorithm;
|
||||
adap->dev.parent = &dev->dev;
|
||||
adap->retries = 5;
|
||||
adap->nr = dev->id;
|
||||
|
||||
strlcpy(adap->name, dev->name, sizeof(adap->name));
|
||||
|
||||
sh_mobile_i2c_setup_channel(dev);
|
||||
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
if (ret < 0) {
|
||||
dev_err(&dev->dev, "cannot add numbered adapter\n");
|
||||
goto err_all;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_all:
|
||||
iounmap(pd->reg);
|
||||
err_irq:
|
||||
sh_mobile_i2c_hook_irqs(dev, 0);
|
||||
err_clk:
|
||||
clk_put(pd->clk);
|
||||
err:
|
||||
kfree(pd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_remove(struct platform_device *dev)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
|
||||
|
||||
i2c_del_adapter(&pd->adap);
|
||||
iounmap(pd->reg);
|
||||
sh_mobile_i2c_hook_irqs(dev, 0);
|
||||
clk_put(pd->clk);
|
||||
kfree(pd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver sh_mobile_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "i2c-sh_mobile",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = sh_mobile_i2c_probe,
|
||||
.remove = sh_mobile_i2c_remove,
|
||||
};
|
||||
|
||||
static int __init sh_mobile_i2c_adap_init(void)
|
||||
{
|
||||
return platform_driver_register(&sh_mobile_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit sh_mobile_i2c_adap_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&sh_mobile_i2c_driver);
|
||||
}
|
||||
|
||||
module_init(sh_mobile_i2c_adap_init);
|
||||
module_exit(sh_mobile_i2c_adap_exit);
|
||||
|
||||
MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");
|
||||
MODULE_AUTHOR("Magnus Damm");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -159,6 +159,9 @@ static int simtec_i2c_remove(struct platform_device *dev)
|
|||
|
||||
/* device driver */
|
||||
|
||||
/* work with hotplug and coldplug */
|
||||
MODULE_ALIAS("platform:simtec-i2c");
|
||||
|
||||
static struct platform_driver simtec_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "simtec-i2c",
|
||||
|
|
|
@ -151,3 +151,4 @@ module_exit(i2c_versatile_exit);
|
|||
|
||||
MODULE_DESCRIPTION("ARM Versatile I2C bus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:versatile-i2c");
|
||||
|
|
|
@ -527,7 +527,7 @@ static int __init scx200_create_isa(const char *text, unsigned long base,
|
|||
if (iface == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (request_region(base, 8, iface->adapter.name) == 0) {
|
||||
if (!request_region(base, 8, iface->adapter.name)) {
|
||||
printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
|
||||
base, base + 8 - 1);
|
||||
rc = -EBUSY;
|
||||
|
|
|
@ -658,7 +658,7 @@ pulldown:
|
|||
OTG_CTRL_REG |= OTG_PULLUP;
|
||||
}
|
||||
|
||||
check_state(isp, __FUNCTION__);
|
||||
check_state(isp, __func__);
|
||||
dump_regs(isp, "otg->isp1301");
|
||||
}
|
||||
|
||||
|
@ -782,7 +782,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
|
|||
if (otg_ctrl & OTG_DRIVER_SEL) {
|
||||
switch (isp->otg.state) {
|
||||
case OTG_STATE_A_IDLE:
|
||||
b_idle(isp, __FUNCTION__);
|
||||
b_idle(isp, __func__);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -826,7 +826,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
|
|||
isp->otg.host->otg_port);
|
||||
}
|
||||
|
||||
check_state(isp, __FUNCTION__);
|
||||
check_state(isp, __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -837,7 +837,7 @@ static int otg_init(struct isp1301 *isp)
|
|||
if (!otg_dev)
|
||||
return -ENODEV;
|
||||
|
||||
dump_regs(isp, __FUNCTION__);
|
||||
dump_regs(isp, __func__);
|
||||
/* some of these values are board-specific... */
|
||||
OTG_SYSCON_2_REG |= OTG_EN
|
||||
/* for B-device: */
|
||||
|
@ -853,9 +853,9 @@ static int otg_init(struct isp1301 *isp)
|
|||
update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE));
|
||||
update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));
|
||||
|
||||
check_state(isp, __FUNCTION__);
|
||||
check_state(isp, __func__);
|
||||
pr_debug("otg: %s, %s %06x\n",
|
||||
state_name(isp), __FUNCTION__, OTG_CTRL_REG);
|
||||
state_name(isp), __func__, OTG_CTRL_REG);
|
||||
|
||||
OTG_IRQ_EN_REG = DRIVER_SWITCH | OPRT_CHG
|
||||
| B_SRP_TMROUT | B_HNP_FAIL
|
||||
|
@ -1041,11 +1041,11 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
|
|||
OTG1_DP_PULLDOWN);
|
||||
isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1,
|
||||
OTG1_DP_PULLUP);
|
||||
dump_regs(isp, __FUNCTION__);
|
||||
dump_regs(isp, __func__);
|
||||
#endif
|
||||
/* FALLTHROUGH */
|
||||
case OTG_STATE_B_SRP_INIT:
|
||||
b_idle(isp, __FUNCTION__);
|
||||
b_idle(isp, __func__);
|
||||
OTG_CTRL_REG &= OTG_CTRL_REG & OTG_XCEIV_OUTPUTS;
|
||||
/* FALLTHROUGH */
|
||||
case OTG_STATE_B_IDLE:
|
||||
|
@ -1077,7 +1077,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
|
|||
*/
|
||||
update_otg1(isp, isp_stat);
|
||||
update_otg2(isp, isp_bstat);
|
||||
check_state(isp, __FUNCTION__);
|
||||
check_state(isp, __func__);
|
||||
#endif
|
||||
|
||||
dump_regs(isp, "isp1301->otg");
|
||||
|
@ -1310,7 +1310,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
|
|||
*/
|
||||
isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV);
|
||||
|
||||
dump_regs(isp, __FUNCTION__);
|
||||
dump_regs(isp, __func__);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -1365,7 +1365,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
|
|||
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
|
||||
INTR_VBUS_VLD);
|
||||
dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
|
||||
dump_regs(isp, __FUNCTION__);
|
||||
dump_regs(isp, __func__);
|
||||
|
||||
/* If this has a Mini-AB connector, this mode is highly
|
||||
* nonstandard ... but can be handy for testing, so long
|
||||
|
@ -1416,7 +1416,7 @@ isp1301_start_srp(struct otg_transceiver *dev)
|
|||
|
||||
pr_debug("otg: SRP, %s ... %06x\n", state_name(isp), OTG_CTRL_REG);
|
||||
#ifdef CONFIG_USB_OTG
|
||||
check_state(isp, __FUNCTION__);
|
||||
check_state(isp, __func__);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -1463,7 +1463,7 @@ isp1301_start_hnp(struct otg_transceiver *dev)
|
|||
}
|
||||
pr_debug("otg: HNP %s, %06x ...\n",
|
||||
state_name(isp), OTG_CTRL_REG);
|
||||
check_state(isp, __FUNCTION__);
|
||||
check_state(isp, __func__);
|
||||
return 0;
|
||||
#else
|
||||
/* srp-only */
|
||||
|
@ -1601,7 +1601,7 @@ fail2:
|
|||
update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));
|
||||
#endif
|
||||
|
||||
dump_regs(isp, __FUNCTION__);
|
||||
dump_regs(isp, __func__);
|
||||
|
||||
#ifdef VERBOSE
|
||||
mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
|
||||
|
|
|
@ -1506,7 +1506,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
|
|||
read_write = I2C_SMBUS_READ;
|
||||
if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
|
||||
dev_err(&adapter->dev, "%s called with invalid "
|
||||
"block proc call size (%d)\n", __FUNCTION__,
|
||||
"block proc call size (%d)\n", __func__,
|
||||
data->block[0]);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -200,16 +200,176 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
|
|||
return device_for_each_child(&adapter->dev, &addr, i2cdev_check);
|
||||
}
|
||||
|
||||
static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct i2c_rdwr_ioctl_data rdwr_arg;
|
||||
struct i2c_msg *rdwr_pa;
|
||||
u8 __user **data_ptrs;
|
||||
int i, res;
|
||||
|
||||
if (copy_from_user(&rdwr_arg,
|
||||
(struct i2c_rdwr_ioctl_data __user *)arg,
|
||||
sizeof(rdwr_arg)))
|
||||
return -EFAULT;
|
||||
|
||||
/* Put an arbitrary limit on the number of messages that can
|
||||
* be sent at once */
|
||||
if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
|
||||
return -EINVAL;
|
||||
|
||||
rdwr_pa = (struct i2c_msg *)
|
||||
kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
|
||||
GFP_KERNEL);
|
||||
if (!rdwr_pa)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
|
||||
rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
|
||||
kfree(rdwr_pa);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
|
||||
if (data_ptrs == NULL) {
|
||||
kfree(rdwr_pa);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
for (i = 0; i < rdwr_arg.nmsgs; i++) {
|
||||
/* Limit the size of the message to a sane amount;
|
||||
* and don't let length change either. */
|
||||
if ((rdwr_pa[i].len > 8192) ||
|
||||
(rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
|
||||
rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
|
||||
if (rdwr_pa[i].buf == NULL) {
|
||||
res = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i],
|
||||
rdwr_pa[i].len)) {
|
||||
++i; /* Needs to be kfreed too */
|
||||
res = -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res < 0) {
|
||||
int j;
|
||||
for (j = 0; j < i; ++j)
|
||||
kfree(rdwr_pa[j].buf);
|
||||
kfree(data_ptrs);
|
||||
kfree(rdwr_pa);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
|
||||
while (i-- > 0) {
|
||||
if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
|
||||
if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
|
||||
rdwr_pa[i].len))
|
||||
res = -EFAULT;
|
||||
}
|
||||
kfree(rdwr_pa[i].buf);
|
||||
}
|
||||
kfree(data_ptrs);
|
||||
kfree(rdwr_pa);
|
||||
return res;
|
||||
}
|
||||
|
||||
static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct i2c_smbus_ioctl_data data_arg;
|
||||
union i2c_smbus_data temp;
|
||||
int datasize, res;
|
||||
|
||||
if (copy_from_user(&data_arg,
|
||||
(struct i2c_smbus_ioctl_data __user *) arg,
|
||||
sizeof(struct i2c_smbus_ioctl_data)))
|
||||
return -EFAULT;
|
||||
if ((data_arg.size != I2C_SMBUS_BYTE) &&
|
||||
(data_arg.size != I2C_SMBUS_QUICK) &&
|
||||
(data_arg.size != I2C_SMBUS_BYTE_DATA) &&
|
||||
(data_arg.size != I2C_SMBUS_WORD_DATA) &&
|
||||
(data_arg.size != I2C_SMBUS_PROC_CALL) &&
|
||||
(data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
|
||||
(data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
|
||||
(data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
|
||||
(data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
|
||||
dev_dbg(&client->adapter->dev,
|
||||
"size out of range (%x) in ioctl I2C_SMBUS.\n",
|
||||
data_arg.size);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
|
||||
so the check is valid if size==I2C_SMBUS_QUICK too. */
|
||||
if ((data_arg.read_write != I2C_SMBUS_READ) &&
|
||||
(data_arg.read_write != I2C_SMBUS_WRITE)) {
|
||||
dev_dbg(&client->adapter->dev,
|
||||
"read_write out of range (%x) in ioctl I2C_SMBUS.\n",
|
||||
data_arg.read_write);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Note that command values are always valid! */
|
||||
|
||||
if ((data_arg.size == I2C_SMBUS_QUICK) ||
|
||||
((data_arg.size == I2C_SMBUS_BYTE) &&
|
||||
(data_arg.read_write == I2C_SMBUS_WRITE)))
|
||||
/* These are special: we do not use data */
|
||||
return i2c_smbus_xfer(client->adapter, client->addr,
|
||||
client->flags, data_arg.read_write,
|
||||
data_arg.command, data_arg.size, NULL);
|
||||
|
||||
if (data_arg.data == NULL) {
|
||||
dev_dbg(&client->adapter->dev,
|
||||
"data is NULL pointer in ioctl I2C_SMBUS.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
|
||||
(data_arg.size == I2C_SMBUS_BYTE))
|
||||
datasize = sizeof(data_arg.data->byte);
|
||||
else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
|
||||
(data_arg.size == I2C_SMBUS_PROC_CALL))
|
||||
datasize = sizeof(data_arg.data->word);
|
||||
else /* size == smbus block, i2c block, or block proc. call */
|
||||
datasize = sizeof(data_arg.data->block);
|
||||
|
||||
if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
|
||||
(data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
|
||||
(data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||
|
||||
(data_arg.read_write == I2C_SMBUS_WRITE)) {
|
||||
if (copy_from_user(&temp, data_arg.data, datasize))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
|
||||
/* Convert old I2C block commands to the new
|
||||
convention. This preserves binary compatibility. */
|
||||
data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;
|
||||
if (data_arg.read_write == I2C_SMBUS_READ)
|
||||
temp.block[0] = I2C_SMBUS_BLOCK_MAX;
|
||||
}
|
||||
res = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
|
||||
data_arg.read_write, data_arg.command, data_arg.size, &temp);
|
||||
if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
|
||||
(data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
|
||||
(data_arg.read_write == I2C_SMBUS_READ))) {
|
||||
if (copy_to_user(data_arg.data, &temp, datasize))
|
||||
return -EFAULT;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int i2cdev_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct i2c_client *client = (struct i2c_client *)file->private_data;
|
||||
struct i2c_rdwr_ioctl_data rdwr_arg;
|
||||
struct i2c_smbus_ioctl_data data_arg;
|
||||
union i2c_smbus_data temp;
|
||||
struct i2c_msg *rdwr_pa;
|
||||
u8 __user **data_ptrs;
|
||||
int i,datasize,res;
|
||||
unsigned long funcs;
|
||||
|
||||
dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
|
||||
|
@ -253,164 +413,11 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
|
|||
return put_user(funcs, (unsigned long __user *)arg);
|
||||
|
||||
case I2C_RDWR:
|
||||
if (copy_from_user(&rdwr_arg,
|
||||
(struct i2c_rdwr_ioctl_data __user *)arg,
|
||||
sizeof(rdwr_arg)))
|
||||
return -EFAULT;
|
||||
|
||||
/* Put an arbitrary limit on the number of messages that can
|
||||
* be sent at once */
|
||||
if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
|
||||
return -EINVAL;
|
||||
|
||||
rdwr_pa = (struct i2c_msg *)
|
||||
kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (rdwr_pa == NULL) return -ENOMEM;
|
||||
|
||||
if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
|
||||
rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
|
||||
kfree(rdwr_pa);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
|
||||
if (data_ptrs == NULL) {
|
||||
kfree(rdwr_pa);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
for( i=0; i<rdwr_arg.nmsgs; i++ ) {
|
||||
/* Limit the size of the message to a sane amount;
|
||||
* and don't let length change either. */
|
||||
if ((rdwr_pa[i].len > 8192) ||
|
||||
(rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
|
||||
rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
|
||||
if(rdwr_pa[i].buf == NULL) {
|
||||
res = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
if(copy_from_user(rdwr_pa[i].buf,
|
||||
data_ptrs[i],
|
||||
rdwr_pa[i].len)) {
|
||||
++i; /* Needs to be kfreed too */
|
||||
res = -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res < 0) {
|
||||
int j;
|
||||
for (j = 0; j < i; ++j)
|
||||
kfree(rdwr_pa[j].buf);
|
||||
kfree(data_ptrs);
|
||||
kfree(rdwr_pa);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = i2c_transfer(client->adapter,
|
||||
rdwr_pa,
|
||||
rdwr_arg.nmsgs);
|
||||
while(i-- > 0) {
|
||||
if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) {
|
||||
if(copy_to_user(
|
||||
data_ptrs[i],
|
||||
rdwr_pa[i].buf,
|
||||
rdwr_pa[i].len)) {
|
||||
res = -EFAULT;
|
||||
}
|
||||
}
|
||||
kfree(rdwr_pa[i].buf);
|
||||
}
|
||||
kfree(data_ptrs);
|
||||
kfree(rdwr_pa);
|
||||
return res;
|
||||
return i2cdev_ioctl_rdrw(client, arg);
|
||||
|
||||
case I2C_SMBUS:
|
||||
if (copy_from_user(&data_arg,
|
||||
(struct i2c_smbus_ioctl_data __user *) arg,
|
||||
sizeof(struct i2c_smbus_ioctl_data)))
|
||||
return -EFAULT;
|
||||
if ((data_arg.size != I2C_SMBUS_BYTE) &&
|
||||
(data_arg.size != I2C_SMBUS_QUICK) &&
|
||||
(data_arg.size != I2C_SMBUS_BYTE_DATA) &&
|
||||
(data_arg.size != I2C_SMBUS_WORD_DATA) &&
|
||||
(data_arg.size != I2C_SMBUS_PROC_CALL) &&
|
||||
(data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
|
||||
(data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
|
||||
(data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
|
||||
(data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
|
||||
dev_dbg(&client->adapter->dev,
|
||||
"size out of range (%x) in ioctl I2C_SMBUS.\n",
|
||||
data_arg.size);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
|
||||
so the check is valid if size==I2C_SMBUS_QUICK too. */
|
||||
if ((data_arg.read_write != I2C_SMBUS_READ) &&
|
||||
(data_arg.read_write != I2C_SMBUS_WRITE)) {
|
||||
dev_dbg(&client->adapter->dev,
|
||||
"read_write out of range (%x) in ioctl I2C_SMBUS.\n",
|
||||
data_arg.read_write);
|
||||
return -EINVAL;
|
||||
}
|
||||
return i2cdev_ioctl_smbus(client, arg);
|
||||
|
||||
/* Note that command values are always valid! */
|
||||
|
||||
if ((data_arg.size == I2C_SMBUS_QUICK) ||
|
||||
((data_arg.size == I2C_SMBUS_BYTE) &&
|
||||
(data_arg.read_write == I2C_SMBUS_WRITE)))
|
||||
/* These are special: we do not use data */
|
||||
return i2c_smbus_xfer(client->adapter, client->addr,
|
||||
client->flags,
|
||||
data_arg.read_write,
|
||||
data_arg.command,
|
||||
data_arg.size, NULL);
|
||||
|
||||
if (data_arg.data == NULL) {
|
||||
dev_dbg(&client->adapter->dev,
|
||||
"data is NULL pointer in ioctl I2C_SMBUS.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
|
||||
(data_arg.size == I2C_SMBUS_BYTE))
|
||||
datasize = sizeof(data_arg.data->byte);
|
||||
else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
|
||||
(data_arg.size == I2C_SMBUS_PROC_CALL))
|
||||
datasize = sizeof(data_arg.data->word);
|
||||
else /* size == smbus block, i2c block, or block proc. call */
|
||||
datasize = sizeof(data_arg.data->block);
|
||||
|
||||
if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
|
||||
(data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
|
||||
(data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||
|
||||
(data_arg.read_write == I2C_SMBUS_WRITE)) {
|
||||
if (copy_from_user(&temp, data_arg.data, datasize))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
|
||||
/* Convert old I2C block commands to the new
|
||||
convention. This preserves binary compatibility. */
|
||||
data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;
|
||||
if (data_arg.read_write == I2C_SMBUS_READ)
|
||||
temp.block[0] = I2C_SMBUS_BLOCK_MAX;
|
||||
}
|
||||
res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
|
||||
data_arg.read_write,
|
||||
data_arg.command,data_arg.size,&temp);
|
||||
if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
|
||||
(data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
|
||||
(data_arg.read_write == I2C_SMBUS_READ))) {
|
||||
if (copy_to_user(data_arg.data, &temp, datasize))
|
||||
return -EFAULT;
|
||||
}
|
||||
return res;
|
||||
case I2C_RETRIES:
|
||||
client->adapter->retries = arg;
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* MMIO/IRQ and platform data for SH7760 I2C channels
|
||||
*/
|
||||
|
||||
#ifndef _I2C_SH7760_H_
|
||||
#define _I2C_SH7760_H_
|
||||
|
||||
#define SH7760_I2C_DEVNAME "sh7760-i2c"
|
||||
|
||||
#define SH7760_I2C0_MMIO 0xFE140000
|
||||
#define SH7760_I2C0_MMIOEND 0xFE14003B
|
||||
#define SH7760_I2C0_IRQ 62
|
||||
|
||||
#define SH7760_I2C1_MMIO 0xFE150000
|
||||
#define SH7760_I2C1_MMIOEND 0xFE15003B
|
||||
#define SH7760_I2C1_IRQ 63
|
||||
|
||||
struct sh7760_i2c_platdata {
|
||||
unsigned int speed_khz;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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,0 +1,12 @@
|
|||
#ifndef I2C_PCA9564_PLATFORM_H
|
||||
#define I2C_PCA9564_PLATFORM_H
|
||||
|
||||
struct i2c_pca9564_pf_platform_data {
|
||||
int gpio; /* pin to reset chip. driver will work when
|
||||
* not supplied (negative value), but it
|
||||
* cannot exit some error conditions then */
|
||||
int i2c_clock_speed; /* values are defined in linux/i2c-algo-pca.h */
|
||||
int timeout; /* timeout = this value * 10us */
|
||||
};
|
||||
|
||||
#endif /* I2C_PCA9564_PLATFORM_H */
|
Загрузка…
Ссылка в новой задаче