Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/i2c-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/i2c-2.6: (30 commits) i2c: Drop unimplemented slave functions i2c: Constify i2c_algorithm declarations, part 2 i2c: Constify i2c_algorithm declarations, part 1 i2c: Let drivers constify i2c_algorithm data i2c-isa: Restore driver owner i2c-viapro: Add support for the VT8237A and VT8251 i2c: Warn on i2c client creation failure i2c-core: Drop useless bitmaskings i2c-algo-pcf: Discard the mdelay data struct member i2c-algo-bit: Cleanups i2c-isa: Fail adding driver on attach_adapter error i2c: __must_check fixes (chip drivers) i2c-dev: attach/detach_adapter cleanups i2c-stub: Chip address as a module parameter i2c: Plan i2c-isa for removal i2c: New bus driver for TI OMAP boards i2c-algo-bit: Discard the mdelay data struct member i2c-matroxfb: Struct init conversion i2c: Fix copy-n-paste in subsystem Kconfig i2c-au1550: Add I2C support for Au1200 ...
This commit is contained in:
Коммит
a5b08073a0
|
@ -313,3 +313,12 @@ Why: The stacking of class devices makes these values misleading and
|
|||
Who: Kay Sievers <kay.sievers@suse.de>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: i2c-isa
|
||||
When: December 2006
|
||||
Why: i2c-isa is a non-sense and doesn't fit in the device driver
|
||||
model. Drivers relying on it are better implemented as platform
|
||||
drivers.
|
||||
Who: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
---------------------------
|
||||
|
|
|
@ -7,9 +7,12 @@ Supported adapters:
|
|||
* VIA Technologies, Inc. VT82C686A/B
|
||||
Datasheet: Sometimes available at the VIA website
|
||||
|
||||
* VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237R
|
||||
* VIA Technologies, Inc. VT8231, VT8233, VT8233A
|
||||
Datasheet: available on request from VIA
|
||||
|
||||
* VIA Technologies, Inc. VT8235, VT8237R, VT8237A, VT8251
|
||||
Datasheet: available on request and under NDA from VIA
|
||||
|
||||
Authors:
|
||||
Kyösti Mälkki <kmalkki@cc.hut.fi>,
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>,
|
||||
|
@ -39,6 +42,8 @@ Your lspci -n listing must show one of these :
|
|||
device 1106:8235 (VT8231 function 4)
|
||||
device 1106:3177 (VT8235)
|
||||
device 1106:3227 (VT8237R)
|
||||
device 1106:3337 (VT8237A)
|
||||
device 1106:3287 (VT8251)
|
||||
|
||||
If none of these show up, you should look in the BIOS for settings like
|
||||
enable ACPI / SMBus or even USB.
|
||||
|
|
|
@ -6,9 +6,12 @@ This module is a very simple fake I2C/SMBus driver. It implements four
|
|||
types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, and
|
||||
(r/w) word data.
|
||||
|
||||
You need to provide a chip address as a module parameter when loading
|
||||
this driver, which will then only react to SMBus commands to this address.
|
||||
|
||||
No hardware is needed nor associated with this module. It will accept write
|
||||
quick commands to all addresses; it will respond to the other commands (also
|
||||
to all addresses) by reading from or writing to an array in memory. It will
|
||||
quick commands to one address; it will respond to the other commands (also
|
||||
to one address) by reading from or writing to an array in memory. It will
|
||||
also spam the kernel logs for every command it handles.
|
||||
|
||||
A pointer register with auto-increment is implemented for all byte
|
||||
|
@ -21,6 +24,11 @@ The typical use-case is like this:
|
|||
3. load the target sensors chip driver module
|
||||
4. observe its behavior in the kernel log
|
||||
|
||||
PARAMETERS:
|
||||
|
||||
int chip_addr:
|
||||
The SMBus address to emulate a chip at.
|
||||
|
||||
CAVEATS:
|
||||
|
||||
There are independent arrays for byte/data and word/data commands. Depending
|
||||
|
@ -33,6 +41,9 @@ If the hardware for your driver has banked registers (e.g. Winbond sensors
|
|||
chips) this module will not work well - although it could be extended to
|
||||
support that pretty easily.
|
||||
|
||||
Only one chip address is supported - although this module could be
|
||||
extended to support more.
|
||||
|
||||
If you spam it hard enough, printk can be lossy. This module really wants
|
||||
something like relayfs.
|
||||
|
||||
|
|
|
@ -308,7 +308,6 @@ static struct i2c_algo_bit_data ioc_data = {
|
|||
.getsda = ioc_getsda,
|
||||
.getscl = ioc_getscl,
|
||||
.udelay = 80,
|
||||
.mdelay = 80,
|
||||
.timeout = 100
|
||||
};
|
||||
|
||||
|
|
|
@ -293,7 +293,7 @@ static u32 acpi_ec_smb_func(struct i2c_adapter *adapter)
|
|||
I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC);
|
||||
}
|
||||
|
||||
static struct i2c_algorithm acpi_ec_smbus_algorithm = {
|
||||
static const struct i2c_algorithm acpi_ec_smbus_algorithm = {
|
||||
.smbus_xfer = acpi_ec_smb_access,
|
||||
.functionality = acpi_ec_smb_func,
|
||||
};
|
||||
|
|
|
@ -243,6 +243,7 @@ static struct i2c_driver it87_driver = {
|
|||
|
||||
static struct i2c_driver it87_isa_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "it87-isa",
|
||||
},
|
||||
.attach_adapter = it87_isa_attach_adapter,
|
||||
|
|
|
@ -175,6 +175,7 @@ static struct i2c_driver lm78_driver = {
|
|||
|
||||
static struct i2c_driver lm78_isa_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "lm78-isa",
|
||||
},
|
||||
.attach_adapter = lm78_isa_attach_adapter,
|
||||
|
|
|
@ -238,6 +238,7 @@ static struct pc87360_data *pc87360_update_device(struct device *dev);
|
|||
|
||||
static struct i2c_driver pc87360_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "pc87360",
|
||||
},
|
||||
.attach_adapter = pc87360_detect,
|
||||
|
|
|
@ -200,6 +200,7 @@ static void sis5595_init_client(struct i2c_client *client);
|
|||
|
||||
static struct i2c_driver sis5595_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "sis5595",
|
||||
},
|
||||
.attach_adapter = sis5595_detect,
|
||||
|
|
|
@ -228,6 +228,7 @@ static int smsc47b397_detect(struct i2c_adapter *adapter);
|
|||
|
||||
static struct i2c_driver smsc47b397_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "smsc47b397",
|
||||
},
|
||||
.attach_adapter = smsc47b397_detect,
|
||||
|
|
|
@ -128,6 +128,7 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
|
|||
|
||||
static struct i2c_driver smsc47m1_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "smsc47m1",
|
||||
},
|
||||
.attach_adapter = smsc47m1_detect,
|
||||
|
|
|
@ -574,6 +574,7 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
|||
smbus_driver and isa_driver, and clients could be of either kind */
|
||||
static struct i2c_driver via686a_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "via686a",
|
||||
},
|
||||
.attach_adapter = via686a_detect,
|
||||
|
|
|
@ -587,6 +587,7 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
|||
|
||||
static struct i2c_driver vt8231_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "vt8231",
|
||||
},
|
||||
.attach_adapter = vt8231_detect,
|
||||
|
|
|
@ -903,6 +903,7 @@ static int w83627ehf_detach_client(struct i2c_client *client)
|
|||
|
||||
static struct i2c_driver w83627ehf_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "w83627ehf",
|
||||
},
|
||||
.attach_adapter = w83627ehf_detect,
|
||||
|
|
|
@ -339,6 +339,7 @@ static void w83627hf_init_client(struct i2c_client *client);
|
|||
|
||||
static struct i2c_driver w83627hf_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "w83627hf",
|
||||
},
|
||||
.attach_adapter = w83627hf_detect,
|
||||
|
|
|
@ -288,6 +288,7 @@ static struct i2c_driver w83781d_driver = {
|
|||
|
||||
static struct i2c_driver w83781d_isa_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "w83781d-isa",
|
||||
},
|
||||
.attach_adapter = w83781d_isa_attach_adapter,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Character device configuration
|
||||
# I2C subsystem configuration
|
||||
#
|
||||
|
||||
menu "I2C support"
|
||||
|
|
|
@ -53,12 +53,6 @@ config I2C_ALGO8XX
|
|||
tristate "MPC8xx CPM I2C interface"
|
||||
depends on 8xx && I2C
|
||||
|
||||
config I2C_ALGO_SIBYTE
|
||||
tristate "SiByte SMBus interface"
|
||||
depends on SIBYTE_SB1xxx_SOC && I2C
|
||||
help
|
||||
Supports the SiByte SOC on-chip I2C interfaces (2 channels).
|
||||
|
||||
config I2C_ALGO_SGI
|
||||
tristate "I2C SGI interfaces"
|
||||
depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS)
|
||||
|
|
|
@ -6,7 +6,6 @@ obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
|
|||
obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
|
||||
obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
|
||||
obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o
|
||||
obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o
|
||||
obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o
|
||||
|
||||
ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
|
||||
|
|
|
@ -76,17 +76,15 @@ static inline void scllo(struct i2c_algo_bit_data *adap)
|
|||
* Raise scl line, and do checking for delays. This is necessary for slower
|
||||
* devices.
|
||||
*/
|
||||
static inline int sclhi(struct i2c_algo_bit_data *adap)
|
||||
static int sclhi(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
unsigned long start;
|
||||
|
||||
setscl(adap,1);
|
||||
|
||||
/* Not all adapters have scl sense line... */
|
||||
if (adap->getscl == NULL ) {
|
||||
udelay(adap->udelay);
|
||||
return 0;
|
||||
}
|
||||
if (!adap->getscl)
|
||||
goto done;
|
||||
|
||||
start=jiffies;
|
||||
while (! getscl(adap) ) {
|
||||
|
@ -101,6 +99,8 @@ static inline int sclhi(struct i2c_algo_bit_data *adap)
|
|||
cond_resched();
|
||||
}
|
||||
DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start));
|
||||
|
||||
done:
|
||||
udelay(adap->udelay);
|
||||
return 0;
|
||||
}
|
||||
|
@ -121,7 +121,6 @@ static void i2c_repstart(struct i2c_algo_bit_data *adap)
|
|||
DEBPROTO(printk(" Sr "));
|
||||
setsda(adap,1);
|
||||
sclhi(adap);
|
||||
udelay(adap->udelay);
|
||||
|
||||
sdalo(adap);
|
||||
scllo(adap);
|
||||
|
@ -306,7 +305,7 @@ bailout:
|
|||
* 0 chip did not answer
|
||||
* -x transmission error
|
||||
*/
|
||||
static inline int try_address(struct i2c_adapter *i2c_adap,
|
||||
static int try_address(struct i2c_adapter *i2c_adap,
|
||||
unsigned char addr, int retries)
|
||||
{
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
|
@ -354,15 +353,11 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
|||
return (retval<0)? retval : -EFAULT;
|
||||
/* got a better one ?? */
|
||||
}
|
||||
#if 0
|
||||
/* from asm/delay.h */
|
||||
__delay(adap->mdelay * (loops_per_sec / 1000) );
|
||||
#endif
|
||||
}
|
||||
return wrcount;
|
||||
}
|
||||
|
||||
static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||
static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||
{
|
||||
int inval;
|
||||
int rdcount=0; /* counts bytes read */
|
||||
|
@ -412,7 +407,7 @@ static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
|||
* -x an error occurred (like: -EREMOTEIO if the device did not answer, or
|
||||
* -ETIMEDOUT, for example if the lines are stuck...)
|
||||
*/
|
||||
static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||
static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||
{
|
||||
unsigned short flags = msg->flags;
|
||||
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
|
||||
|
@ -517,7 +512,7 @@ static u32 bit_func(struct i2c_adapter *adap)
|
|||
|
||||
/* -----exported algorithm data: ------------------------------------- */
|
||||
|
||||
static struct i2c_algorithm i2c_bit_algo = {
|
||||
static const struct i2c_algorithm i2c_bit_algo = {
|
||||
.master_xfer = bit_xfer,
|
||||
.functionality = bit_func,
|
||||
};
|
||||
|
|
|
@ -355,7 +355,7 @@ static int pca_init(struct i2c_algo_pca_data *adap)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm pca_algo = {
|
||||
static const struct i2c_algorithm pca_algo = {
|
||||
.master_xfer = pca_xfer,
|
||||
.functionality = pca_func,
|
||||
};
|
||||
|
|
|
@ -458,7 +458,7 @@ static u32 pcf_func(struct i2c_adapter *adap)
|
|||
|
||||
/* -----exported algorithm data: ------------------------------------- */
|
||||
|
||||
static struct i2c_algorithm pcf_algo = {
|
||||
static const struct i2c_algorithm pcf_algo = {
|
||||
.master_xfer = pcf_xfer,
|
||||
.functionality = pcf_func,
|
||||
};
|
||||
|
|
|
@ -157,7 +157,7 @@ static u32 sgi_func(struct i2c_adapter *adap)
|
|||
return I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm sgi_algo = {
|
||||
static const struct i2c_algorithm sgi_algo = {
|
||||
.master_xfer = sgi_xfer,
|
||||
.functionality = sgi_func,
|
||||
};
|
||||
|
|
|
@ -1,215 +0,0 @@
|
|||
/* ------------------------------------------------------------------------- */
|
||||
/* i2c-algo-sibyte.c i2c driver algorithms for bit-shift adapters */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Copyright (C) 2001,2002,2003 Broadcom Corporation
|
||||
Copyright (C) 1995-2000 Simon G. Vogl
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
|
||||
Frodo Looijaard <frodol@dds.nl>. */
|
||||
|
||||
/* Ported for SiByte SOCs by Broadcom Corporation. */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/sibyte/sb1250_regs.h>
|
||||
#include <asm/sibyte/sb1250_smbus.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-sibyte.h>
|
||||
|
||||
/* ----- global defines ----------------------------------------------- */
|
||||
#define SMB_CSR(a,r) ((long)(a->reg_base + r))
|
||||
|
||||
/* ----- global variables --------------------------------------------- */
|
||||
|
||||
/* module parameters:
|
||||
*/
|
||||
static int bit_scan; /* have a look at what's hanging 'round */
|
||||
|
||||
|
||||
static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data * data)
|
||||
{
|
||||
struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
|
||||
int data_bytes = 0;
|
||||
int error;
|
||||
|
||||
while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
|
||||
;
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_QUICK:
|
||||
csr_out32((V_SMB_ADDR(addr) | (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
|
||||
V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
|
||||
break;
|
||||
case I2C_SMBUS_BYTE:
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
data_bytes = 1;
|
||||
} else {
|
||||
csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
}
|
||||
break;
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
data_bytes = 1;
|
||||
} else {
|
||||
csr_out32(V_SMB_LB(data->byte), SMB_CSR(adap, R_SMB_DATA));
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
}
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
data_bytes = 2;
|
||||
} else {
|
||||
csr_out32(V_SMB_LB(data->word & 0xff), SMB_CSR(adap, R_SMB_DATA));
|
||||
csr_out32(V_SMB_MB(data->word >> 8), SMB_CSR(adap, R_SMB_DATA));
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -1; /* XXXKW better error code? */
|
||||
}
|
||||
|
||||
while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
|
||||
;
|
||||
|
||||
error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
|
||||
if (error & M_SMB_ERROR) {
|
||||
/* Clear error bit by writing a 1 */
|
||||
csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
|
||||
return -1; /* XXXKW better error code? */
|
||||
}
|
||||
|
||||
if (data_bytes == 1)
|
||||
data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
|
||||
if (data_bytes == 2)
|
||||
data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int algo_control(struct i2c_adapter *adapter,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 bit_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
|
||||
}
|
||||
|
||||
|
||||
/* -----exported algorithm data: ------------------------------------- */
|
||||
|
||||
static struct i2c_algorithm i2c_sibyte_algo = {
|
||||
.smbus_xfer = smbus_xfer,
|
||||
.algo_control = algo_control, /* ioctl */
|
||||
.functionality = bit_func,
|
||||
};
|
||||
|
||||
/*
|
||||
* registering functions to load algorithms at runtime
|
||||
*/
|
||||
int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
|
||||
{
|
||||
int i;
|
||||
struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
|
||||
|
||||
/* register new adapter to i2c module... */
|
||||
i2c_adap->algo = &i2c_sibyte_algo;
|
||||
|
||||
/* Set the frequency to 100 kHz */
|
||||
csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
|
||||
csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
|
||||
|
||||
/* scan bus */
|
||||
if (bit_scan) {
|
||||
union i2c_smbus_data data;
|
||||
int rc;
|
||||
printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
|
||||
i2c_adap->name);
|
||||
for (i = 0x00; i < 0x7f; i++) {
|
||||
/* XXXKW is this a realistic probe? */
|
||||
rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
|
||||
I2C_SMBUS_BYTE_DATA, &data);
|
||||
if (!rc) {
|
||||
printk("(%02x)",i);
|
||||
} else
|
||||
printk(".");
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
return i2c_add_adapter(i2c_adap);
|
||||
}
|
||||
|
||||
|
||||
int i2c_sibyte_del_bus(struct i2c_adapter *adap)
|
||||
{
|
||||
int res;
|
||||
|
||||
if ((res = i2c_del_adapter(adap)) < 0)
|
||||
return res;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init i2c_algo_sibyte_init (void)
|
||||
{
|
||||
printk("i2c-algo-sibyte.o: i2c SiByte algorithm module\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(i2c_sibyte_add_bus);
|
||||
EXPORT_SYMBOL(i2c_sibyte_del_bus);
|
||||
|
||||
#ifdef MODULE
|
||||
MODULE_AUTHOR("Kip Walker, Broadcom Corp.");
|
||||
MODULE_DESCRIPTION("SiByte I2C-Bus algorithm");
|
||||
module_param(bit_scan, int, 0);
|
||||
MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
return i2c_algo_sibyte_init();
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
{
|
||||
}
|
||||
#endif
|
|
@ -75,11 +75,11 @@ config I2C_AMD8111
|
|||
will be called i2c-amd8111.
|
||||
|
||||
config I2C_AU1550
|
||||
tristate "Au1550 SMBus interface"
|
||||
depends on I2C && SOC_AU1550
|
||||
tristate "Au1550/Au1200 SMBus interface"
|
||||
depends on I2C && (SOC_AU1550 || SOC_AU1200)
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Au1550 SMBus interface.
|
||||
Au1550 and Au1200 SMBus interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-au1550.
|
||||
|
@ -287,6 +287,16 @@ config I2C_OCORES
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-ocores.
|
||||
|
||||
config I2C_OMAP
|
||||
tristate "OMAP I2C adapter"
|
||||
depends on I2C && ARCH_OMAP
|
||||
default y if MACH_OMAP_H3 || MACH_OMAP_OSK
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface on the Texas Instruments OMAP1/2 family of processors.
|
||||
Like OMAP1510/1610/1710/5912 and OMAP242x.
|
||||
For details see http://www.ti.com/omap.
|
||||
|
||||
config I2C_PARPORT
|
||||
tristate "Parallel port adapter"
|
||||
depends on I2C && PARPORT
|
||||
|
@ -482,19 +492,19 @@ config I2C_VIA
|
|||
will be called i2c-via.
|
||||
|
||||
config I2C_VIAPRO
|
||||
tristate "VIA 82C596/82C686/823x"
|
||||
tristate "VIA 82C596/82C686/82xx"
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the VIA
|
||||
82C596/82C686/823x I2C interfaces. Specifically, the following
|
||||
82C596/82C686/82xx I2C interfaces. Specifically, the following
|
||||
chipsets are supported:
|
||||
82C596A/B
|
||||
82C686A/B
|
||||
8231
|
||||
8233
|
||||
8233A
|
||||
8235
|
||||
8237
|
||||
VT82C596A/B
|
||||
VT82C686A/B
|
||||
VT8231
|
||||
VT8233/A
|
||||
VT8235
|
||||
VT8237R/A
|
||||
VT8251
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-viapro.
|
||||
|
|
|
@ -24,6 +24,7 @@ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
|
|||
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
|
||||
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
|
||||
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
|
||||
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
|
||||
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
|
||||
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
|
||||
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
|
||||
|
|
|
@ -468,7 +468,7 @@ static u32 ali1535_func(struct i2c_adapter *adapter)
|
|||
I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = ali1535_access,
|
||||
.functionality = ali1535_func,
|
||||
};
|
||||
|
|
|
@ -367,7 +367,7 @@ static void ali1563_shutdown(struct pci_dev *dev)
|
|||
release_region(ali1563_smba,ALI1563_SMB_IOSIZE);
|
||||
}
|
||||
|
||||
static struct i2c_algorithm ali1563_algorithm = {
|
||||
static const struct i2c_algorithm ali1563_algorithm = {
|
||||
.smbus_xfer = ali1563_access,
|
||||
.functionality = ali1563_func,
|
||||
};
|
||||
|
|
|
@ -463,7 +463,7 @@ static u32 ali15x3_func(struct i2c_adapter *adapter)
|
|||
I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = ali15x3_access,
|
||||
.functionality = ali15x3_func,
|
||||
};
|
||||
|
|
|
@ -294,7 +294,7 @@ static u32 amd756_func(struct i2c_adapter *adapter)
|
|||
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = amd756_access,
|
||||
.functionality = amd756_func,
|
||||
};
|
||||
|
|
|
@ -316,7 +316,7 @@ static u32 amd8111_func(struct i2c_adapter *adapter)
|
|||
I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = amd8111_access,
|
||||
.functionality = amd8111_func,
|
||||
};
|
||||
|
|
|
@ -34,8 +34,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
#include <asm/mach-pb1x00/pb1550.h>
|
||||
#include <asm/mach-au1x00/au1xxx.h>
|
||||
#include <asm/mach-au1x00/au1xxx_psc.h>
|
||||
|
||||
#include "i2c-au1550.h"
|
||||
|
@ -118,13 +117,19 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
|
|||
|
||||
/* Reset the FIFOs, clear events.
|
||||
*/
|
||||
sp->psc_smbpcr = PSC_SMBPCR_DC;
|
||||
stat = sp->psc_smbstat;
|
||||
sp->psc_smbevnt = PSC_SMBEVNT_ALLCLR;
|
||||
au_sync();
|
||||
do {
|
||||
stat = sp->psc_smbpcr;
|
||||
|
||||
if (!(stat & PSC_SMBSTAT_TE) || !(stat & PSC_SMBSTAT_RE)) {
|
||||
sp->psc_smbpcr = PSC_SMBPCR_DC;
|
||||
au_sync();
|
||||
} while ((stat & PSC_SMBPCR_DC) != 0);
|
||||
do {
|
||||
stat = sp->psc_smbpcr;
|
||||
au_sync();
|
||||
} while ((stat & PSC_SMBPCR_DC) != 0);
|
||||
udelay(50);
|
||||
}
|
||||
|
||||
/* Write out the i2c chip address and specify operation
|
||||
*/
|
||||
|
@ -279,10 +284,10 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
|
|||
static u32
|
||||
au1550_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm au1550_algo = {
|
||||
static const struct i2c_algorithm au1550_algo = {
|
||||
.master_xfer = au1550_xfer,
|
||||
.functionality = au1550_func,
|
||||
};
|
||||
|
|
|
@ -196,7 +196,6 @@ static struct i2c_algo_pcf_data pcf_isa_data = {
|
|||
.getclock = pcf_isa_getclock,
|
||||
.waitforpin = pcf_isa_waitforpin,
|
||||
.udelay = 10,
|
||||
.mdelay = 10,
|
||||
.timeout = 100,
|
||||
};
|
||||
|
||||
|
|
|
@ -99,7 +99,6 @@ static struct i2c_algo_bit_data hydra_bit_data = {
|
|||
.getsda = hydra_bit_getsda,
|
||||
.getscl = hydra_bit_getscl,
|
||||
.udelay = 5,
|
||||
.mdelay = 5,
|
||||
.timeout = HZ
|
||||
};
|
||||
|
||||
|
|
|
@ -434,7 +434,7 @@ static u32 i801_func(struct i2c_adapter *adapter)
|
|||
| (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = i801_access,
|
||||
.functionality = i801_func,
|
||||
};
|
||||
|
|
|
@ -166,7 +166,6 @@ static struct i2c_algo_bit_data i810_i2c_bit_data = {
|
|||
.getsda = bit_i810i2c_getsda,
|
||||
.getscl = bit_i810i2c_getscl,
|
||||
.udelay = CYCLE_DELAY,
|
||||
.mdelay = CYCLE_DELAY,
|
||||
.timeout = TIMEOUT,
|
||||
};
|
||||
|
||||
|
@ -182,7 +181,6 @@ static struct i2c_algo_bit_data i810_ddc_bit_data = {
|
|||
.getsda = bit_i810ddc_getsda,
|
||||
.getscl = bit_i810ddc_getscl,
|
||||
.udelay = CYCLE_DELAY,
|
||||
.mdelay = CYCLE_DELAY,
|
||||
.timeout = TIMEOUT,
|
||||
};
|
||||
|
||||
|
|
|
@ -625,7 +625,7 @@ static u32 iic_func(struct i2c_adapter *adap)
|
|||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm iic_algo = {
|
||||
static const struct i2c_algorithm iic_algo = {
|
||||
.master_xfer = iic_xfer,
|
||||
.functionality = iic_func
|
||||
};
|
||||
|
|
|
@ -401,7 +401,7 @@ iop3xx_i2c_func(struct i2c_adapter *adap)
|
|||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm iop3xx_i2c_algo = {
|
||||
static const struct i2c_algorithm iop3xx_i2c_algo = {
|
||||
.master_xfer = iop3xx_i2c_master_xfer,
|
||||
.algo_control = iop3xx_i2c_algo_control,
|
||||
.functionality = iop3xx_i2c_func,
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
static u32 isa_func(struct i2c_adapter *adapter);
|
||||
|
||||
/* This is the actual algorithm we define */
|
||||
static struct i2c_algorithm isa_algorithm = {
|
||||
static const struct i2c_algorithm isa_algorithm = {
|
||||
.functionality = isa_func,
|
||||
};
|
||||
|
||||
|
@ -89,9 +89,14 @@ int i2c_isa_add_driver(struct i2c_driver *driver)
|
|||
dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->driver.name);
|
||||
|
||||
/* Now look for clients */
|
||||
driver->attach_adapter(&isa_adapter);
|
||||
|
||||
return 0;
|
||||
res = driver->attach_adapter(&isa_adapter);
|
||||
if (res) {
|
||||
dev_err(&isa_adapter.dev,
|
||||
"Driver %s failed to attach adapter, unregistering\n",
|
||||
driver->driver.name);
|
||||
driver_unregister(&driver->driver);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int i2c_isa_del_driver(struct i2c_driver *driver)
|
||||
|
@ -125,6 +130,8 @@ int i2c_isa_del_driver(struct i2c_driver *driver)
|
|||
|
||||
static int __init i2c_isa_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
mutex_init(&isa_adapter.clist_lock);
|
||||
INIT_LIST_HEAD(&isa_adapter.clients);
|
||||
|
||||
|
@ -133,8 +140,16 @@ static int __init i2c_isa_init(void)
|
|||
sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
|
||||
isa_adapter.dev.driver = &i2c_adapter_driver;
|
||||
isa_adapter.dev.release = &i2c_adapter_dev_release;
|
||||
device_register(&isa_adapter.dev);
|
||||
device_create_file(&isa_adapter.dev, &dev_attr_name);
|
||||
err = device_register(&isa_adapter.dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "i2c-isa: Failed to register device\n");
|
||||
goto exit;
|
||||
}
|
||||
err = device_create_file(&isa_adapter.dev, &dev_attr_name);
|
||||
if (err) {
|
||||
printk(KERN_ERR "i2c-isa: Failed to create name file\n");
|
||||
goto exit_unregister;
|
||||
}
|
||||
|
||||
/* Add this adapter to the i2c_adapter class */
|
||||
memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device));
|
||||
|
@ -142,11 +157,24 @@ static int __init i2c_isa_init(void)
|
|||
isa_adapter.class_dev.class = &i2c_adapter_class;
|
||||
strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id,
|
||||
BUS_ID_SIZE);
|
||||
class_device_register(&isa_adapter.class_dev);
|
||||
err = class_device_register(&isa_adapter.class_dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "i2c-isa: Failed to register class device\n");
|
||||
goto exit_remove_name;
|
||||
}
|
||||
|
||||
dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_name:
|
||||
device_remove_file(&isa_adapter.dev, &dev_attr_name);
|
||||
exit_unregister:
|
||||
init_completion(&isa_adapter.dev_released); /* Needed? */
|
||||
device_unregister(&isa_adapter.dev);
|
||||
wait_for_completion(&isa_adapter.dev_released);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit i2c_isa_exit(void)
|
||||
|
|
|
@ -114,7 +114,6 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev)
|
|||
drv_data->algo_data.getsda = ixp2000_bit_getsda;
|
||||
drv_data->algo_data.getscl = ixp2000_bit_getscl;
|
||||
drv_data->algo_data.udelay = 6;
|
||||
drv_data->algo_data.mdelay = 6;
|
||||
drv_data->algo_data.timeout = 100;
|
||||
|
||||
drv_data->adapter.id = I2C_HW_B_IXP2000,
|
||||
|
|
|
@ -122,7 +122,6 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
|
|||
drv_data->algo_data.getsda = ixp4xx_bit_getsda;
|
||||
drv_data->algo_data.getscl = ixp4xx_bit_getscl;
|
||||
drv_data->algo_data.udelay = 10;
|
||||
drv_data->algo_data.mdelay = 10;
|
||||
drv_data->algo_data.timeout = 100;
|
||||
|
||||
drv_data->adapter.id = I2C_HW_B_IXP4XX;
|
||||
|
|
|
@ -272,7 +272,7 @@ static u32 mpc_functionality(struct i2c_adapter *adap)
|
|||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm mpc_algo = {
|
||||
static const struct i2c_algorithm mpc_algo = {
|
||||
.master_xfer = mpc_xfer,
|
||||
.functionality = mpc_functionality,
|
||||
};
|
||||
|
|
|
@ -431,7 +431,7 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|||
return num;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm mv64xxx_i2c_algo = {
|
||||
static const struct i2c_algorithm mv64xxx_i2c_algo = {
|
||||
.master_xfer = mv64xxx_i2c_xfer,
|
||||
.functionality = mv64xxx_i2c_functionality,
|
||||
};
|
||||
|
|
|
@ -109,7 +109,7 @@ static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
|
|||
static u32 nforce2_func(struct i2c_adapter *adapter);
|
||||
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = nforce2_access,
|
||||
.functionality = nforce2_func,
|
||||
};
|
||||
|
|
|
@ -199,7 +199,7 @@ static u32 ocores_func(struct i2c_adapter *adap)
|
|||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm ocores_algorithm = {
|
||||
static const struct i2c_algorithm ocores_algorithm = {
|
||||
.master_xfer = ocores_xfer,
|
||||
.functionality = ocores_func,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,676 @@
|
|||
/*
|
||||
* TI OMAP I2C master mode driver
|
||||
*
|
||||
* Copyright (C) 2003 MontaVista Software, Inc.
|
||||
* Copyright (C) 2004 Texas Instruments.
|
||||
*
|
||||
* Updated to work with multiple I2C interfaces on 24xx by
|
||||
* Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
|
||||
* Copyright (C) 2005 Nokia Corporation
|
||||
*
|
||||
* Cleaned up by Juha Yrjölä <juha.yrjola@nokia.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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
/* timeout waiting for the controller to respond */
|
||||
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
||||
|
||||
#define OMAP_I2C_REV_REG 0x00
|
||||
#define OMAP_I2C_IE_REG 0x04
|
||||
#define OMAP_I2C_STAT_REG 0x08
|
||||
#define OMAP_I2C_IV_REG 0x0c
|
||||
#define OMAP_I2C_SYSS_REG 0x10
|
||||
#define OMAP_I2C_BUF_REG 0x14
|
||||
#define OMAP_I2C_CNT_REG 0x18
|
||||
#define OMAP_I2C_DATA_REG 0x1c
|
||||
#define OMAP_I2C_SYSC_REG 0x20
|
||||
#define OMAP_I2C_CON_REG 0x24
|
||||
#define OMAP_I2C_OA_REG 0x28
|
||||
#define OMAP_I2C_SA_REG 0x2c
|
||||
#define OMAP_I2C_PSC_REG 0x30
|
||||
#define OMAP_I2C_SCLL_REG 0x34
|
||||
#define OMAP_I2C_SCLH_REG 0x38
|
||||
#define OMAP_I2C_SYSTEST_REG 0x3c
|
||||
|
||||
/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
|
||||
#define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */
|
||||
#define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */
|
||||
#define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */
|
||||
#define OMAP_I2C_IE_NACK (1 << 1) /* No ack interrupt enable */
|
||||
#define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */
|
||||
|
||||
/* I2C Status Register (OMAP_I2C_STAT): */
|
||||
#define OMAP_I2C_STAT_SBD (1 << 15) /* Single byte data */
|
||||
#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */
|
||||
#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
|
||||
#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
|
||||
#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */
|
||||
#define OMAP_I2C_STAT_AD0 (1 << 8) /* Address zero */
|
||||
#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
|
||||
#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */
|
||||
#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */
|
||||
#define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */
|
||||
#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */
|
||||
|
||||
/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
|
||||
#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
|
||||
#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
|
||||
|
||||
/* I2C Configuration Register (OMAP_I2C_CON): */
|
||||
#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */
|
||||
#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */
|
||||
#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */
|
||||
#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */
|
||||
#define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */
|
||||
#define OMAP_I2C_CON_XA (1 << 8) /* Expand address */
|
||||
#define OMAP_I2C_CON_RM (1 << 2) /* Repeat mode (master only) */
|
||||
#define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */
|
||||
#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */
|
||||
|
||||
/* I2C System Test Register (OMAP_I2C_SYSTEST): */
|
||||
#ifdef DEBUG
|
||||
#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
|
||||
#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
|
||||
#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
|
||||
#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
|
||||
#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */
|
||||
#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
|
||||
#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
|
||||
#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
|
||||
#endif
|
||||
|
||||
/* I2C System Status register (OMAP_I2C_SYSS): */
|
||||
#define OMAP_I2C_SYSS_RDONE (1 << 0) /* Reset Done */
|
||||
|
||||
/* I2C System Configuration Register (OMAP_I2C_SYSC): */
|
||||
#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */
|
||||
|
||||
/* REVISIT: Use platform_data instead of module parameters */
|
||||
/* Fast Mode = 400 kHz, Standard = 100 kHz */
|
||||
static int clock = 100; /* Default: 100 kHz */
|
||||
module_param(clock, int, 0);
|
||||
MODULE_PARM_DESC(clock, "Set I2C clock in kHz: 400=fast mode (default == 100)");
|
||||
|
||||
struct omap_i2c_dev {
|
||||
struct device *dev;
|
||||
void __iomem *base; /* virtual */
|
||||
int irq;
|
||||
struct clk *iclk; /* Interface clock */
|
||||
struct clk *fclk; /* Functional clock */
|
||||
struct completion cmd_complete;
|
||||
struct resource *ioarea;
|
||||
u16 cmd_err;
|
||||
u8 *buf;
|
||||
size_t buf_len;
|
||||
struct i2c_adapter adapter;
|
||||
unsigned rev1:1;
|
||||
};
|
||||
|
||||
static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
|
||||
int reg, u16 val)
|
||||
{
|
||||
__raw_writew(val, i2c_dev->base + reg);
|
||||
}
|
||||
|
||||
static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
|
||||
{
|
||||
return __raw_readw(i2c_dev->base + reg);
|
||||
}
|
||||
|
||||
static int omap_i2c_get_clocks(struct omap_i2c_dev *dev)
|
||||
{
|
||||
if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
|
||||
dev->iclk = clk_get(dev->dev, "i2c_ick");
|
||||
if (IS_ERR(dev->iclk)) {
|
||||
dev->iclk = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
dev->fclk = clk_get(dev->dev, "i2c_fck");
|
||||
if (IS_ERR(dev->fclk)) {
|
||||
if (dev->iclk != NULL) {
|
||||
clk_put(dev->iclk);
|
||||
dev->iclk = NULL;
|
||||
}
|
||||
dev->fclk = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
|
||||
{
|
||||
clk_put(dev->fclk);
|
||||
dev->fclk = NULL;
|
||||
if (dev->iclk != NULL) {
|
||||
clk_put(dev->iclk);
|
||||
dev->iclk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_i2c_enable_clocks(struct omap_i2c_dev *dev)
|
||||
{
|
||||
if (dev->iclk != NULL)
|
||||
clk_enable(dev->iclk);
|
||||
clk_enable(dev->fclk);
|
||||
}
|
||||
|
||||
static void omap_i2c_disable_clocks(struct omap_i2c_dev *dev)
|
||||
{
|
||||
if (dev->iclk != NULL)
|
||||
clk_disable(dev->iclk);
|
||||
clk_disable(dev->fclk);
|
||||
}
|
||||
|
||||
static int omap_i2c_init(struct omap_i2c_dev *dev)
|
||||
{
|
||||
u16 psc = 0;
|
||||
unsigned long fclk_rate = 12000000;
|
||||
unsigned long timeout;
|
||||
|
||||
if (!dev->rev1) {
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
|
||||
/* For some reason we need to set the EN bit before the
|
||||
* reset done bit gets set. */
|
||||
timeout = jiffies + OMAP_I2C_TIMEOUT;
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
||||
while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) &
|
||||
OMAP_I2C_SYSS_RDONE)) {
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_warn(dev->dev, "timeout waiting"
|
||||
"for controller reset\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
}
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
||||
|
||||
if (cpu_class_is_omap1()) {
|
||||
struct clk *armxor_ck;
|
||||
|
||||
armxor_ck = clk_get(NULL, "armxor_ck");
|
||||
if (IS_ERR(armxor_ck))
|
||||
dev_warn(dev->dev, "Could not get armxor_ck\n");
|
||||
else {
|
||||
fclk_rate = clk_get_rate(armxor_ck);
|
||||
clk_put(armxor_ck);
|
||||
}
|
||||
/* TRM for 5912 says the I2C clock must be prescaled to be
|
||||
* between 7 - 12 MHz. The XOR input clock is typically
|
||||
* 12, 13 or 19.2 MHz. So we should have code that produces:
|
||||
*
|
||||
* XOR MHz Divider Prescaler
|
||||
* 12 1 0
|
||||
* 13 2 1
|
||||
* 19.2 2 1
|
||||
*/
|
||||
if (fclk_rate > 16000000)
|
||||
psc = (fclk_rate + 8000000) / 12000000;
|
||||
}
|
||||
|
||||
/* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
|
||||
|
||||
/* Program desired operating rate */
|
||||
fclk_rate /= (psc + 1) * 1000;
|
||||
if (psc > 2)
|
||||
psc = 2;
|
||||
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG,
|
||||
fclk_rate / (clock * 2) - 7 + psc);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG,
|
||||
fclk_rate / (clock * 2) - 7 + psc);
|
||||
|
||||
/* Take the I2C module out of reset: */
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
||||
|
||||
/* Enable interrupts */
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG,
|
||||
(OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
|
||||
OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
|
||||
OMAP_I2C_IE_AL));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Waiting on Bus Busy
|
||||
*/
|
||||
static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
||||
timeout = jiffies + OMAP_I2C_TIMEOUT;
|
||||
while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_warn(dev->dev, "timeout waiting for bus ready\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Low level master read/write transaction.
|
||||
*/
|
||||
static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msg, int stop)
|
||||
{
|
||||
struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||
int r;
|
||||
u16 w;
|
||||
|
||||
dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
|
||||
msg->addr, msg->len, msg->flags, stop);
|
||||
|
||||
if (msg->len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
|
||||
|
||||
/* REVISIT: Could the STB bit of I2C_CON be used with probing? */
|
||||
dev->buf = msg->buf;
|
||||
dev->buf_len = msg->len;
|
||||
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
|
||||
|
||||
init_completion(&dev->cmd_complete);
|
||||
dev->cmd_err = 0;
|
||||
|
||||
w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
|
||||
if (msg->flags & I2C_M_TEN)
|
||||
w |= OMAP_I2C_CON_XA;
|
||||
if (!(msg->flags & I2C_M_RD))
|
||||
w |= OMAP_I2C_CON_TRX;
|
||||
if (stop)
|
||||
w |= OMAP_I2C_CON_STP;
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
|
||||
|
||||
r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
|
||||
OMAP_I2C_TIMEOUT);
|
||||
dev->buf_len = 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
dev_err(dev->dev, "controller timed out\n");
|
||||
omap_i2c_init(dev);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (likely(!dev->cmd_err))
|
||||
return 0;
|
||||
|
||||
/* We have an error */
|
||||
if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
|
||||
OMAP_I2C_STAT_XUDF)) {
|
||||
omap_i2c_init(dev);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
|
||||
if (msg->flags & I2C_M_IGNORE_NAK)
|
||||
return 0;
|
||||
if (stop) {
|
||||
w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
|
||||
w |= OMAP_I2C_CON_STP;
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
|
||||
}
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prepare controller for a transaction and call omap_i2c_xfer_msg
|
||||
* to do the work during IRQ processing.
|
||||
*/
|
||||
static int
|
||||
omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
int r;
|
||||
|
||||
omap_i2c_enable_clocks(dev);
|
||||
|
||||
/* REVISIT: initialize and use adap->retries. This is an optional
|
||||
* feature */
|
||||
if ((r = omap_i2c_wait_for_bb(dev)) < 0)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
|
||||
if (r != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (r == 0)
|
||||
r = num;
|
||||
out:
|
||||
omap_i2c_disable_clocks(dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
static u32
|
||||
omap_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||
}
|
||||
|
||||
static inline void
|
||||
omap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err)
|
||||
{
|
||||
dev->cmd_err |= err;
|
||||
complete(&dev->cmd_complete);
|
||||
}
|
||||
|
||||
static inline void
|
||||
omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
|
||||
{
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
omap_i2c_rev1_isr(int this_irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
struct omap_i2c_dev *dev = dev_id;
|
||||
u16 iv, w;
|
||||
|
||||
iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
|
||||
switch (iv) {
|
||||
case 0x00: /* None */
|
||||
break;
|
||||
case 0x01: /* Arbitration lost */
|
||||
dev_err(dev->dev, "Arbitration lost\n");
|
||||
omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
|
||||
break;
|
||||
case 0x02: /* No acknowledgement */
|
||||
omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
|
||||
break;
|
||||
case 0x03: /* Register access ready */
|
||||
omap_i2c_complete_cmd(dev, 0);
|
||||
break;
|
||||
case 0x04: /* Receive data ready */
|
||||
if (dev->buf_len) {
|
||||
w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
|
||||
*dev->buf++ = w;
|
||||
dev->buf_len--;
|
||||
if (dev->buf_len) {
|
||||
*dev->buf++ = w >> 8;
|
||||
dev->buf_len--;
|
||||
}
|
||||
} else
|
||||
dev_err(dev->dev, "RRDY IRQ while no data requested\n");
|
||||
break;
|
||||
case 0x05: /* Transmit data ready */
|
||||
if (dev->buf_len) {
|
||||
w = *dev->buf++;
|
||||
dev->buf_len--;
|
||||
if (dev->buf_len) {
|
||||
w |= *dev->buf++ << 8;
|
||||
dev->buf_len--;
|
||||
}
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
|
||||
} else
|
||||
dev_err(dev->dev, "XRDY IRQ while no data to send\n");
|
||||
break;
|
||||
default:
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
omap_i2c_isr(int this_irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
struct omap_i2c_dev *dev = dev_id;
|
||||
u16 bits;
|
||||
u16 stat, w;
|
||||
int count = 0;
|
||||
|
||||
bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
|
||||
while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
|
||||
dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
|
||||
if (count++ == 100) {
|
||||
dev_warn(dev->dev, "Too much work in one IRQ\n");
|
||||
break;
|
||||
}
|
||||
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
|
||||
|
||||
if (stat & OMAP_I2C_STAT_ARDY) {
|
||||
omap_i2c_complete_cmd(dev, 0);
|
||||
continue;
|
||||
}
|
||||
if (stat & OMAP_I2C_STAT_RRDY) {
|
||||
w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
|
||||
if (dev->buf_len) {
|
||||
*dev->buf++ = w;
|
||||
dev->buf_len--;
|
||||
if (dev->buf_len) {
|
||||
*dev->buf++ = w >> 8;
|
||||
dev->buf_len--;
|
||||
}
|
||||
} else
|
||||
dev_err(dev->dev, "RRDY IRQ while no data"
|
||||
"requested\n");
|
||||
omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
|
||||
continue;
|
||||
}
|
||||
if (stat & OMAP_I2C_STAT_XRDY) {
|
||||
w = 0;
|
||||
if (dev->buf_len) {
|
||||
w = *dev->buf++;
|
||||
dev->buf_len--;
|
||||
if (dev->buf_len) {
|
||||
w |= *dev->buf++ << 8;
|
||||
dev->buf_len--;
|
||||
}
|
||||
} else
|
||||
dev_err(dev->dev, "XRDY IRQ while no"
|
||||
"data to send\n");
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
|
||||
omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
|
||||
continue;
|
||||
}
|
||||
if (stat & OMAP_I2C_STAT_ROVR) {
|
||||
dev_err(dev->dev, "Receive overrun\n");
|
||||
dev->cmd_err |= OMAP_I2C_STAT_ROVR;
|
||||
}
|
||||
if (stat & OMAP_I2C_STAT_XUDF) {
|
||||
dev_err(dev->dev, "Transmit overflow\n");
|
||||
dev->cmd_err |= OMAP_I2C_STAT_XUDF;
|
||||
}
|
||||
if (stat & OMAP_I2C_STAT_NACK) {
|
||||
omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
|
||||
OMAP_I2C_CON_STP);
|
||||
}
|
||||
if (stat & OMAP_I2C_STAT_AL) {
|
||||
dev_err(dev->dev, "Arbitration lost\n");
|
||||
omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
|
||||
}
|
||||
}
|
||||
|
||||
return count ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm omap_i2c_algo = {
|
||||
.master_xfer = omap_i2c_xfer,
|
||||
.functionality = omap_i2c_func,
|
||||
};
|
||||
|
||||
static int
|
||||
omap_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_i2c_dev *dev;
|
||||
struct i2c_adapter *adap;
|
||||
struct resource *mem, *irq, *ioarea;
|
||||
int r;
|
||||
|
||||
/* NOTE: driver uses the static register mapping */
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem) {
|
||||
dev_err(&pdev->dev, "no mem resource?\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!irq) {
|
||||
dev_err(&pdev->dev, "no irq resource?\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
|
||||
pdev->name);
|
||||
if (!ioarea) {
|
||||
dev_err(&pdev->dev, "I2C region already claimed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (clock > 200)
|
||||
clock = 400; /* Fast mode */
|
||||
else
|
||||
clock = 100; /* Standard mode */
|
||||
|
||||
dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
r = -ENOMEM;
|
||||
goto err_release_region;
|
||||
}
|
||||
|
||||
dev->dev = &pdev->dev;
|
||||
dev->irq = irq->start;
|
||||
dev->base = (void __iomem *) IO_ADDRESS(mem->start);
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
if ((r = omap_i2c_get_clocks(dev)) != 0)
|
||||
goto err_free_mem;
|
||||
|
||||
omap_i2c_enable_clocks(dev);
|
||||
|
||||
if (cpu_is_omap15xx())
|
||||
dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
|
||||
|
||||
/* reset ASAP, clearing any IRQs */
|
||||
omap_i2c_init(dev);
|
||||
|
||||
r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr,
|
||||
0, pdev->name, dev);
|
||||
|
||||
if (r) {
|
||||
dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
|
||||
goto err_unuse_clocks;
|
||||
}
|
||||
r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
|
||||
dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
|
||||
pdev->id, r >> 4, r & 0xf, clock);
|
||||
|
||||
adap = &dev->adapter;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_HWMON;
|
||||
strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
|
||||
adap->algo = &omap_i2c_algo;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
|
||||
/* i2c device drivers may be active on return from add_adapter() */
|
||||
r = i2c_add_adapter(adap);
|
||||
if (r) {
|
||||
dev_err(dev->dev, "failure adding adapter\n");
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
omap_i2c_disable_clocks(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(dev->irq, dev);
|
||||
err_unuse_clocks:
|
||||
omap_i2c_disable_clocks(dev);
|
||||
omap_i2c_put_clocks(dev);
|
||||
err_free_mem:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(dev);
|
||||
err_release_region:
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
||||
release_mem_region(mem->start, (mem->end - mem->start) + 1);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
omap_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
struct resource *mem;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
free_irq(dev->irq, dev);
|
||||
i2c_del_adapter(&dev->adapter);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
||||
omap_i2c_put_clocks(dev);
|
||||
kfree(dev);
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(mem->start, (mem->end - mem->start) + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver omap_i2c_driver = {
|
||||
.probe = omap_i2c_probe,
|
||||
.remove = omap_i2c_remove,
|
||||
.driver = {
|
||||
.name = "i2c_omap",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
/* I2C may be needed to bring up other drivers */
|
||||
static int __init
|
||||
omap_i2c_init_driver(void)
|
||||
{
|
||||
return platform_driver_register(&omap_i2c_driver);
|
||||
}
|
||||
subsys_initcall(omap_i2c_init_driver);
|
||||
|
||||
static void __exit omap_i2c_exit_driver(void)
|
||||
{
|
||||
platform_driver_unregister(&omap_i2c_driver);
|
||||
}
|
||||
module_exit(omap_i2c_exit_driver);
|
||||
|
||||
MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
|
||||
MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -103,7 +103,6 @@ static struct i2c_algo_bit_data parport_algo_data = {
|
|||
.getsda = parport_getsda,
|
||||
.getscl = parport_getscl,
|
||||
.udelay = 50,
|
||||
.mdelay = 50,
|
||||
.timeout = HZ,
|
||||
};
|
||||
|
||||
|
|
|
@ -138,7 +138,6 @@ static struct i2c_algo_bit_data parport_algo_data = {
|
|||
.getsda = parport_getsda,
|
||||
.getscl = parport_getscl,
|
||||
.udelay = 60,
|
||||
.mdelay = 60,
|
||||
.timeout = HZ,
|
||||
};
|
||||
|
||||
|
|
|
@ -376,7 +376,7 @@ static u32 piix4_func(struct i2c_adapter *adapter)
|
|||
I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = piix4_access,
|
||||
.functionality = piix4_func,
|
||||
};
|
||||
|
|
|
@ -175,7 +175,7 @@ static u32 i2c_powermac_func(struct i2c_adapter * adapter)
|
|||
}
|
||||
|
||||
/* For now, we only handle smbus */
|
||||
static struct i2c_algorithm i2c_powermac_algorithm = {
|
||||
static const struct i2c_algorithm i2c_powermac_algorithm = {
|
||||
.smbus_xfer = i2c_powermac_smbus_xfer,
|
||||
.master_xfer = i2c_powermac_master_xfer,
|
||||
.functionality = i2c_powermac_func,
|
||||
|
|
|
@ -180,7 +180,6 @@ static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, void __iom
|
|||
p->algo.getsda = bit_s3via_getsda;
|
||||
p->algo.getscl = bit_s3via_getscl;
|
||||
p->algo.udelay = CYCLE_DELAY;
|
||||
p->algo.mdelay = CYCLE_DELAY;
|
||||
p->algo.timeout = TIMEOUT;
|
||||
p->algo.data = p;
|
||||
p->mmvga = mmvga;
|
||||
|
|
|
@ -926,7 +926,7 @@ static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
|
|||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm i2c_pxa_algorithm = {
|
||||
static const struct i2c_algorithm i2c_pxa_algorithm = {
|
||||
.master_xfer = i2c_pxa_xfer,
|
||||
.functionality = i2c_pxa_functionality,
|
||||
};
|
||||
|
|
|
@ -566,7 +566,7 @@ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
|
|||
|
||||
/* i2c bus registration info */
|
||||
|
||||
static struct i2c_algorithm s3c24xx_i2c_algorithm = {
|
||||
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
|
||||
.master_xfer = s3c24xx_i2c_xfer,
|
||||
.functionality = s3c24xx_i2c_func,
|
||||
};
|
||||
|
|
|
@ -140,7 +140,6 @@ static struct i2c_algo_bit_data sav_i2c_bit_data = {
|
|||
.getsda = bit_savi2c_getsda,
|
||||
.getscl = bit_savi2c_getscl,
|
||||
.udelay = CYCLE_DELAY,
|
||||
.mdelay = CYCLE_DELAY,
|
||||
.timeout = TIMEOUT
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (C) 2004 Steven J. Hill
|
||||
* Copyright (C) 2001,2002,2003 Broadcom Corporation
|
||||
* Copyright (C) 1995-2000 Simon G. Vogl
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -17,11 +18,162 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c-algo-sibyte.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/sibyte/sb1250_regs.h>
|
||||
#include <asm/sibyte/sb1250_smbus.h>
|
||||
|
||||
|
||||
struct i2c_algo_sibyte_data {
|
||||
void *data; /* private data */
|
||||
int bus; /* which bus */
|
||||
void *reg_base; /* CSR base */
|
||||
};
|
||||
|
||||
/* ----- global defines ----------------------------------------------- */
|
||||
#define SMB_CSR(a,r) ((long)(a->reg_base + r))
|
||||
|
||||
/* ----- global variables --------------------------------------------- */
|
||||
|
||||
/* module parameters:
|
||||
*/
|
||||
static int bit_scan; /* have a look at what's hanging 'round */
|
||||
module_param(bit_scan, int, 0);
|
||||
MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
|
||||
|
||||
|
||||
static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data * data)
|
||||
{
|
||||
struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
|
||||
int data_bytes = 0;
|
||||
int error;
|
||||
|
||||
while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
|
||||
;
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_QUICK:
|
||||
csr_out32((V_SMB_ADDR(addr) |
|
||||
(read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
|
||||
V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
|
||||
break;
|
||||
case I2C_SMBUS_BYTE:
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
data_bytes = 1;
|
||||
} else {
|
||||
csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
}
|
||||
break;
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
data_bytes = 1;
|
||||
} else {
|
||||
csr_out32(V_SMB_LB(data->byte),
|
||||
SMB_CSR(adap, R_SMB_DATA));
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
}
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
data_bytes = 2;
|
||||
} else {
|
||||
csr_out32(V_SMB_LB(data->word & 0xff),
|
||||
SMB_CSR(adap, R_SMB_DATA));
|
||||
csr_out32(V_SMB_MB(data->word >> 8),
|
||||
SMB_CSR(adap, R_SMB_DATA));
|
||||
csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
|
||||
SMB_CSR(adap, R_SMB_START));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -1; /* XXXKW better error code? */
|
||||
}
|
||||
|
||||
while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
|
||||
;
|
||||
|
||||
error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
|
||||
if (error & M_SMB_ERROR) {
|
||||
/* Clear error bit by writing a 1 */
|
||||
csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
|
||||
return -1; /* XXXKW better error code? */
|
||||
}
|
||||
|
||||
if (data_bytes == 1)
|
||||
data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
|
||||
if (data_bytes == 2)
|
||||
data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 bit_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
|
||||
}
|
||||
|
||||
|
||||
/* -----exported algorithm data: ------------------------------------- */
|
||||
|
||||
static const struct i2c_algorithm i2c_sibyte_algo = {
|
||||
.smbus_xfer = smbus_xfer,
|
||||
.functionality = bit_func,
|
||||
};
|
||||
|
||||
/*
|
||||
* registering functions to load algorithms at runtime
|
||||
*/
|
||||
int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
|
||||
{
|
||||
int i;
|
||||
struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
|
||||
|
||||
/* register new adapter to i2c module... */
|
||||
i2c_adap->algo = &i2c_sibyte_algo;
|
||||
|
||||
/* Set the frequency to 100 kHz */
|
||||
csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
|
||||
csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
|
||||
|
||||
/* scan bus */
|
||||
if (bit_scan) {
|
||||
union i2c_smbus_data data;
|
||||
int rc;
|
||||
printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
|
||||
i2c_adap->name);
|
||||
for (i = 0x00; i < 0x7f; i++) {
|
||||
/* XXXKW is this a realistic probe? */
|
||||
rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
|
||||
I2C_SMBUS_BYTE_DATA, &data);
|
||||
if (!rc) {
|
||||
printk("(%02x)",i);
|
||||
} else
|
||||
printk(".");
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
return i2c_add_adapter(i2c_adap);
|
||||
}
|
||||
|
||||
|
||||
static struct i2c_algo_sibyte_data sibyte_board_data[2] = {
|
||||
{ NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) },
|
||||
{ NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) }
|
||||
|
@ -58,13 +210,13 @@ static int __init i2c_sibyte_init(void)
|
|||
|
||||
static void __exit i2c_sibyte_exit(void)
|
||||
{
|
||||
i2c_sibyte_del_bus(&sibyte_board_adapter[0]);
|
||||
i2c_sibyte_del_bus(&sibyte_board_adapter[1]);
|
||||
i2c_del_bus(&sibyte_board_adapter[0]);
|
||||
i2c_del_bus(&sibyte_board_adapter[1]);
|
||||
}
|
||||
|
||||
module_init(i2c_sibyte_init);
|
||||
module_exit(i2c_sibyte_exit);
|
||||
|
||||
MODULE_AUTHOR("Kip Walker <kwalker@broadcom.com>, Steven J. Hill <sjhill@realitydiluted.com>");
|
||||
MODULE_AUTHOR("Kip Walker (Broadcom Corp.), Steven J. Hill <sjhill@realitydiluted.com>");
|
||||
MODULE_DESCRIPTION("SMBus adapter routines for SiByte boards");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -358,7 +358,7 @@ static u32 sis5595_func(struct i2c_adapter *adapter)
|
|||
I2C_FUNC_SMBUS_PROC_CALL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = sis5595_access,
|
||||
.functionality = sis5595_func,
|
||||
};
|
||||
|
|
|
@ -450,7 +450,7 @@ exit:
|
|||
}
|
||||
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = sis630_access,
|
||||
.functionality = sis630_func,
|
||||
};
|
||||
|
|
|
@ -242,7 +242,7 @@ static u32 sis96x_func(struct i2c_adapter *adapter)
|
|||
I2C_FUNC_SMBUS_PROC_CALL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = sis96x_access,
|
||||
.functionality = sis96x_func,
|
||||
};
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
static unsigned short chip_addr;
|
||||
module_param(chip_addr, ushort, S_IRUGO);
|
||||
MODULE_PARM_DESC(chip_addr, "Chip address (between 0x03 and 0x77)\n");
|
||||
|
||||
static u8 stub_pointer;
|
||||
static u8 stub_bytes[256];
|
||||
static u16 stub_words[256];
|
||||
|
@ -37,6 +41,9 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
|
|||
{
|
||||
s32 ret;
|
||||
|
||||
if (addr != chip_addr)
|
||||
return -ENODEV;
|
||||
|
||||
switch (size) {
|
||||
|
||||
case I2C_SMBUS_QUICK:
|
||||
|
@ -108,7 +115,7 @@ static u32 stub_func(struct i2c_adapter *adapter)
|
|||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.functionality = stub_func,
|
||||
.smbus_xfer = stub_xfer,
|
||||
};
|
||||
|
@ -122,7 +129,17 @@ static struct i2c_adapter stub_adapter = {
|
|||
|
||||
static int __init i2c_stub_init(void)
|
||||
{
|
||||
printk(KERN_INFO "i2c-stub loaded\n");
|
||||
if (!chip_addr) {
|
||||
printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (chip_addr < 0x03 || chip_addr > 0x77) {
|
||||
printk(KERN_ERR "i2c-stub: Invalid chip address 0x%02x\n",
|
||||
chip_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", chip_addr);
|
||||
return i2c_add_adapter(&stub_adapter);
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,6 @@ static struct i2c_algo_bit_data bit_data = {
|
|||
.getsda = bit_via_getsda,
|
||||
.getscl = bit_via_getscl,
|
||||
.udelay = 5,
|
||||
.mdelay = 5,
|
||||
.timeout = HZ
|
||||
};
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
VT8233A 0x3147 yes?
|
||||
VT8235 0x3177 yes
|
||||
VT8237R 0x3227 yes
|
||||
VT8237A 0x3337 yes
|
||||
VT8251 0x3287 yes
|
||||
|
||||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
*/
|
||||
|
@ -297,7 +299,7 @@ static u32 vt596_func(struct i2c_adapter *adapter)
|
|||
return func;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = vt596_access,
|
||||
.functionality = vt596_func,
|
||||
};
|
||||
|
@ -381,7 +383,9 @@ found:
|
|||
dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
|
||||
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_VIA_8251:
|
||||
case PCI_DEVICE_ID_VIA_8237:
|
||||
case PCI_DEVICE_ID_VIA_8237A:
|
||||
case PCI_DEVICE_ID_VIA_8235:
|
||||
case PCI_DEVICE_ID_VIA_8233A:
|
||||
case PCI_DEVICE_ID_VIA_8233_0:
|
||||
|
@ -432,8 +436,12 @@ static struct pci_device_id vt596_ids[] = {
|
|||
.driver_data = SMBBA3 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237),
|
||||
.driver_data = SMBBA3 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
|
||||
.driver_data = SMBBA3 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
|
||||
.driver_data = SMBBA1 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
|
||||
.driver_data = SMBBA3 },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
|
|
|
@ -160,7 +160,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = {
|
|||
.getsda = bit_vooi2c_getsda,
|
||||
.getscl = bit_vooi2c_getscl,
|
||||
.udelay = CYCLE_DELAY,
|
||||
.mdelay = CYCLE_DELAY,
|
||||
.timeout = TIMEOUT
|
||||
};
|
||||
|
||||
|
@ -177,7 +176,6 @@ static struct i2c_algo_bit_data voo_ddc_bit_data = {
|
|||
.getsda = bit_vooddc_getsda,
|
||||
.getscl = bit_vooddc_getscl,
|
||||
.udelay = CYCLE_DELAY,
|
||||
.mdelay = CYCLE_DELAY,
|
||||
.timeout = TIMEOUT
|
||||
};
|
||||
|
||||
|
|
|
@ -383,7 +383,7 @@ static u32 scx200_acb_func(struct i2c_adapter *adapter)
|
|||
}
|
||||
|
||||
/* For now, we only handle combined mode (smbus) */
|
||||
static struct i2c_algorithm scx200_acb_algorithm = {
|
||||
static const struct i2c_algorithm scx200_acb_algorithm = {
|
||||
.smbus_xfer = scx200_acb_smbus_xfer,
|
||||
.functionality = scx200_acb_func,
|
||||
};
|
||||
|
|
|
@ -71,12 +71,12 @@ static int scx200_i2c_getsda(void *data)
|
|||
*/
|
||||
|
||||
static struct i2c_algo_bit_data scx200_i2c_data = {
|
||||
NULL,
|
||||
scx200_i2c_setsda,
|
||||
scx200_i2c_setscl,
|
||||
scx200_i2c_getsda,
|
||||
scx200_i2c_getscl,
|
||||
10, 10, 100, /* waits, timeout */
|
||||
.setsda = scx200_i2c_setsda,
|
||||
.setscl = scx200_i2c_setscl,
|
||||
.getsda = scx200_i2c_getsda,
|
||||
.getscl = scx200_i2c_getscl,
|
||||
.udelay = 10,
|
||||
.timeout = 100,
|
||||
};
|
||||
|
||||
static struct i2c_adapter scx200_i2c_ops = {
|
||||
|
|
|
@ -209,10 +209,14 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
}
|
||||
|
||||
/* create the sysfs eeprom file */
|
||||
sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
|
||||
err = sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
|
||||
if (err)
|
||||
goto exit_detach;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_kfree:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
@ -223,6 +227,8 @@ static int eeprom_detach_client(struct i2c_client *client)
|
|||
{
|
||||
int err;
|
||||
|
||||
sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -199,8 +199,7 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Init fake client data */
|
||||
/* set the client data to the i2c_client so that it will get freed */
|
||||
i2c_set_clientdata(fake_client, fake_client);
|
||||
i2c_set_clientdata(fake_client, NULL);
|
||||
fake_client->addr = address | 1;
|
||||
fake_client->adapter = adapter;
|
||||
fake_client->driver = &max6875_driver;
|
||||
|
@ -214,13 +213,17 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
goto exit_kfree2;
|
||||
|
||||
if ((err = i2c_attach_client(fake_client)) != 0)
|
||||
goto exit_detach;
|
||||
goto exit_detach1;
|
||||
|
||||
sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
|
||||
err = sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
|
||||
if (err)
|
||||
goto exit_detach2;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_detach:
|
||||
exit_detach2:
|
||||
i2c_detach_client(fake_client);
|
||||
exit_detach1:
|
||||
i2c_detach_client(real_client);
|
||||
exit_kfree2:
|
||||
kfree(fake_client);
|
||||
|
@ -229,14 +232,24 @@ exit_kfree1:
|
|||
return err;
|
||||
}
|
||||
|
||||
/* Will be called for both the real client and the fake client */
|
||||
static int max6875_detach_client(struct i2c_client *client)
|
||||
{
|
||||
int err;
|
||||
struct max6875_data *data = i2c_get_clientdata(client);
|
||||
|
||||
/* data is NULL for the fake client */
|
||||
if (data)
|
||||
sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err)
|
||||
return err;
|
||||
kfree(i2c_get_clientdata(client));
|
||||
|
||||
if (data) /* real client */
|
||||
kfree(data);
|
||||
else /* fake client */
|
||||
kfree(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -148,11 +148,16 @@ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
if ((err = i2c_attach_client(new_client)))
|
||||
goto exit_kfree;
|
||||
|
||||
/* Register sysfs hooks (don't care about failure) */
|
||||
sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group);
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&new_client->dev.kobj,
|
||||
&pca9539_defattr_group);
|
||||
if (err)
|
||||
goto exit_detach;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_kfree:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
@ -163,6 +168,8 @@ static int pca9539_detach_client(struct i2c_client *client)
|
|||
{
|
||||
int err;
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &pca9539_defattr_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
||||
|
|
|
@ -105,6 +105,16 @@ static ssize_t set_write(struct device *dev, struct device_attribute *attr, cons
|
|||
|
||||
static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
|
||||
|
||||
static struct attribute *pcf8574_attributes[] = {
|
||||
&dev_attr_read.attr,
|
||||
&dev_attr_write.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group pcf8574_attr_group = {
|
||||
.attrs = pcf8574_attributes,
|
||||
};
|
||||
|
||||
/*
|
||||
* Real code
|
||||
*/
|
||||
|
@ -166,13 +176,13 @@ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
pcf8574_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
device_create_file(&new_client->dev, &dev_attr_read);
|
||||
device_create_file(&new_client->dev, &dev_attr_write);
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &pcf8574_attr_group);
|
||||
if (err)
|
||||
goto exit_detach;
|
||||
return 0;
|
||||
|
||||
/* OK, this is not exactly good programming practice, usually. But it is
|
||||
very code-efficient in this case. */
|
||||
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
@ -183,6 +193,8 @@ static int pcf8574_detach_client(struct i2c_client *client)
|
|||
{
|
||||
int err;
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
||||
|
|
|
@ -158,6 +158,28 @@ static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr
|
|||
static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO,
|
||||
show_out0_enable, set_out0_enable);
|
||||
|
||||
static struct attribute *pcf8591_attributes[] = {
|
||||
&dev_attr_out0_enable.attr,
|
||||
&dev_attr_out0_output.attr,
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group pcf8591_attr_group = {
|
||||
.attrs = pcf8591_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *pcf8591_attributes_opt[] = {
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group pcf8591_attr_group_opt = {
|
||||
.attrs = pcf8591_attributes_opt,
|
||||
};
|
||||
|
||||
/*
|
||||
* Real code
|
||||
*/
|
||||
|
@ -211,24 +233,31 @@ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
pcf8591_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
device_create_file(&new_client->dev, &dev_attr_out0_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_out0_output);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &pcf8591_attr_group);
|
||||
if (err)
|
||||
goto exit_detach;
|
||||
|
||||
/* Register input2 if not in "two differential inputs" mode */
|
||||
if (input_mode != 3 )
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
|
||||
/* Register input3 only in "four single ended inputs" mode */
|
||||
if (input_mode == 0)
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
|
||||
return 0;
|
||||
|
||||
/* OK, this is not exactly good programming practice, usually. But it is
|
||||
very code-efficient in this case. */
|
||||
if (input_mode != 3) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in2_input)))
|
||||
goto exit_sysfs_remove;
|
||||
}
|
||||
|
||||
/* Register input3 only in "four single ended inputs" mode */
|
||||
if (input_mode == 0) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in3_input)))
|
||||
goto exit_sysfs_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_sysfs_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group_opt);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_kfree:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
@ -239,6 +268,9 @@ static int pcf8591_detach_client(struct i2c_client *client)
|
|||
{
|
||||
int err;
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
|
||||
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
||||
|
|
|
@ -183,15 +183,21 @@ int i2c_add_adapter(struct i2c_adapter *adap)
|
|||
sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
|
||||
adap->dev.driver = &i2c_adapter_driver;
|
||||
adap->dev.release = &i2c_adapter_dev_release;
|
||||
device_register(&adap->dev);
|
||||
device_create_file(&adap->dev, &dev_attr_name);
|
||||
res = device_register(&adap->dev);
|
||||
if (res)
|
||||
goto out_list;
|
||||
res = device_create_file(&adap->dev, &dev_attr_name);
|
||||
if (res)
|
||||
goto out_unregister;
|
||||
|
||||
/* Add this adapter to the i2c_adapter class */
|
||||
memset(&adap->class_dev, 0x00, sizeof(struct class_device));
|
||||
adap->class_dev.dev = &adap->dev;
|
||||
adap->class_dev.class = &i2c_adapter_class;
|
||||
strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
|
||||
class_device_register(&adap->class_dev);
|
||||
res = class_device_register(&adap->class_dev);
|
||||
if (res)
|
||||
goto out_remove_name;
|
||||
|
||||
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
|
||||
|
||||
|
@ -206,6 +212,17 @@ int i2c_add_adapter(struct i2c_adapter *adap)
|
|||
out_unlock:
|
||||
mutex_unlock(&core_lists);
|
||||
return res;
|
||||
|
||||
out_remove_name:
|
||||
device_remove_file(&adap->dev, &dev_attr_name);
|
||||
out_unregister:
|
||||
init_completion(&adap->dev_released); /* Needed? */
|
||||
device_unregister(&adap->dev);
|
||||
wait_for_completion(&adap->dev_released);
|
||||
out_list:
|
||||
list_del(&adap->list);
|
||||
idr_remove(&i2c_adapter_idr, adap->nr);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
|
||||
|
@ -394,14 +411,14 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr)
|
|||
int i2c_attach_client(struct i2c_client *client)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
int res = 0;
|
||||
|
||||
mutex_lock(&adapter->clist_lock);
|
||||
if (__i2c_check_addr(client->adapter, client->addr)) {
|
||||
mutex_unlock(&adapter->clist_lock);
|
||||
return -EBUSY;
|
||||
res = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
list_add_tail(&client->list,&adapter->clients);
|
||||
mutex_unlock(&adapter->clist_lock);
|
||||
|
||||
if (adapter->client_register) {
|
||||
if (adapter->client_register(client)) {
|
||||
|
@ -422,10 +439,26 @@ int i2c_attach_client(struct i2c_client *client)
|
|||
"%d-%04x", i2c_adapter_id(adapter), client->addr);
|
||||
dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
|
||||
client->name, client->dev.bus_id);
|
||||
device_register(&client->dev);
|
||||
device_create_file(&client->dev, &dev_attr_client_name);
|
||||
|
||||
return 0;
|
||||
res = device_register(&client->dev);
|
||||
if (res)
|
||||
goto out_list;
|
||||
res = device_create_file(&client->dev, &dev_attr_client_name);
|
||||
if (res)
|
||||
goto out_unregister;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&adapter->clist_lock);
|
||||
return res;
|
||||
|
||||
out_unregister:
|
||||
init_completion(&client->released); /* Needed? */
|
||||
device_unregister(&client->dev);
|
||||
wait_for_completion(&client->released);
|
||||
out_list:
|
||||
list_del(&client->list);
|
||||
dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
|
||||
"(%d)\n", client->name, client->addr, res);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
|
||||
|
@ -674,11 +707,16 @@ static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
|
|||
|
||||
/* Finally call the custom detection function */
|
||||
err = found_proc(adapter, addr, kind);
|
||||
|
||||
/* -ENODEV can be returned if there is a chip at the given address
|
||||
but it isn't supported by this chip driver. We catch it here as
|
||||
this isn't an error. */
|
||||
return (err == -ENODEV) ? 0 : err;
|
||||
if (err == -ENODEV)
|
||||
err = 0;
|
||||
|
||||
if (err)
|
||||
dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n",
|
||||
addr, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int i2c_probe(struct i2c_adapter *adapter,
|
||||
|
@ -868,7 +906,7 @@ s32 i2c_smbus_read_byte(struct i2c_client *client)
|
|||
I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))
|
||||
return -1;
|
||||
else
|
||||
return 0x0FF & data.byte;
|
||||
return data.byte;
|
||||
}
|
||||
|
||||
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
|
||||
|
@ -884,7 +922,7 @@ s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
|
|||
I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
|
||||
return -1;
|
||||
else
|
||||
return 0x0FF & data.byte;
|
||||
return data.byte;
|
||||
}
|
||||
|
||||
s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
|
||||
|
@ -903,7 +941,7 @@ s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)
|
|||
I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))
|
||||
return -1;
|
||||
else
|
||||
return 0x0FFFF & data.word;
|
||||
return data.word;
|
||||
}
|
||||
|
||||
s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
|
||||
|
@ -1006,7 +1044,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
|
|||
else {
|
||||
msg[0].len=3;
|
||||
msgbuf0[1] = data->word & 0xff;
|
||||
msgbuf0[2] = (data->word >> 8) & 0xff;
|
||||
msgbuf0[2] = data->word >> 8;
|
||||
}
|
||||
break;
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
|
@ -1015,7 +1053,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
|
|||
msg[0].len = 3;
|
||||
msg[1].len = 2;
|
||||
msgbuf0[1] = data->word & 0xff;
|
||||
msgbuf0[2] = (data->word >> 8) & 0xff;
|
||||
msgbuf0[2] = data->word >> 8;
|
||||
break;
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
|
|
|
@ -32,43 +32,35 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static struct i2c_client i2cdev_client_template;
|
||||
static struct i2c_driver i2cdev_driver;
|
||||
|
||||
struct i2c_dev {
|
||||
int minor;
|
||||
struct list_head list;
|
||||
struct i2c_adapter *adap;
|
||||
struct class_device *class_dev;
|
||||
};
|
||||
#define to_i2c_dev(d) container_of(d, struct i2c_dev, class_dev)
|
||||
|
||||
#define I2C_MINORS 256
|
||||
static struct i2c_dev *i2c_dev_array[I2C_MINORS];
|
||||
static DEFINE_SPINLOCK(i2c_dev_array_lock);
|
||||
static LIST_HEAD(i2c_dev_list);
|
||||
static DEFINE_SPINLOCK(i2c_dev_list_lock);
|
||||
|
||||
static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
|
||||
{
|
||||
struct i2c_dev *i2c_dev;
|
||||
|
||||
spin_lock(&i2c_dev_array_lock);
|
||||
i2c_dev = i2c_dev_array[index];
|
||||
spin_unlock(&i2c_dev_array_lock);
|
||||
return i2c_dev;
|
||||
}
|
||||
|
||||
static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_dev *i2c_dev = NULL;
|
||||
|
||||
spin_lock(&i2c_dev_array_lock);
|
||||
if ((i2c_dev_array[adap->nr]) &&
|
||||
(i2c_dev_array[adap->nr]->adap == adap))
|
||||
i2c_dev = i2c_dev_array[adap->nr];
|
||||
spin_unlock(&i2c_dev_array_lock);
|
||||
spin_lock(&i2c_dev_list_lock);
|
||||
list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
|
||||
if (i2c_dev->adap->nr == index)
|
||||
goto found;
|
||||
}
|
||||
i2c_dev = NULL;
|
||||
found:
|
||||
spin_unlock(&i2c_dev_list_lock);
|
||||
return i2c_dev;
|
||||
}
|
||||
|
||||
|
@ -76,30 +68,28 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
|
|||
{
|
||||
struct i2c_dev *i2c_dev;
|
||||
|
||||
if (adap->nr >= I2C_MINORS) {
|
||||
printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n",
|
||||
adap->nr);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);
|
||||
if (!i2c_dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
i2c_dev->adap = adap;
|
||||
|
||||
spin_lock(&i2c_dev_array_lock);
|
||||
if (i2c_dev_array[adap->nr]) {
|
||||
spin_unlock(&i2c_dev_array_lock);
|
||||
dev_err(&adap->dev, "i2c-dev already has a device assigned to this adapter\n");
|
||||
goto error;
|
||||
}
|
||||
i2c_dev->minor = adap->nr;
|
||||
i2c_dev_array[adap->nr] = i2c_dev;
|
||||
spin_unlock(&i2c_dev_array_lock);
|
||||
spin_lock(&i2c_dev_list_lock);
|
||||
list_add_tail(&i2c_dev->list, &i2c_dev_list);
|
||||
spin_unlock(&i2c_dev_list_lock);
|
||||
return i2c_dev;
|
||||
error:
|
||||
kfree(i2c_dev);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static void return_i2c_dev(struct i2c_dev *i2c_dev)
|
||||
{
|
||||
spin_lock(&i2c_dev_array_lock);
|
||||
i2c_dev_array[i2c_dev->minor] = NULL;
|
||||
spin_unlock(&i2c_dev_array_lock);
|
||||
spin_lock(&i2c_dev_list_lock);
|
||||
list_del(&i2c_dev->list);
|
||||
spin_unlock(&i2c_dev_list_lock);
|
||||
}
|
||||
|
||||
static ssize_t show_adapter_name(struct class_device *class_dev, char *buf)
|
||||
|
@ -375,12 +365,13 @@ static int i2cdev_open(struct inode *inode, struct file *file)
|
|||
if (!adap)
|
||||
return -ENODEV;
|
||||
|
||||
client = kmalloc(sizeof(*client), GFP_KERNEL);
|
||||
client = kzalloc(sizeof(*client), GFP_KERNEL);
|
||||
if (!client) {
|
||||
i2c_put_adapter(adap);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(client, &i2cdev_client_template, sizeof(*client));
|
||||
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
|
||||
client->driver = &i2cdev_driver;
|
||||
|
||||
/* registered with adapter, passed as client to user */
|
||||
client->adapter = adap;
|
||||
|
@ -415,41 +406,47 @@ static struct class *i2c_dev_class;
|
|||
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_dev *i2c_dev;
|
||||
struct device *dev;
|
||||
int res;
|
||||
|
||||
i2c_dev = get_free_i2c_dev(adap);
|
||||
if (IS_ERR(i2c_dev))
|
||||
return PTR_ERR(i2c_dev);
|
||||
|
||||
pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
|
||||
adap->name, i2c_dev->minor);
|
||||
|
||||
/* register this i2c device with the driver core */
|
||||
i2c_dev->adap = adap;
|
||||
dev = &adap->dev;
|
||||
i2c_dev->class_dev = class_device_create(i2c_dev_class, NULL,
|
||||
MKDEV(I2C_MAJOR, i2c_dev->minor),
|
||||
dev, "i2c-%d", i2c_dev->minor);
|
||||
if (!i2c_dev->class_dev)
|
||||
MKDEV(I2C_MAJOR, adap->nr),
|
||||
&adap->dev, "i2c-%d",
|
||||
adap->nr);
|
||||
if (!i2c_dev->class_dev) {
|
||||
res = -ENODEV;
|
||||
goto error;
|
||||
class_device_create_file(i2c_dev->class_dev, &class_device_attr_name);
|
||||
}
|
||||
res = class_device_create_file(i2c_dev->class_dev, &class_device_attr_name);
|
||||
if (res)
|
||||
goto error_destroy;
|
||||
|
||||
pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
|
||||
adap->name, adap->nr);
|
||||
return 0;
|
||||
error_destroy:
|
||||
class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
|
||||
error:
|
||||
return_i2c_dev(i2c_dev);
|
||||
kfree(i2c_dev);
|
||||
return -ENODEV;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int i2cdev_detach_adapter(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_dev *i2c_dev;
|
||||
|
||||
i2c_dev = i2c_dev_get_by_adapter(adap);
|
||||
if (!i2c_dev)
|
||||
return -ENODEV;
|
||||
i2c_dev = i2c_dev_get_by_minor(adap->nr);
|
||||
if (!i2c_dev) /* attach_adapter must have failed */
|
||||
return 0;
|
||||
|
||||
class_device_remove_file(i2c_dev->class_dev, &class_device_attr_name);
|
||||
return_i2c_dev(i2c_dev);
|
||||
class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, i2c_dev->minor));
|
||||
class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
|
||||
kfree(i2c_dev);
|
||||
|
||||
pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
|
||||
|
@ -471,12 +468,6 @@ static struct i2c_driver i2cdev_driver = {
|
|||
.detach_client = i2cdev_detach_client,
|
||||
};
|
||||
|
||||
static struct i2c_client i2cdev_client_template = {
|
||||
.name = "I2C /dev entry",
|
||||
.addr = -1,
|
||||
.driver = &i2cdev_driver,
|
||||
};
|
||||
|
||||
static int __init i2c_dev_init(void)
|
||||
{
|
||||
int res;
|
||||
|
|
|
@ -137,7 +137,6 @@ static struct i2c_algo_bit_data bit_data = {
|
|||
.getsda = bit_getsda,
|
||||
.getscl = bit_getscl,
|
||||
.udelay = 5,
|
||||
.mdelay = 5,
|
||||
.timeout = 100,
|
||||
};
|
||||
|
||||
|
|
|
@ -100,7 +100,6 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
|
|||
.getsda = bttv_bit_getsda,
|
||||
.getscl = bttv_bit_getscl,
|
||||
.udelay = 16,
|
||||
.mdelay = 10,
|
||||
.timeout = 200,
|
||||
};
|
||||
|
||||
|
|
|
@ -155,7 +155,6 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
|
|||
.getsda = cx8800_bit_getsda,
|
||||
.getscl = cx8800_bit_getscl,
|
||||
.udelay = 16,
|
||||
.mdelay = 10,
|
||||
.timeout = 200,
|
||||
};
|
||||
|
||||
|
|
|
@ -100,7 +100,6 @@ static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
|
|||
.getsda = vp3054_bit_getsda,
|
||||
.getscl = vp3054_bit_getscl,
|
||||
.udelay = 16,
|
||||
.mdelay = 10,
|
||||
.timeout = 200,
|
||||
};
|
||||
|
||||
|
|
|
@ -820,7 +820,6 @@ static struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
|
|||
.getsda = zoran_i2c_getsda,
|
||||
.getscl = zoran_i2c_getscl,
|
||||
.udelay = 10,
|
||||
.mdelay = 0,
|
||||
.timeout = 100,
|
||||
};
|
||||
|
||||
|
|
|
@ -98,7 +98,6 @@ static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name)
|
|||
chan->algo.getsda = i810i2c_getsda;
|
||||
chan->algo.getscl = i810i2c_getscl;
|
||||
chan->algo.udelay = 10;
|
||||
chan->algo.mdelay = 10;
|
||||
chan->algo.timeout = (HZ/2);
|
||||
chan->algo.data = chan;
|
||||
|
||||
|
|
|
@ -95,12 +95,12 @@ static struct i2c_adapter matrox_i2c_adapter_template =
|
|||
|
||||
static struct i2c_algo_bit_data matrox_i2c_algo_template =
|
||||
{
|
||||
NULL,
|
||||
matroxfb_gpio_setsda,
|
||||
matroxfb_gpio_setscl,
|
||||
matroxfb_gpio_getsda,
|
||||
matroxfb_gpio_getscl,
|
||||
10, 10, 100,
|
||||
.setsda = matroxfb_gpio_setsda,
|
||||
.setscl = matroxfb_gpio_setscl,
|
||||
.getsda = matroxfb_gpio_getsda,
|
||||
.getscl = matroxfb_gpio_getscl,
|
||||
.udelay = 10,
|
||||
.timeout = 100,
|
||||
};
|
||||
|
||||
static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
|
||||
|
|
|
@ -148,7 +148,6 @@ static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
|
|||
chan->adapter.algo_data = &chan->algo;
|
||||
chan->adapter.dev.parent = &chan->par->pcidev->dev;
|
||||
chan->algo.udelay = 40;
|
||||
chan->algo.mdelay = 5;
|
||||
chan->algo.timeout = 20;
|
||||
chan->algo.data = chan;
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ struct i2c_algo_bit_data {
|
|||
/* local settings */
|
||||
int udelay; /* half-clock-cycle time in microsecs */
|
||||
/* i.e. clock is (500 / udelay) KHz */
|
||||
int mdelay; /* in millisecs, unused */
|
||||
int timeout; /* in jiffies */
|
||||
};
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ struct i2c_algo_pcf_data {
|
|||
|
||||
/* local settings */
|
||||
int udelay;
|
||||
int mdelay;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001,2002,2003 Broadcom Corporation
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef I2C_ALGO_SIBYTE_H
|
||||
#define I2C_ALGO_SIBYTE_H 1
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
struct i2c_algo_sibyte_data {
|
||||
void *data; /* private data */
|
||||
int bus; /* which bus */
|
||||
void *reg_base; /* CSR base */
|
||||
};
|
||||
|
||||
int i2c_sibyte_add_bus(struct i2c_adapter *, int speed);
|
||||
int i2c_sibyte_del_bus(struct i2c_adapter *);
|
||||
|
||||
#endif /* I2C_ALGO_SIBYTE_H */
|
|
@ -64,14 +64,6 @@ extern int i2c_master_recv(struct i2c_client *,char* ,int);
|
|||
*/
|
||||
extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
|
||||
|
||||
/*
|
||||
* Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor.
|
||||
* This is not tested/implemented yet and will change in the future.
|
||||
*/
|
||||
extern int i2c_slave_send(struct i2c_client *,char*,int);
|
||||
extern int i2c_slave_recv(struct i2c_client *,char*,int);
|
||||
|
||||
|
||||
|
||||
/* This is the very generalized SMBus access routine. You probably do not
|
||||
want to use this, though; one of the functions below may be much easier,
|
||||
|
@ -201,10 +193,6 @@ struct i2c_algorithm {
|
|||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data * data);
|
||||
|
||||
/* --- these optional/future use for some adapter types.*/
|
||||
int (*slave_send)(struct i2c_adapter *,char*,int);
|
||||
int (*slave_recv)(struct i2c_adapter *,char*,int);
|
||||
|
||||
/* --- ioctl like call to set div. parameters. */
|
||||
int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);
|
||||
|
||||
|
@ -220,7 +208,7 @@ struct i2c_adapter {
|
|||
struct module *owner;
|
||||
unsigned int id;
|
||||
unsigned int class;
|
||||
struct i2c_algorithm *algo;/* the algorithm to access the bus */
|
||||
const struct i2c_algorithm *algo; /* the algorithm to access the bus */
|
||||
void *algo_data;
|
||||
|
||||
/* --- administration stuff. */
|
||||
|
|
Загрузка…
Ссылка в новой задаче