Merge commit 'a849088aa1' from rmk/fixes into cleanup/io-pci
As Stephen Rothwell reports,a849088aa1
("ARM: Fix ioremap() of address zero") from the arm-current tree and commitc279443709
("ARM: Add fixed PCI i/o mapping") from the arm-soc tree conflict in a nontrivial way in arch/arm/mm/mmu.c. Rob Herring explains: The PCI i/o reserved area has a dummy physical address of 0 and needs to be skipped by ioremap searches. So we don't set VM_ARM_STATIC_MAPPING to prevent matches by ioremap. The vm_struct settings don't really matter when we do the real mapping of the i/o space. Since commita849088aa1
is at the start of the fixes branch in the arm tree, we can merge it into the branch that contains the other ioremap changes. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Cc: Rob Herring <rob.herring@calxeda.com> Cc: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
@@ -133,7 +133,7 @@ config I2C_PIIX4
|
||||
ATI IXP300
|
||||
ATI IXP400
|
||||
ATI SB600
|
||||
ATI SB700
|
||||
ATI SB700/SP5100
|
||||
ATI SB800
|
||||
AMD Hudson-2
|
||||
Serverworks OSB4
|
||||
@@ -143,6 +143,10 @@ config I2C_PIIX4
|
||||
Serverworks HT-1100
|
||||
SMSC Victory66
|
||||
|
||||
Some AMD chipsets contain two PIIX4-compatible SMBus
|
||||
controllers. This driver will attempt to use both controllers
|
||||
on the SB700/SP5100, if they have been initialized by the BIOS.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-piix4.
|
||||
|
||||
@@ -458,7 +462,7 @@ config I2C_MPC
|
||||
|
||||
config I2C_MV64XXX
|
||||
tristate "Marvell mv64xxx I2C Controller"
|
||||
depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
|
||||
depends on (MV64X60 || PLAT_ORION)
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface on the Marvell 64xxx line of host bridges.
|
||||
@@ -479,10 +483,11 @@ config I2C_MXS
|
||||
|
||||
config I2C_NOMADIK
|
||||
tristate "ST-Ericsson Nomadik/Ux500 I2C Controller"
|
||||
depends on PLAT_NOMADIK
|
||||
depends on ARM_AMBA
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface from ST-Ericsson's Nomadik and Ux500 architectures.
|
||||
I2C interface from ST-Ericsson's Nomadik and Ux500 architectures,
|
||||
as well as the STA2X11 PCIe I/O HUB.
|
||||
|
||||
config I2C_NUC900
|
||||
tristate "NUC900 I2C Driver"
|
||||
|
@@ -531,15 +531,7 @@ static struct pci_driver ali1535_driver = {
|
||||
.remove = __devexit_p(ali1535_remove),
|
||||
};
|
||||
|
||||
static int __init i2c_ali1535_init(void)
|
||||
{
|
||||
return pci_register_driver(&ali1535_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_ali1535_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&ali1535_driver);
|
||||
}
|
||||
module_pci_driver(ali1535_driver);
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
|
||||
"Philip Edelbrock <phil@netroedge.com>, "
|
||||
@@ -547,6 +539,3 @@ MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
|
||||
"and Dan Eaton <dan.eaton@rocketlogix.com>");
|
||||
MODULE_DESCRIPTION("ALI1535 SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_ali1535_init);
|
||||
module_exit(i2c_ali1535_exit);
|
||||
|
@@ -431,18 +431,6 @@ static struct pci_driver ali1563_pci_driver = {
|
||||
.remove = __devexit_p(ali1563_remove),
|
||||
};
|
||||
|
||||
static int __init ali1563_init(void)
|
||||
{
|
||||
return pci_register_driver(&ali1563_pci_driver);
|
||||
}
|
||||
|
||||
module_init(ali1563_init);
|
||||
|
||||
static void __exit ali1563_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&ali1563_pci_driver);
|
||||
}
|
||||
|
||||
module_exit(ali1563_exit);
|
||||
module_pci_driver(ali1563_pci_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -513,21 +513,10 @@ static struct pci_driver ali15x3_driver = {
|
||||
.remove = __devexit_p(ali15x3_remove),
|
||||
};
|
||||
|
||||
static int __init i2c_ali15x3_init(void)
|
||||
{
|
||||
return pci_register_driver(&ali15x3_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_ali15x3_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&ali15x3_driver);
|
||||
}
|
||||
module_pci_driver(ali15x3_driver);
|
||||
|
||||
MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
|
||||
"Philip Edelbrock <phil@netroedge.com>, "
|
||||
"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||
MODULE_DESCRIPTION("ALI15X3 SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_ali15x3_init);
|
||||
module_exit(i2c_ali15x3_exit);
|
||||
|
@@ -410,21 +410,10 @@ static struct pci_driver amd756_driver = {
|
||||
.remove = __devexit_p(amd756_remove),
|
||||
};
|
||||
|
||||
static int __init amd756_init(void)
|
||||
{
|
||||
return pci_register_driver(&amd756_driver);
|
||||
}
|
||||
|
||||
static void __exit amd756_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&amd756_driver);
|
||||
}
|
||||
module_pci_driver(amd756_driver);
|
||||
|
||||
MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
|
||||
MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL(amd756_smbus);
|
||||
|
||||
module_init(amd756_init)
|
||||
module_exit(amd756_exit)
|
||||
|
@@ -491,15 +491,4 @@ static struct pci_driver amd8111_driver = {
|
||||
.remove = __devexit_p(amd8111_remove),
|
||||
};
|
||||
|
||||
static int __init i2c_amd8111_init(void)
|
||||
{
|
||||
return pci_register_driver(&amd8111_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_amd8111_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&amd8111_driver);
|
||||
}
|
||||
|
||||
module_init(i2c_amd8111_init);
|
||||
module_exit(i2c_amd8111_exit);
|
||||
module_pci_driver(amd8111_driver);
|
||||
|
@@ -279,30 +279,31 @@ static int __devexit at91_i2c_remove(struct platform_device *pdev)
|
||||
|
||||
/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
|
||||
|
||||
static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
|
||||
static int at91_i2c_suspend(struct device *dev)
|
||||
{
|
||||
clk_disable(twi_clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91_i2c_resume(struct platform_device *pdev)
|
||||
static int at91_i2c_resume(struct device *dev)
|
||||
{
|
||||
return clk_enable(twi_clk);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(at91_i2c_pm, at91_i2c_suspend, at91_i2c_resume);
|
||||
#define AT91_I2C_PM (&at91_i2c_pm)
|
||||
|
||||
#else
|
||||
#define at91_i2c_suspend NULL
|
||||
#define at91_i2c_resume NULL
|
||||
#define AT91_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver at91_i2c_driver = {
|
||||
.probe = at91_i2c_probe,
|
||||
.remove = __devexit_p(at91_i2c_remove),
|
||||
.suspend = at91_i2c_suspend,
|
||||
.resume = at91_i2c_resume,
|
||||
.driver = {
|
||||
.name = "at91_i2c",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = AT91_I2C_PM,
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/bfin_twi.h>
|
||||
|
||||
/* SMBus mode*/
|
||||
#define TWI_I2C_MODE_STANDARD 1
|
||||
@@ -32,56 +33,6 @@
|
||||
#define TWI_I2C_MODE_COMBINED 3
|
||||
#define TWI_I2C_MODE_REPEAT 4
|
||||
|
||||
struct bfin_twi_iface {
|
||||
int irq;
|
||||
spinlock_t lock;
|
||||
char read_write;
|
||||
u8 command;
|
||||
u8 *transPtr;
|
||||
int readNum;
|
||||
int writeNum;
|
||||
int cur_mode;
|
||||
int manual_stop;
|
||||
int result;
|
||||
struct i2c_adapter adap;
|
||||
struct completion complete;
|
||||
struct i2c_msg *pmsg;
|
||||
int msg_num;
|
||||
int cur_msg;
|
||||
u16 saved_clkdiv;
|
||||
u16 saved_control;
|
||||
void __iomem *regs_base;
|
||||
};
|
||||
|
||||
|
||||
#define DEFINE_TWI_REG(reg, off) \
|
||||
static inline u16 read_##reg(struct bfin_twi_iface *iface) \
|
||||
{ return bfin_read16(iface->regs_base + (off)); } \
|
||||
static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
|
||||
{ bfin_write16(iface->regs_base + (off), v); }
|
||||
|
||||
DEFINE_TWI_REG(CLKDIV, 0x00)
|
||||
DEFINE_TWI_REG(CONTROL, 0x04)
|
||||
DEFINE_TWI_REG(SLAVE_CTL, 0x08)
|
||||
DEFINE_TWI_REG(SLAVE_STAT, 0x0C)
|
||||
DEFINE_TWI_REG(SLAVE_ADDR, 0x10)
|
||||
DEFINE_TWI_REG(MASTER_CTL, 0x14)
|
||||
DEFINE_TWI_REG(MASTER_STAT, 0x18)
|
||||
DEFINE_TWI_REG(MASTER_ADDR, 0x1C)
|
||||
DEFINE_TWI_REG(INT_STAT, 0x20)
|
||||
DEFINE_TWI_REG(INT_MASK, 0x24)
|
||||
DEFINE_TWI_REG(FIFO_CTL, 0x28)
|
||||
DEFINE_TWI_REG(FIFO_STAT, 0x2C)
|
||||
DEFINE_TWI_REG(XMT_DATA8, 0x80)
|
||||
DEFINE_TWI_REG(XMT_DATA16, 0x84)
|
||||
DEFINE_TWI_REG(RCV_DATA8, 0x88)
|
||||
DEFINE_TWI_REG(RCV_DATA16, 0x8C)
|
||||
|
||||
static const u16 pin_req[2][3] = {
|
||||
{P_TWI0_SCL, P_TWI0_SDA, 0},
|
||||
{P_TWI1_SCL, P_TWI1_SDA, 0},
|
||||
};
|
||||
|
||||
static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
||||
unsigned short twi_int_status)
|
||||
{
|
||||
@@ -99,7 +50,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
||||
*/
|
||||
else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | MDIR | RSTART);
|
||||
read_MASTER_CTL(iface) | MDIR);
|
||||
else if (iface->manual_stop)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | STOP);
|
||||
@@ -107,10 +58,10 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
||||
iface->cur_msg + 1 < iface->msg_num) {
|
||||
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | RSTART | MDIR);
|
||||
read_MASTER_CTL(iface) | MDIR);
|
||||
else
|
||||
write_MASTER_CTL(iface,
|
||||
(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
|
||||
read_MASTER_CTL(iface) & ~MDIR);
|
||||
}
|
||||
}
|
||||
if (twi_int_status & RCVSERV) {
|
||||
@@ -130,17 +81,25 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
||||
}
|
||||
iface->transPtr++;
|
||||
iface->readNum--;
|
||||
} else if (iface->manual_stop) {
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | STOP);
|
||||
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
|
||||
iface->cur_msg + 1 < iface->msg_num) {
|
||||
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
|
||||
}
|
||||
|
||||
if (iface->readNum == 0) {
|
||||
if (iface->manual_stop) {
|
||||
/* Temporary workaround to avoid possible bus stall -
|
||||
* Flush FIFO before issuing the STOP condition
|
||||
*/
|
||||
read_RCV_DATA16(iface);
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | RSTART | MDIR);
|
||||
else
|
||||
write_MASTER_CTL(iface,
|
||||
(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
|
||||
read_MASTER_CTL(iface) | STOP);
|
||||
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
|
||||
iface->cur_msg + 1 < iface->msg_num) {
|
||||
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | MDIR);
|
||||
else
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) & ~MDIR);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (twi_int_status & MERR) {
|
||||
@@ -193,7 +152,8 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
||||
return;
|
||||
}
|
||||
if (twi_int_status & MCOMP) {
|
||||
if ((read_MASTER_CTL(iface) & MEN) == 0 &&
|
||||
if (twi_int_status & (XMTSERV | RCVSERV) &&
|
||||
(read_MASTER_CTL(iface) & MEN) == 0 &&
|
||||
(iface->cur_mode == TWI_I2C_MODE_REPEAT ||
|
||||
iface->cur_mode == TWI_I2C_MODE_COMBINED)) {
|
||||
iface->result = -1;
|
||||
@@ -221,7 +181,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) & ~RSTART);
|
||||
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
|
||||
iface->cur_msg+1 < iface->msg_num) {
|
||||
iface->cur_msg + 1 < iface->msg_num) {
|
||||
iface->cur_msg++;
|
||||
iface->transPtr = iface->pmsg[iface->cur_msg].buf;
|
||||
iface->writeNum = iface->readNum =
|
||||
@@ -241,27 +201,29 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
||||
}
|
||||
}
|
||||
|
||||
if (iface->pmsg[iface->cur_msg].len <= 255)
|
||||
write_MASTER_CTL(iface,
|
||||
if (iface->pmsg[iface->cur_msg].len <= 255) {
|
||||
write_MASTER_CTL(iface,
|
||||
(read_MASTER_CTL(iface) &
|
||||
(~(0xff << 6))) |
|
||||
(iface->pmsg[iface->cur_msg].len << 6));
|
||||
else {
|
||||
(iface->pmsg[iface->cur_msg].len << 6));
|
||||
iface->manual_stop = 0;
|
||||
} else {
|
||||
write_MASTER_CTL(iface,
|
||||
(read_MASTER_CTL(iface) |
|
||||
(0xff << 6)));
|
||||
iface->manual_stop = 1;
|
||||
}
|
||||
/* remove restart bit and enable master receive */
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) & ~RSTART);
|
||||
/* remove restart bit before last message */
|
||||
if (iface->cur_msg + 1 == iface->msg_num)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) & ~RSTART);
|
||||
} else {
|
||||
iface->result = 1;
|
||||
write_INT_MASK(iface, 0);
|
||||
write_MASTER_CTL(iface, 0);
|
||||
}
|
||||
complete(&iface->complete);
|
||||
}
|
||||
complete(&iface->complete);
|
||||
}
|
||||
|
||||
/* Interrupt handler */
|
||||
@@ -298,8 +260,8 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
|
||||
if (!(read_CONTROL(iface) & TWI_ENA))
|
||||
return -ENXIO;
|
||||
|
||||
while (read_MASTER_STAT(iface) & BUSBUSY)
|
||||
yield();
|
||||
if (read_MASTER_STAT(iface) & BUSBUSY)
|
||||
return -EAGAIN;
|
||||
|
||||
iface->pmsg = msgs;
|
||||
iface->msg_num = num;
|
||||
@@ -311,7 +273,8 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iface->cur_mode = TWI_I2C_MODE_REPEAT;
|
||||
if (iface->msg_num > 1)
|
||||
iface->cur_mode = TWI_I2C_MODE_REPEAT;
|
||||
iface->manual_stop = 0;
|
||||
iface->transPtr = pmsg->buf;
|
||||
iface->writeNum = iface->readNum = pmsg->len;
|
||||
@@ -356,6 +319,7 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
|
||||
|
||||
/* Master enable */
|
||||
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
|
||||
(iface->msg_num > 1 ? RSTART : 0) |
|
||||
((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
|
||||
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
|
||||
SSYNC();
|
||||
@@ -398,8 +362,8 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
||||
if (!(read_CONTROL(iface) & TWI_ENA))
|
||||
return -ENXIO;
|
||||
|
||||
while (read_MASTER_STAT(iface) & BUSBUSY)
|
||||
yield();
|
||||
if (read_MASTER_STAT(iface) & BUSBUSY)
|
||||
return -EAGAIN;
|
||||
|
||||
iface->writeNum = 0;
|
||||
iface->readNum = 0;
|
||||
@@ -520,7 +484,7 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
||||
else
|
||||
write_MASTER_CTL(iface, 0x1 << 6);
|
||||
/* Master enable */
|
||||
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
|
||||
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | RSTART |
|
||||
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
|
||||
break;
|
||||
default:
|
||||
@@ -611,9 +575,9 @@ static struct i2c_algorithm bfin_twi_algorithm = {
|
||||
.functionality = bfin_twi_functionality,
|
||||
};
|
||||
|
||||
static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int i2c_bfin_twi_suspend(struct device *dev)
|
||||
{
|
||||
struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
|
||||
struct bfin_twi_iface *iface = dev_get_drvdata(dev);
|
||||
|
||||
iface->saved_clkdiv = read_CLKDIV(iface);
|
||||
iface->saved_control = read_CONTROL(iface);
|
||||
@@ -626,14 +590,14 @@ static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_bfin_twi_resume(struct platform_device *pdev)
|
||||
static int i2c_bfin_twi_resume(struct device *dev)
|
||||
{
|
||||
struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
|
||||
struct bfin_twi_iface *iface = dev_get_drvdata(dev);
|
||||
|
||||
int rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
|
||||
0, pdev->name, iface);
|
||||
0, to_platform_device(dev)->name, iface);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
|
||||
dev_err(dev, "Can't get IRQ %d !\n", iface->irq);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -646,6 +610,9 @@ static int i2c_bfin_twi_resume(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(i2c_bfin_twi_pm,
|
||||
i2c_bfin_twi_suspend, i2c_bfin_twi_resume);
|
||||
|
||||
static int i2c_bfin_twi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bfin_twi_iface *iface;
|
||||
@@ -695,7 +662,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
|
||||
p_adap->timeout = 5 * HZ;
|
||||
p_adap->retries = 3;
|
||||
|
||||
rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
|
||||
rc = peripheral_request_list((unsigned short *)pdev->dev.platform_data,
|
||||
"i2c-bfin-twi");
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Can't setup pin mux!\n");
|
||||
goto out_error_pin_mux;
|
||||
@@ -742,7 +710,7 @@ out_error_add_adapter:
|
||||
free_irq(iface->irq, iface);
|
||||
out_error_req_irq:
|
||||
out_error_no_irq:
|
||||
peripheral_free_list(pin_req[pdev->id]);
|
||||
peripheral_free_list((unsigned short *)pdev->dev.platform_data);
|
||||
out_error_pin_mux:
|
||||
iounmap(iface->regs_base);
|
||||
out_error_ioremap:
|
||||
@@ -760,7 +728,7 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev)
|
||||
|
||||
i2c_del_adapter(&(iface->adap));
|
||||
free_irq(iface->irq, iface);
|
||||
peripheral_free_list(pin_req[pdev->id]);
|
||||
peripheral_free_list((unsigned short *)pdev->dev.platform_data);
|
||||
iounmap(iface->regs_base);
|
||||
kfree(iface);
|
||||
|
||||
@@ -770,11 +738,10 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev)
|
||||
static struct platform_driver i2c_bfin_twi_driver = {
|
||||
.probe = i2c_bfin_twi_probe,
|
||||
.remove = i2c_bfin_twi_remove,
|
||||
.suspend = i2c_bfin_twi_suspend,
|
||||
.resume = i2c_bfin_twi_resume,
|
||||
.driver = {
|
||||
.name = "i2c-bfin-twi",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &i2c_bfin_twi_pm,
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -374,17 +374,7 @@ static struct pci_driver dw_i2c_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init dw_i2c_init_driver(void)
|
||||
{
|
||||
return pci_register_driver(&dw_i2c_driver);
|
||||
}
|
||||
module_init(dw_i2c_init_driver);
|
||||
|
||||
static void __exit dw_i2c_exit_driver(void)
|
||||
{
|
||||
pci_unregister_driver(&dw_i2c_driver);
|
||||
}
|
||||
module_exit(dw_i2c_exit_driver);
|
||||
module_pci_driver(dw_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
|
||||
MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
|
||||
|
@@ -405,6 +405,7 @@ static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = num;
|
||||
abort:
|
||||
sret = diolan_i2c_stop(dev);
|
||||
if (sret < 0 && ret >= 0)
|
||||
@@ -517,6 +518,6 @@ static struct usb_driver diolan_u2c_driver = {
|
||||
|
||||
module_usb_driver(diolan_u2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
|
||||
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
|
||||
MODULE_DESCRIPTION(DRIVER_NAME " driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -953,17 +953,7 @@ static struct pci_driver pch_pcidriver = {
|
||||
.resume = pch_i2c_resume
|
||||
};
|
||||
|
||||
static int __init pch_pci_init(void)
|
||||
{
|
||||
return pci_register_driver(&pch_pcidriver);
|
||||
}
|
||||
module_init(pch_pci_init);
|
||||
|
||||
static void __exit pch_pci_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&pch_pcidriver);
|
||||
}
|
||||
module_exit(pch_pci_exit);
|
||||
module_pci_driver(pch_pcidriver);
|
||||
|
||||
MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -156,23 +156,8 @@ static struct pci_driver hydra_driver = {
|
||||
.remove = __devexit_p(hydra_remove),
|
||||
};
|
||||
|
||||
static int __init i2c_hydra_init(void)
|
||||
{
|
||||
return pci_register_driver(&hydra_driver);
|
||||
}
|
||||
|
||||
|
||||
static void __exit i2c_hydra_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&hydra_driver);
|
||||
}
|
||||
|
||||
|
||||
module_pci_driver(hydra_driver);
|
||||
|
||||
MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
|
||||
MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_hydra_init);
|
||||
module_exit(i2c_hydra_exit);
|
||||
|
||||
|
@@ -60,10 +60,12 @@
|
||||
Block process call transaction no
|
||||
I2C block read transaction yes (doesn't use the block buffer)
|
||||
Slave mode no
|
||||
Interrupt processing yes
|
||||
|
||||
See the file Documentation/i2c/busses/i2c-i801 for details.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -76,6 +78,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
/* I801 SMBus address offsets */
|
||||
#define SMBHSTSTS(p) (0 + (p)->smba)
|
||||
@@ -91,8 +94,12 @@
|
||||
|
||||
/* PCI Address Constants */
|
||||
#define SMBBAR 4
|
||||
#define SMBPCISTS 0x006
|
||||
#define SMBHSTCFG 0x040
|
||||
|
||||
/* Host status bits for SMBPCISTS */
|
||||
#define SMBPCISTS_INTS 0x08
|
||||
|
||||
/* Host configuration bits for SMBHSTCFG */
|
||||
#define SMBHSTCFG_HST_EN 1
|
||||
#define SMBHSTCFG_SMB_SMI_EN 2
|
||||
@@ -102,12 +109,8 @@
|
||||
#define SMBAUXCTL_CRC 1
|
||||
#define SMBAUXCTL_E32B 2
|
||||
|
||||
/* kill bit for SMBHSTCNT */
|
||||
#define SMBHSTCNT_KILL 2
|
||||
|
||||
/* Other settings */
|
||||
#define MAX_RETRIES 400
|
||||
#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
|
||||
|
||||
/* I801 command constants */
|
||||
#define I801_QUICK 0x00
|
||||
@@ -117,10 +120,13 @@
|
||||
#define I801_PROC_CALL 0x10 /* unimplemented */
|
||||
#define I801_BLOCK_DATA 0x14
|
||||
#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */
|
||||
#define I801_BLOCK_LAST 0x34
|
||||
#define I801_I2C_BLOCK_LAST 0x38 /* ICH5 and later */
|
||||
#define I801_START 0x40
|
||||
#define I801_PEC_EN 0x80 /* ICH3 and later */
|
||||
|
||||
/* I801 Host Control register bits */
|
||||
#define SMBHSTCNT_INTREN 0x01
|
||||
#define SMBHSTCNT_KILL 0x02
|
||||
#define SMBHSTCNT_LAST_BYTE 0x20
|
||||
#define SMBHSTCNT_START 0x40
|
||||
#define SMBHSTCNT_PEC_EN 0x80 /* ICH3 and later */
|
||||
|
||||
/* I801 Hosts Status register bits */
|
||||
#define SMBHSTSTS_BYTE_DONE 0x80
|
||||
@@ -132,9 +138,11 @@
|
||||
#define SMBHSTSTS_INTR 0x02
|
||||
#define SMBHSTSTS_HOST_BUSY 0x01
|
||||
|
||||
#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | \
|
||||
SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
|
||||
SMBHSTSTS_INTR)
|
||||
#define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \
|
||||
SMBHSTSTS_DEV_ERR)
|
||||
|
||||
#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \
|
||||
STATUS_ERROR_FLAGS)
|
||||
|
||||
/* Older devices have their ID defined in <linux/pci_ids.h> */
|
||||
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
|
||||
@@ -154,6 +162,17 @@ struct i801_priv {
|
||||
unsigned char original_hstcfg;
|
||||
struct pci_dev *pci_dev;
|
||||
unsigned int features;
|
||||
|
||||
/* isr processing */
|
||||
wait_queue_head_t waitq;
|
||||
u8 status;
|
||||
|
||||
/* Command state used by isr for byte-by-byte block transactions */
|
||||
u8 cmd;
|
||||
bool is_read;
|
||||
int count;
|
||||
int len;
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
static struct pci_driver i801_driver;
|
||||
@@ -162,6 +181,7 @@ static struct pci_driver i801_driver;
|
||||
#define FEATURE_BLOCK_BUFFER (1 << 1)
|
||||
#define FEATURE_BLOCK_PROC (1 << 2)
|
||||
#define FEATURE_I2C_BLOCK_READ (1 << 3)
|
||||
#define FEATURE_IRQ (1 << 4)
|
||||
/* Not really a feature, but it's convenient to handle it as such */
|
||||
#define FEATURE_IDF (1 << 15)
|
||||
|
||||
@@ -170,6 +190,7 @@ static const char *i801_feature_names[] = {
|
||||
"Block buffer",
|
||||
"Block process call",
|
||||
"I2C block read",
|
||||
"Interrupt",
|
||||
};
|
||||
|
||||
static unsigned int disable_features;
|
||||
@@ -205,13 +226,22 @@ static int i801_check_pre(struct i801_priv *priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert the status register to an error code, and clear it. */
|
||||
static int i801_check_post(struct i801_priv *priv, int status, int timeout)
|
||||
/*
|
||||
* Convert the status register to an error code, and clear it.
|
||||
* Note that status only contains the bits we want to clear, not the
|
||||
* actual register value.
|
||||
*/
|
||||
static int i801_check_post(struct i801_priv *priv, int status)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout) {
|
||||
/*
|
||||
* If the SMBus is still busy, we give up
|
||||
* Note: This timeout condition only happens when using polling
|
||||
* transactions. For interrupt operation, NAK/timeout is indicated by
|
||||
* DEV_ERR.
|
||||
*/
|
||||
if (unlikely(status < 0)) {
|
||||
dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
|
||||
/* try to stop the current command */
|
||||
dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
|
||||
@@ -244,64 +274,76 @@ static int i801_check_post(struct i801_priv *priv, int status, int timeout)
|
||||
dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
|
||||
}
|
||||
|
||||
if (result) {
|
||||
/* Clear error flags */
|
||||
outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
|
||||
status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
|
||||
if (status) {
|
||||
dev_warn(&priv->pci_dev->dev, "Failed clearing status "
|
||||
"flags at end of transaction (%02x)\n",
|
||||
status);
|
||||
}
|
||||
}
|
||||
/* Clear status flags except BYTE_DONE, to be cleared by caller */
|
||||
outb_p(status, SMBHSTSTS(priv));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Wait for BUSY being cleared and either INTR or an error flag being set */
|
||||
static int i801_wait_intr(struct i801_priv *priv)
|
||||
{
|
||||
int timeout = 0;
|
||||
int status;
|
||||
|
||||
/* We will always wait for a fraction of a second! */
|
||||
do {
|
||||
usleep_range(250, 500);
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
} while (((status & SMBHSTSTS_HOST_BUSY) ||
|
||||
!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) &&
|
||||
(timeout++ < MAX_RETRIES));
|
||||
|
||||
if (timeout > MAX_RETRIES) {
|
||||
dev_dbg(&priv->pci_dev->dev, "INTR Timeout!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR);
|
||||
}
|
||||
|
||||
/* Wait for either BYTE_DONE or an error flag being set */
|
||||
static int i801_wait_byte_done(struct i801_priv *priv)
|
||||
{
|
||||
int timeout = 0;
|
||||
int status;
|
||||
|
||||
/* We will always wait for a fraction of a second! */
|
||||
do {
|
||||
usleep_range(250, 500);
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
} while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) &&
|
||||
(timeout++ < MAX_RETRIES));
|
||||
|
||||
if (timeout > MAX_RETRIES) {
|
||||
dev_dbg(&priv->pci_dev->dev, "BYTE_DONE Timeout!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
return status & STATUS_ERROR_FLAGS;
|
||||
}
|
||||
|
||||
static int i801_transaction(struct i801_priv *priv, int xact)
|
||||
{
|
||||
int status;
|
||||
int result;
|
||||
int timeout = 0;
|
||||
|
||||
result = i801_check_pre(priv);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
if (priv->features & FEATURE_IRQ) {
|
||||
outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
|
||||
SMBHSTCNT(priv));
|
||||
wait_event(priv->waitq, (status = priv->status));
|
||||
priv->status = 0;
|
||||
return i801_check_post(priv, status);
|
||||
}
|
||||
|
||||
/* the current contents of SMBHSTCNT can be overwritten, since PEC,
|
||||
* INTREN, SMBSCMD are passed in xact */
|
||||
outb_p(xact | I801_START, SMBHSTCNT(priv));
|
||||
* SMBSCMD are passed in xact */
|
||||
outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
|
||||
|
||||
/* We will always wait for a fraction of a second! */
|
||||
do {
|
||||
usleep_range(250, 500);
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
} while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES));
|
||||
|
||||
result = i801_check_post(priv, status, timeout > MAX_RETRIES);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wait for INTR bit as advised by Intel */
|
||||
static void i801_wait_hwpec(struct i801_priv *priv)
|
||||
{
|
||||
int timeout = 0;
|
||||
int status;
|
||||
|
||||
do {
|
||||
usleep_range(250, 500);
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
} while ((!(status & SMBHSTSTS_INTR))
|
||||
&& (timeout++ < MAX_RETRIES));
|
||||
|
||||
if (timeout > MAX_RETRIES)
|
||||
dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n");
|
||||
|
||||
outb_p(status, SMBHSTSTS(priv));
|
||||
status = i801_wait_intr(priv);
|
||||
return i801_check_post(priv, status);
|
||||
}
|
||||
|
||||
static int i801_block_transaction_by_block(struct i801_priv *priv,
|
||||
@@ -321,8 +363,8 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
|
||||
outb_p(data->block[i+1], SMBBLKDAT(priv));
|
||||
}
|
||||
|
||||
status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 |
|
||||
I801_PEC_EN * hwpec);
|
||||
status = i801_transaction(priv, I801_BLOCK_DATA |
|
||||
(hwpec ? SMBHSTCNT_PEC_EN : 0));
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@@ -338,6 +380,98 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i801_isr_byte_done(struct i801_priv *priv)
|
||||
{
|
||||
if (priv->is_read) {
|
||||
/* For SMBus block reads, length is received with first byte */
|
||||
if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) &&
|
||||
(priv->count == 0)) {
|
||||
priv->len = inb_p(SMBHSTDAT0(priv));
|
||||
if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) {
|
||||
dev_err(&priv->pci_dev->dev,
|
||||
"Illegal SMBus block read size %d\n",
|
||||
priv->len);
|
||||
/* FIXME: Recover */
|
||||
priv->len = I2C_SMBUS_BLOCK_MAX;
|
||||
} else {
|
||||
dev_dbg(&priv->pci_dev->dev,
|
||||
"SMBus block read size is %d\n",
|
||||
priv->len);
|
||||
}
|
||||
priv->data[-1] = priv->len;
|
||||
}
|
||||
|
||||
/* Read next byte */
|
||||
if (priv->count < priv->len)
|
||||
priv->data[priv->count++] = inb(SMBBLKDAT(priv));
|
||||
else
|
||||
dev_dbg(&priv->pci_dev->dev,
|
||||
"Discarding extra byte on block read\n");
|
||||
|
||||
/* Set LAST_BYTE for last byte of read transaction */
|
||||
if (priv->count == priv->len - 1)
|
||||
outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE,
|
||||
SMBHSTCNT(priv));
|
||||
} else if (priv->count < priv->len - 1) {
|
||||
/* Write next byte, except for IRQ after last byte */
|
||||
outb_p(priv->data[++priv->count], SMBBLKDAT(priv));
|
||||
}
|
||||
|
||||
/* Clear BYTE_DONE to continue with next byte */
|
||||
outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
|
||||
}
|
||||
|
||||
/*
|
||||
* There are two kinds of interrupts:
|
||||
*
|
||||
* 1) i801 signals transaction completion with one of these interrupts:
|
||||
* INTR - Success
|
||||
* DEV_ERR - Invalid command, NAK or communication timeout
|
||||
* BUS_ERR - SMI# transaction collision
|
||||
* FAILED - transaction was canceled due to a KILL request
|
||||
* When any of these occur, update ->status and wake up the waitq.
|
||||
* ->status must be cleared before kicking off the next transaction.
|
||||
*
|
||||
* 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt
|
||||
* occurs for each byte of a byte-by-byte to prepare the next byte.
|
||||
*/
|
||||
static irqreturn_t i801_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct i801_priv *priv = dev_id;
|
||||
u16 pcists;
|
||||
u8 status;
|
||||
|
||||
/* Confirm this is our interrupt */
|
||||
pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists);
|
||||
if (!(pcists & SMBPCISTS_INTS))
|
||||
return IRQ_NONE;
|
||||
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
if (status != 0x42)
|
||||
dev_dbg(&priv->pci_dev->dev, "irq: status = %02x\n", status);
|
||||
|
||||
if (status & SMBHSTSTS_BYTE_DONE)
|
||||
i801_isr_byte_done(priv);
|
||||
|
||||
/*
|
||||
* Clear irq sources and report transaction result.
|
||||
* ->status must be cleared before the next transaction is started.
|
||||
*/
|
||||
status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS;
|
||||
if (status) {
|
||||
outb_p(status, SMBHSTSTS(priv));
|
||||
priv->status |= status;
|
||||
wake_up(&priv->waitq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* For "byte-by-byte" block transactions:
|
||||
* I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1
|
||||
* I2C read uses cmd=I801_I2C_BLOCK_DATA
|
||||
*/
|
||||
static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
|
||||
union i2c_smbus_data *data,
|
||||
char read_write, int command,
|
||||
@@ -347,7 +481,6 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
|
||||
int smbcmd;
|
||||
int status;
|
||||
int result;
|
||||
int timeout;
|
||||
|
||||
result = i801_check_pre(priv);
|
||||
if (result < 0)
|
||||
@@ -360,36 +493,39 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
|
||||
outb_p(data->block[1], SMBBLKDAT(priv));
|
||||
}
|
||||
|
||||
if (command == I2C_SMBUS_I2C_BLOCK_DATA &&
|
||||
read_write == I2C_SMBUS_READ)
|
||||
smbcmd = I801_I2C_BLOCK_DATA;
|
||||
else
|
||||
smbcmd = I801_BLOCK_DATA;
|
||||
|
||||
if (priv->features & FEATURE_IRQ) {
|
||||
priv->is_read = (read_write == I2C_SMBUS_READ);
|
||||
if (len == 1 && priv->is_read)
|
||||
smbcmd |= SMBHSTCNT_LAST_BYTE;
|
||||
priv->cmd = smbcmd | SMBHSTCNT_INTREN;
|
||||
priv->len = len;
|
||||
priv->count = 0;
|
||||
priv->data = &data->block[1];
|
||||
|
||||
outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
|
||||
wait_event(priv->waitq, (status = priv->status));
|
||||
priv->status = 0;
|
||||
return i801_check_post(priv, status);
|
||||
}
|
||||
|
||||
for (i = 1; i <= len; i++) {
|
||||
if (i == len && read_write == I2C_SMBUS_READ) {
|
||||
if (command == I2C_SMBUS_I2C_BLOCK_DATA)
|
||||
smbcmd = I801_I2C_BLOCK_LAST;
|
||||
else
|
||||
smbcmd = I801_BLOCK_LAST;
|
||||
} else {
|
||||
if (command == I2C_SMBUS_I2C_BLOCK_DATA
|
||||
&& read_write == I2C_SMBUS_READ)
|
||||
smbcmd = I801_I2C_BLOCK_DATA;
|
||||
else
|
||||
smbcmd = I801_BLOCK_DATA;
|
||||
}
|
||||
outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));
|
||||
if (i == len && read_write == I2C_SMBUS_READ)
|
||||
smbcmd |= SMBHSTCNT_LAST_BYTE;
|
||||
outb_p(smbcmd, SMBHSTCNT(priv));
|
||||
|
||||
if (i == 1)
|
||||
outb_p(inb(SMBHSTCNT(priv)) | I801_START,
|
||||
outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START,
|
||||
SMBHSTCNT(priv));
|
||||
|
||||
/* We will always wait for a fraction of a second! */
|
||||
timeout = 0;
|
||||
do {
|
||||
usleep_range(250, 500);
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
} while ((!(status & SMBHSTSTS_BYTE_DONE))
|
||||
&& (timeout++ < MAX_RETRIES));
|
||||
|
||||
result = i801_check_post(priv, status, timeout > MAX_RETRIES);
|
||||
if (result < 0)
|
||||
return result;
|
||||
status = i801_wait_byte_done(priv);
|
||||
if (status)
|
||||
goto exit;
|
||||
|
||||
if (i == 1 && read_write == I2C_SMBUS_READ
|
||||
&& command != I2C_SMBUS_I2C_BLOCK_DATA) {
|
||||
@@ -416,10 +552,12 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
|
||||
outb_p(data->block[i+1], SMBBLKDAT(priv));
|
||||
|
||||
/* signals SMBBLKDAT ready */
|
||||
outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));
|
||||
outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
|
||||
}
|
||||
|
||||
return 0;
|
||||
status = i801_wait_intr(priv);
|
||||
exit:
|
||||
return i801_check_post(priv, status);
|
||||
}
|
||||
|
||||
static int i801_set_block_buffer_mode(struct i801_priv *priv)
|
||||
@@ -474,9 +612,6 @@ static int i801_block_transaction(struct i801_priv *priv,
|
||||
read_write,
|
||||
command, hwpec);
|
||||
|
||||
if (result == 0 && hwpec)
|
||||
i801_wait_hwpec(priv);
|
||||
|
||||
if (command == I2C_SMBUS_I2C_BLOCK_DATA
|
||||
&& read_write == I2C_SMBUS_WRITE) {
|
||||
/* restore saved configuration register value */
|
||||
@@ -564,7 +699,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
||||
ret = i801_block_transaction(priv, data, read_write, size,
|
||||
hwpec);
|
||||
else
|
||||
ret = i801_transaction(priv, xact | ENABLE_INT9);
|
||||
ret = i801_transaction(priv, xact);
|
||||
|
||||
/* Some BIOSes don't like it when PEC is enabled at reboot or resume
|
||||
time, so we forcibly disable it after every transaction. Turn off
|
||||
@@ -799,6 +934,16 @@ static int __devinit i801_probe(struct pci_dev *dev,
|
||||
break;
|
||||
}
|
||||
|
||||
/* IRQ processing tested on CougarPoint PCH, ICH5, ICH7-M and ICH10 */
|
||||
if (dev->device == PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS ||
|
||||
dev->device == PCI_DEVICE_ID_INTEL_82801EB_3 ||
|
||||
dev->device == PCI_DEVICE_ID_INTEL_ICH7_17 ||
|
||||
dev->device == PCI_DEVICE_ID_INTEL_ICH8_5 ||
|
||||
dev->device == PCI_DEVICE_ID_INTEL_ICH9_6 ||
|
||||
dev->device == PCI_DEVICE_ID_INTEL_ICH10_4 ||
|
||||
dev->device == PCI_DEVICE_ID_INTEL_ICH10_5)
|
||||
priv->features |= FEATURE_IRQ;
|
||||
|
||||
/* Disable features on user request */
|
||||
for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
|
||||
if (priv->features & disable_features & (1 << i))
|
||||
@@ -846,16 +991,30 @@ static int __devinit i801_probe(struct pci_dev *dev,
|
||||
}
|
||||
pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
|
||||
|
||||
if (temp & SMBHSTCFG_SMB_SMI_EN)
|
||||
if (temp & SMBHSTCFG_SMB_SMI_EN) {
|
||||
dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
|
||||
else
|
||||
dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
|
||||
/* Disable SMBus interrupt feature if SMBus using SMI# */
|
||||
priv->features &= ~FEATURE_IRQ;
|
||||
}
|
||||
|
||||
/* Clear special mode bits */
|
||||
if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
|
||||
outb_p(inb_p(SMBAUXCTL(priv)) &
|
||||
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
|
||||
|
||||
if (priv->features & FEATURE_IRQ) {
|
||||
init_waitqueue_head(&priv->waitq);
|
||||
|
||||
err = request_irq(dev->irq, i801_isr, IRQF_SHARED,
|
||||
i801_driver.name, priv);
|
||||
if (err) {
|
||||
dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
|
||||
dev->irq, err);
|
||||
goto exit_release;
|
||||
}
|
||||
dev_info(&dev->dev, "SMBus using PCI Interrupt\n");
|
||||
}
|
||||
|
||||
/* set up the sysfs linkage to our parent device */
|
||||
priv->adapter.dev.parent = &dev->dev;
|
||||
|
||||
@@ -867,14 +1026,18 @@ static int __devinit i801_probe(struct pci_dev *dev,
|
||||
err = i2c_add_adapter(&priv->adapter);
|
||||
if (err) {
|
||||
dev_err(&dev->dev, "Failed to add SMBus adapter\n");
|
||||
goto exit_release;
|
||||
goto exit_free_irq;
|
||||
}
|
||||
|
||||
i801_probe_optional_slaves(priv);
|
||||
|
||||
pci_set_drvdata(dev, priv);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free_irq:
|
||||
if (priv->features & FEATURE_IRQ)
|
||||
free_irq(dev->irq, priv);
|
||||
exit_release:
|
||||
pci_release_region(dev, SMBBAR);
|
||||
exit:
|
||||
@@ -888,7 +1051,11 @@ static void __devexit i801_remove(struct pci_dev *dev)
|
||||
|
||||
i2c_del_adapter(&priv->adapter);
|
||||
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
|
||||
|
||||
if (priv->features & FEATURE_IRQ)
|
||||
free_irq(dev->irq, priv);
|
||||
pci_release_region(dev, SMBBAR);
|
||||
|
||||
pci_set_drvdata(dev, NULL);
|
||||
kfree(priv);
|
||||
/*
|
||||
|
@@ -53,7 +53,6 @@
|
||||
#include <linux/of_i2c.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/i2c.h>
|
||||
|
||||
@@ -118,10 +117,8 @@ static u16 __initdata i2c_clk_div[50][2] = {
|
||||
|
||||
struct imx_i2c_struct {
|
||||
struct i2c_adapter adapter;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
wait_queue_head_t queue;
|
||||
unsigned long i2csr;
|
||||
unsigned int disable_delay;
|
||||
@@ -473,9 +470,8 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
||||
struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct pinctrl *pinctrl;
|
||||
void __iomem *base;
|
||||
resource_size_t res_size;
|
||||
int irq, bitrate;
|
||||
int ret;
|
||||
int irq, ret;
|
||||
u32 bitrate;
|
||||
|
||||
dev_dbg(&pdev->dev, "<%s>\n", __func__);
|
||||
|
||||
@@ -490,25 +486,15 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
res_size = resource_size(res);
|
||||
|
||||
if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
|
||||
dev_err(&pdev->dev, "request_mem_region failed\n");
|
||||
base = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!base)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
base = ioremap(res->start, res_size);
|
||||
if (!base) {
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
ret = -EIO;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
i2c_imx = kzalloc(sizeof(struct imx_i2c_struct), GFP_KERNEL);
|
||||
i2c_imx = devm_kzalloc(&pdev->dev, sizeof(struct imx_i2c_struct),
|
||||
GFP_KERNEL);
|
||||
if (!i2c_imx) {
|
||||
dev_err(&pdev->dev, "can't allocate interface\n");
|
||||
ret = -ENOMEM;
|
||||
goto fail2;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Setup i2c_imx driver structure */
|
||||
@@ -518,29 +504,27 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
||||
i2c_imx->adapter.dev.parent = &pdev->dev;
|
||||
i2c_imx->adapter.nr = pdev->id;
|
||||
i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
|
||||
i2c_imx->irq = irq;
|
||||
i2c_imx->base = base;
|
||||
i2c_imx->res = res;
|
||||
|
||||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
if (IS_ERR(pinctrl)) {
|
||||
ret = PTR_ERR(pinctrl);
|
||||
goto fail3;
|
||||
dev_err(&pdev->dev, "can't get/select pinctrl\n");
|
||||
return PTR_ERR(pinctrl);
|
||||
}
|
||||
|
||||
/* Get I2C clock */
|
||||
i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk");
|
||||
i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(i2c_imx->clk)) {
|
||||
ret = PTR_ERR(i2c_imx->clk);
|
||||
dev_err(&pdev->dev, "can't get I2C clock\n");
|
||||
goto fail3;
|
||||
return PTR_ERR(i2c_imx->clk);
|
||||
}
|
||||
|
||||
/* Request IRQ */
|
||||
ret = request_irq(i2c_imx->irq, i2c_imx_isr, 0, pdev->name, i2c_imx);
|
||||
ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
|
||||
pdev->name, i2c_imx);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "can't claim irq %d\n", i2c_imx->irq);
|
||||
goto fail4;
|
||||
dev_err(&pdev->dev, "can't claim irq %d\n", irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Init queue */
|
||||
@@ -565,7 +549,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
||||
ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "registration failed\n");
|
||||
goto fail5;
|
||||
return ret;
|
||||
}
|
||||
|
||||
of_i2c_register_devices(&i2c_imx->adapter);
|
||||
@@ -573,28 +557,16 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
||||
/* Set up platform driver data */
|
||||
platform_set_drvdata(pdev, i2c_imx);
|
||||
|
||||
dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", i2c_imx->irq);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "device resources from 0x%x to 0x%x\n",
|
||||
i2c_imx->res->start, i2c_imx->res->end);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x \n",
|
||||
res_size, i2c_imx->res->start);
|
||||
res->start, res->end);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x\n",
|
||||
resource_size(res), res->start);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
|
||||
i2c_imx->adapter.name);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
|
||||
|
||||
return 0; /* Return OK */
|
||||
|
||||
fail5:
|
||||
free_irq(i2c_imx->irq, i2c_imx);
|
||||
fail4:
|
||||
clk_put(i2c_imx->clk);
|
||||
fail3:
|
||||
kfree(i2c_imx);
|
||||
fail2:
|
||||
iounmap(base);
|
||||
fail1:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
return ret; /* Return error number */
|
||||
}
|
||||
|
||||
static int __exit i2c_imx_remove(struct platform_device *pdev)
|
||||
@@ -606,20 +578,12 @@ static int __exit i2c_imx_remove(struct platform_device *pdev)
|
||||
i2c_del_adapter(&i2c_imx->adapter);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
/* free interrupt */
|
||||
free_irq(i2c_imx->irq, i2c_imx);
|
||||
|
||||
/* setup chip registers to defaults */
|
||||
writeb(0, i2c_imx->base + IMX_I2C_IADR);
|
||||
writeb(0, i2c_imx->base + IMX_I2C_IFDR);
|
||||
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
|
||||
writeb(0, i2c_imx->base + IMX_I2C_I2SR);
|
||||
|
||||
clk_put(i2c_imx->clk);
|
||||
|
||||
iounmap(i2c_imx->base);
|
||||
release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res));
|
||||
kfree(i2c_imx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -1116,18 +1116,7 @@ static struct pci_driver intel_mid_i2c_driver = {
|
||||
.remove = __devexit_p(intel_mid_i2c_remove),
|
||||
};
|
||||
|
||||
static int __init intel_mid_i2c_init(void)
|
||||
{
|
||||
return pci_register_driver(&intel_mid_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit intel_mid_i2c_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&intel_mid_i2c_driver);
|
||||
}
|
||||
|
||||
module_init(intel_mid_i2c_init);
|
||||
module_exit(intel_mid_i2c_exit);
|
||||
module_pci_driver(intel_mid_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Ba Zheng <zheng.ba@intel.com>");
|
||||
MODULE_DESCRIPTION("I2C driver for Moorestown Platform");
|
||||
|
@@ -18,6 +18,11 @@
|
||||
#include <linux/mv643xx_i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_i2c.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
/* Register defines */
|
||||
#define MV64XXX_I2C_REG_SLAVE_ADDR 0x00
|
||||
@@ -98,6 +103,9 @@ struct mv64xxx_i2c_data {
|
||||
int rc;
|
||||
u32 freq_m;
|
||||
u32 freq_n;
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
struct clk *clk;
|
||||
#endif
|
||||
wait_queue_head_t waitq;
|
||||
spinlock_t lock;
|
||||
struct i2c_msg *msg;
|
||||
@@ -521,6 +529,82 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
|
||||
drv_data->reg_base_p = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int __devinit
|
||||
mv64xxx_calc_freq(const int tclk, const int n, const int m)
|
||||
{
|
||||
return tclk / (10 * (m + 1) * (2 << n));
|
||||
}
|
||||
|
||||
static bool __devinit
|
||||
mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n,
|
||||
u32 *best_m)
|
||||
{
|
||||
int freq, delta, best_delta = INT_MAX;
|
||||
int m, n;
|
||||
|
||||
for (n = 0; n <= 7; n++)
|
||||
for (m = 0; m <= 15; m++) {
|
||||
freq = mv64xxx_calc_freq(tclk, n, m);
|
||||
delta = req_freq - freq;
|
||||
if (delta >= 0 && delta < best_delta) {
|
||||
*best_m = m;
|
||||
*best_n = n;
|
||||
best_delta = delta;
|
||||
}
|
||||
if (best_delta == 0)
|
||||
return true;
|
||||
}
|
||||
if (best_delta == INT_MAX)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
|
||||
struct device_node *np)
|
||||
{
|
||||
u32 bus_freq, tclk;
|
||||
int rc = 0;
|
||||
|
||||
/* CLK is mandatory when using DT to describe the i2c bus. We
|
||||
* need to know tclk in order to calculate bus clock
|
||||
* factors.
|
||||
*/
|
||||
#if !defined(CONFIG_HAVE_CLK)
|
||||
/* Have OF but no CLK */
|
||||
return -ENODEV;
|
||||
#else
|
||||
if (IS_ERR(drv_data->clk)) {
|
||||
rc = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
tclk = clk_get_rate(drv_data->clk);
|
||||
of_property_read_u32(np, "clock-frequency", &bus_freq);
|
||||
if (!mv64xxx_find_baud_factors(bus_freq, tclk,
|
||||
&drv_data->freq_n, &drv_data->freq_m)) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
drv_data->irq = irq_of_parse_and_map(np, 0);
|
||||
|
||||
/* Its not yet defined how timeouts will be specified in device tree.
|
||||
* So hard code the value to 1 second.
|
||||
*/
|
||||
drv_data->adapter.timeout = HZ;
|
||||
out:
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
#else /* CONFIG_OF */
|
||||
static int __devinit
|
||||
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
|
||||
struct device_node *np)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int __devinit
|
||||
mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
{
|
||||
@@ -528,7 +612,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data;
|
||||
int rc;
|
||||
|
||||
if ((pd->id != 0) || !pdata)
|
||||
if ((!pdata && !pd->dev.of_node))
|
||||
return -ENODEV;
|
||||
|
||||
drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL);
|
||||
@@ -546,19 +630,35 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
init_waitqueue_head(&drv_data->waitq);
|
||||
spin_lock_init(&drv_data->lock);
|
||||
|
||||
drv_data->freq_m = pdata->freq_m;
|
||||
drv_data->freq_n = pdata->freq_n;
|
||||
drv_data->irq = platform_get_irq(pd, 0);
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
/* Not all platforms have a clk */
|
||||
drv_data->clk = clk_get(&pd->dev, NULL);
|
||||
if (!IS_ERR(drv_data->clk)) {
|
||||
clk_prepare(drv_data->clk);
|
||||
clk_enable(drv_data->clk);
|
||||
}
|
||||
#endif
|
||||
if (pdata) {
|
||||
drv_data->freq_m = pdata->freq_m;
|
||||
drv_data->freq_n = pdata->freq_n;
|
||||
drv_data->irq = platform_get_irq(pd, 0);
|
||||
drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
|
||||
} else if (pd->dev.of_node) {
|
||||
rc = mv64xxx_of_config(drv_data, pd->dev.of_node);
|
||||
if (rc)
|
||||
goto exit_unmap_regs;
|
||||
}
|
||||
if (drv_data->irq < 0) {
|
||||
rc = -ENXIO;
|
||||
goto exit_unmap_regs;
|
||||
}
|
||||
|
||||
drv_data->adapter.dev.parent = &pd->dev;
|
||||
drv_data->adapter.algo = &mv64xxx_i2c_algo;
|
||||
drv_data->adapter.owner = THIS_MODULE;
|
||||
drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
|
||||
drv_data->adapter.nr = pd->id;
|
||||
drv_data->adapter.dev.of_node = pd->dev.of_node;
|
||||
platform_set_drvdata(pd, drv_data);
|
||||
i2c_set_adapdata(&drv_data->adapter, drv_data);
|
||||
|
||||
@@ -577,11 +677,20 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
goto exit_free_irq;
|
||||
}
|
||||
|
||||
of_i2c_register_devices(&drv_data->adapter);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free_irq:
|
||||
free_irq(drv_data->irq, drv_data);
|
||||
exit_unmap_regs:
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
/* Not all platforms have a clk */
|
||||
if (!IS_ERR(drv_data->clk)) {
|
||||
clk_disable(drv_data->clk);
|
||||
clk_unprepare(drv_data->clk);
|
||||
}
|
||||
#endif
|
||||
mv64xxx_i2c_unmap_regs(drv_data);
|
||||
exit_kfree:
|
||||
kfree(drv_data);
|
||||
@@ -597,17 +706,31 @@ mv64xxx_i2c_remove(struct platform_device *dev)
|
||||
rc = i2c_del_adapter(&drv_data->adapter);
|
||||
free_irq(drv_data->irq, drv_data);
|
||||
mv64xxx_i2c_unmap_regs(drv_data);
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
/* Not all platforms have a clk */
|
||||
if (!IS_ERR(drv_data->clk)) {
|
||||
clk_disable(drv_data->clk);
|
||||
clk_unprepare(drv_data->clk);
|
||||
}
|
||||
#endif
|
||||
kfree(drv_data);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct of_device_id mv64xxx_i2c_of_match_table[] __devinitdata = {
|
||||
{ .compatible = "marvell,mv64xxx-i2c", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
|
||||
|
||||
static struct platform_driver mv64xxx_i2c_driver = {
|
||||
.probe = mv64xxx_i2c_probe,
|
||||
.remove = __devexit_p(mv64xxx_i2c_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = MV64XXX_I2C_CTLR_NAME,
|
||||
.of_match_table = of_match_ptr(mv64xxx_i2c_of_match_table),
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -46,6 +46,10 @@
|
||||
#define MXS_I2C_CTRL0_DIRECTION 0x00010000
|
||||
#define MXS_I2C_CTRL0_XFER_COUNT(v) ((v) & 0x0000FFFF)
|
||||
|
||||
#define MXS_I2C_TIMING0 (0x10)
|
||||
#define MXS_I2C_TIMING1 (0x20)
|
||||
#define MXS_I2C_TIMING2 (0x30)
|
||||
|
||||
#define MXS_I2C_CTRL1 (0x40)
|
||||
#define MXS_I2C_CTRL1_SET (0x44)
|
||||
#define MXS_I2C_CTRL1_CLR (0x48)
|
||||
@@ -97,6 +101,35 @@
|
||||
#define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
|
||||
MXS_I2C_CTRL0_MASTER_MODE)
|
||||
|
||||
struct mxs_i2c_speed_config {
|
||||
uint32_t timing0;
|
||||
uint32_t timing1;
|
||||
uint32_t timing2;
|
||||
};
|
||||
|
||||
/*
|
||||
* Timing values for the default 24MHz clock supplied into the i2c block.
|
||||
*
|
||||
* The bus can operate at 95kHz or at 400kHz with the following timing
|
||||
* register configurations. The 100kHz mode isn't present because it's
|
||||
* values are not stated in the i.MX233/i.MX28 datasheet. The 95kHz mode
|
||||
* shall be close enough replacement. Therefore when the bus is configured
|
||||
* for 100kHz operation, 95kHz timing settings are actually loaded.
|
||||
*
|
||||
* For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4].
|
||||
*/
|
||||
static const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
|
||||
.timing0 = 0x00780030,
|
||||
.timing1 = 0x00800030,
|
||||
.timing2 = 0x00300030,
|
||||
};
|
||||
|
||||
static const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
|
||||
.timing0 = 0x000f0007,
|
||||
.timing1 = 0x001f000f,
|
||||
.timing2 = 0x00300030,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mxs_i2c_dev - per device, private MXS-I2C data
|
||||
*
|
||||
@@ -112,11 +145,17 @@ struct mxs_i2c_dev {
|
||||
struct completion cmd_complete;
|
||||
u32 cmd_err;
|
||||
struct i2c_adapter adapter;
|
||||
const struct mxs_i2c_speed_config *speed;
|
||||
};
|
||||
|
||||
static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
|
||||
{
|
||||
stmp_reset_block(i2c->regs);
|
||||
|
||||
writel(i2c->speed->timing0, i2c->regs + MXS_I2C_TIMING0);
|
||||
writel(i2c->speed->timing1, i2c->regs + MXS_I2C_TIMING1);
|
||||
writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
|
||||
|
||||
writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
|
||||
writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
|
||||
i2c->regs + MXS_I2C_QUEUECTRL_SET);
|
||||
@@ -193,7 +232,7 @@ static int mxs_i2c_wait_for_data(struct mxs_i2c_dev *i2c)
|
||||
|
||||
static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
|
||||
{
|
||||
u32 data;
|
||||
u32 uninitialized_var(data);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
@@ -319,6 +358,28 @@ static const struct i2c_algorithm mxs_i2c_algo = {
|
||||
.functionality = mxs_i2c_func,
|
||||
};
|
||||
|
||||
static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
|
||||
{
|
||||
uint32_t speed;
|
||||
struct device *dev = i2c->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
int ret;
|
||||
|
||||
if (!node)
|
||||
return -EINVAL;
|
||||
|
||||
i2c->speed = &mxs_i2c_95kHz_config;
|
||||
ret = of_property_read_u32(node, "clock-frequency", &speed);
|
||||
if (ret)
|
||||
dev_warn(dev, "No I2C speed selected, using 100kHz\n");
|
||||
else if (speed == 400000)
|
||||
i2c->speed = &mxs_i2c_400kHz_config;
|
||||
else if (speed != 100000)
|
||||
dev_warn(dev, "Unsupported I2C speed selected, using 100kHz\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit mxs_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -358,6 +419,11 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
|
||||
return err;
|
||||
|
||||
i2c->dev = dev;
|
||||
|
||||
err = mxs_i2c_get_ofdata(i2c);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
/* Do reset to enforce correct startup after pinmuxing */
|
||||
|
@@ -453,16 +453,4 @@ static struct pci_driver nforce2_driver = {
|
||||
.remove = __devexit_p(nforce2_remove),
|
||||
};
|
||||
|
||||
static int __init nforce2_init(void)
|
||||
{
|
||||
return pci_register_driver(&nforce2_driver);
|
||||
}
|
||||
|
||||
static void __exit nforce2_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&nforce2_driver);
|
||||
}
|
||||
|
||||
module_init(nforce2_init);
|
||||
module_exit(nforce2_exit);
|
||||
|
||||
module_pci_driver(nforce2_driver);
|
||||
|
@@ -14,7 +14,8 @@
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -23,8 +24,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
#include <linux/platform_data/i2c-nomadik.h>
|
||||
|
||||
#define DRIVER_NAME "nmk-i2c"
|
||||
|
||||
@@ -136,7 +136,7 @@ struct i2c_nmk_client {
|
||||
|
||||
/**
|
||||
* struct nmk_i2c_dev - private data structure of the controller.
|
||||
* @pdev: parent platform device.
|
||||
* @adev: parent amba device.
|
||||
* @adap: corresponding I2C adapter.
|
||||
* @irq: interrupt line for the controller.
|
||||
* @virtbase: virtual io memory area.
|
||||
@@ -150,7 +150,7 @@ struct i2c_nmk_client {
|
||||
* @busy: Busy doing transfer.
|
||||
*/
|
||||
struct nmk_i2c_dev {
|
||||
struct platform_device *pdev;
|
||||
struct amba_device *adev;
|
||||
struct i2c_adapter adap;
|
||||
int irq;
|
||||
void __iomem *virtbase;
|
||||
@@ -217,7 +217,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(&dev->adev->dev,
|
||||
"flushing operation timed out giving up after %d attempts",
|
||||
LOOP_ATTEMPTS);
|
||||
|
||||
@@ -276,15 +276,32 @@ exit:
|
||||
/**
|
||||
* load_i2c_mcr_reg() - load the MCR register
|
||||
* @dev: private data of controller
|
||||
* @flags: message flags
|
||||
*/
|
||||
static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev)
|
||||
static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev, u16 flags)
|
||||
{
|
||||
u32 mcr = 0;
|
||||
unsigned short slave_adr_3msb_bits;
|
||||
|
||||
/* 7-bit address transaction */
|
||||
mcr |= GEN_MASK(1, I2C_MCR_AM, 12);
|
||||
mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1);
|
||||
|
||||
if (unlikely(flags & I2C_M_TEN)) {
|
||||
/* 10-bit address transaction */
|
||||
mcr |= GEN_MASK(2, I2C_MCR_AM, 12);
|
||||
/*
|
||||
* Get the top 3 bits.
|
||||
* EA10 represents extended address in MCR. This includes
|
||||
* the extension (MSB bits) of the 7 bit address loaded
|
||||
* in A7
|
||||
*/
|
||||
slave_adr_3msb_bits = (dev->cli.slave_adr >> 7) & 0x7;
|
||||
|
||||
mcr |= GEN_MASK(slave_adr_3msb_bits, I2C_MCR_EA10, 8);
|
||||
} else {
|
||||
/* 7-bit address transaction */
|
||||
mcr |= GEN_MASK(1, I2C_MCR_AM, 12);
|
||||
}
|
||||
|
||||
/* start byte procedure not applied */
|
||||
mcr |= GEN_MASK(0, I2C_MCR_SB, 11);
|
||||
|
||||
@@ -333,10 +350,6 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
|
||||
|
||||
i2c_clk = clk_get_rate(dev->clk);
|
||||
|
||||
/* fallback to std. mode if machine has not provided it */
|
||||
if (dev->cfg.clk_freq == 0)
|
||||
dev->cfg.clk_freq = 100000;
|
||||
|
||||
/*
|
||||
* The spec says, in case of std. mode the divider is
|
||||
* 2 whereas it is 3 for fast and fastplus mode of
|
||||
@@ -364,7 +377,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
|
||||
* and high speed (up to 3.4 Mb/s)
|
||||
*/
|
||||
if (dev->cfg.sm > I2C_FREQ_MODE_FAST) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(&dev->adev->dev,
|
||||
"do not support this mode defaulting to std. mode\n");
|
||||
brcr2 = i2c_clk/(100000 * 2) & 0xffff;
|
||||
writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
|
||||
@@ -381,19 +394,20 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
|
||||
/**
|
||||
* read_i2c() - Read from I2C client device
|
||||
* @dev: private data of I2C Driver
|
||||
* @flags: message flags
|
||||
*
|
||||
* This function reads from i2c client device when controller is in
|
||||
* master mode. There is a completion timeout. If there is no transfer
|
||||
* before timeout error is returned.
|
||||
*/
|
||||
static int read_i2c(struct nmk_i2c_dev *dev)
|
||||
static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
|
||||
{
|
||||
u32 status = 0;
|
||||
u32 mcr;
|
||||
u32 irq_mask = 0;
|
||||
int timeout;
|
||||
|
||||
mcr = load_i2c_mcr_reg(dev);
|
||||
mcr = load_i2c_mcr_reg(dev, flags);
|
||||
writel(mcr, dev->virtbase + I2C_MCR);
|
||||
|
||||
/* load the current CR value */
|
||||
@@ -423,7 +437,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
|
||||
&dev->xfer_complete, dev->adap.timeout);
|
||||
|
||||
if (timeout < 0) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(&dev->adev->dev,
|
||||
"wait_for_completion_timeout "
|
||||
"returned %d waiting for event\n", timeout);
|
||||
status = timeout;
|
||||
@@ -431,7 +445,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
|
||||
|
||||
if (timeout == 0) {
|
||||
/* Controller timed out */
|
||||
dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n",
|
||||
dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n",
|
||||
dev->cli.slave_adr);
|
||||
status = -ETIMEDOUT;
|
||||
}
|
||||
@@ -459,17 +473,18 @@ static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes)
|
||||
/**
|
||||
* write_i2c() - Write data to I2C client.
|
||||
* @dev: private data of I2C Driver
|
||||
* @flags: message flags
|
||||
*
|
||||
* This function writes data to I2C client
|
||||
*/
|
||||
static int write_i2c(struct nmk_i2c_dev *dev)
|
||||
static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
|
||||
{
|
||||
u32 status = 0;
|
||||
u32 mcr;
|
||||
u32 irq_mask = 0;
|
||||
int timeout;
|
||||
|
||||
mcr = load_i2c_mcr_reg(dev);
|
||||
mcr = load_i2c_mcr_reg(dev, flags);
|
||||
|
||||
writel(mcr, dev->virtbase + I2C_MCR);
|
||||
|
||||
@@ -510,7 +525,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
|
||||
&dev->xfer_complete, dev->adap.timeout);
|
||||
|
||||
if (timeout < 0) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(&dev->adev->dev,
|
||||
"wait_for_completion_timeout "
|
||||
"returned %d waiting for event\n", timeout);
|
||||
status = timeout;
|
||||
@@ -518,7 +533,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
|
||||
|
||||
if (timeout == 0) {
|
||||
/* Controller timed out */
|
||||
dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n",
|
||||
dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n",
|
||||
dev->cli.slave_adr);
|
||||
status = -ETIMEDOUT;
|
||||
}
|
||||
@@ -538,11 +553,11 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
|
||||
if (flags & I2C_M_RD) {
|
||||
/* read operation */
|
||||
dev->cli.operation = I2C_READ;
|
||||
status = read_i2c(dev);
|
||||
status = read_i2c(dev, flags);
|
||||
} else {
|
||||
/* write operation */
|
||||
dev->cli.operation = I2C_WRITE;
|
||||
status = write_i2c(dev);
|
||||
status = write_i2c(dev, flags);
|
||||
}
|
||||
|
||||
if (status || (dev->result)) {
|
||||
@@ -557,7 +572,7 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
|
||||
if (((i2c_sr >> 2) & 0x3) == 0x3) {
|
||||
/* get the abort cause */
|
||||
cause = (i2c_sr >> 4) & 0x7;
|
||||
dev_err(&dev->pdev->dev, "%s\n",
|
||||
dev_err(&dev->adev->dev, "%s\n",
|
||||
cause >= ARRAY_SIZE(abort_causes) ?
|
||||
"unknown reason" :
|
||||
abort_causes[cause]);
|
||||
@@ -630,7 +645,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||
|
||||
if (dev->regulator)
|
||||
regulator_enable(dev->regulator);
|
||||
pm_runtime_get_sync(&dev->pdev->dev);
|
||||
pm_runtime_get_sync(&dev->adev->dev);
|
||||
|
||||
clk_enable(dev->clk);
|
||||
|
||||
@@ -644,13 +659,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||
setup_i2c_controller(dev);
|
||||
|
||||
for (i = 0; i < num_msgs; i++) {
|
||||
if (unlikely(msgs[i].flags & I2C_M_TEN)) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
"10 bit addressing not supported\n");
|
||||
|
||||
status = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
dev->cli.slave_adr = msgs[i].addr;
|
||||
dev->cli.buffer = msgs[i].buf;
|
||||
dev->cli.count = msgs[i].len;
|
||||
@@ -667,7 +675,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||
|
||||
out:
|
||||
clk_disable(dev->clk);
|
||||
pm_runtime_put_sync(&dev->pdev->dev);
|
||||
pm_runtime_put_sync(&dev->adev->dev);
|
||||
if (dev->regulator)
|
||||
regulator_disable(dev->regulator);
|
||||
|
||||
@@ -790,7 +798,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
|
||||
|
||||
if (dev->cli.count) {
|
||||
dev->result = -EIO;
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(&dev->adev->dev,
|
||||
"%lu bytes still remain to be xfered\n",
|
||||
dev->cli.count);
|
||||
(void) init_hw(dev);
|
||||
@@ -834,7 +842,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
|
||||
dev->result = -EIO;
|
||||
(void) init_hw(dev);
|
||||
|
||||
dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
|
||||
dev_err(&dev->adev->dev, "Tx Fifo Over run\n");
|
||||
complete(&dev->xfer_complete);
|
||||
|
||||
break;
|
||||
@@ -847,10 +855,10 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
|
||||
case I2C_IT_RFSE:
|
||||
case I2C_IT_WTSR:
|
||||
case I2C_IT_STD:
|
||||
dev_err(&dev->pdev->dev, "unhandled Interrupt\n");
|
||||
dev_err(&dev->adev->dev, "unhandled Interrupt\n");
|
||||
break;
|
||||
default:
|
||||
dev_err(&dev->pdev->dev, "spurious Interrupt..\n");
|
||||
dev_err(&dev->adev->dev, "spurious Interrupt..\n");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -861,8 +869,8 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
|
||||
#ifdef CONFIG_PM
|
||||
static int nmk_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev);
|
||||
struct amba_device *adev = to_amba_device(dev);
|
||||
struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
|
||||
|
||||
if (nmk_i2c->busy)
|
||||
return -EBUSY;
|
||||
@@ -891,7 +899,7 @@ static const struct dev_pm_ops nmk_i2c_pm = {
|
||||
|
||||
static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm nmk_i2c_algo = {
|
||||
@@ -899,79 +907,81 @@ static const struct i2c_algorithm nmk_i2c_algo = {
|
||||
.functionality = nmk_i2c_functionality
|
||||
};
|
||||
|
||||
static int __devinit nmk_i2c_probe(struct platform_device *pdev)
|
||||
static struct nmk_i2c_controller u8500_i2c = {
|
||||
/*
|
||||
* Slave data setup time; 250ns, 100ns, and 10ns, which
|
||||
* is 14, 6 and 2 respectively for a 48Mhz i2c clock.
|
||||
*/
|
||||
.slsu = 0xe,
|
||||
.tft = 1, /* Tx FIFO threshold */
|
||||
.rft = 8, /* Rx FIFO threshold */
|
||||
.clk_freq = 400000, /* fast mode operation */
|
||||
.timeout = 200, /* Slave response timeout(ms) */
|
||||
.sm = I2C_FREQ_MODE_FAST,
|
||||
};
|
||||
|
||||
static atomic_t adapter_id = ATOMIC_INIT(0);
|
||||
|
||||
static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
{
|
||||
int ret = 0;
|
||||
struct resource *res;
|
||||
struct nmk_i2c_controller *pdata =
|
||||
pdev->dev.platform_data;
|
||||
struct nmk_i2c_controller *pdata = adev->dev.platform_data;
|
||||
struct nmk_i2c_dev *dev;
|
||||
struct i2c_adapter *adap;
|
||||
|
||||
if (!pdata)
|
||||
/* No i2c configuration found, using the default. */
|
||||
pdata = &u8500_i2c;
|
||||
|
||||
dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
dev_err(&pdev->dev, "cannot allocate memory\n");
|
||||
dev_err(&adev->dev, "cannot allocate memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_no_mem;
|
||||
}
|
||||
dev->busy = false;
|
||||
dev->pdev = pdev;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
dev->adev = adev;
|
||||
amba_set_drvdata(adev, dev);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENOENT;
|
||||
goto err_no_resource;
|
||||
}
|
||||
|
||||
if (request_mem_region(res->start, resource_size(res),
|
||||
DRIVER_NAME "I/O region") == NULL) {
|
||||
ret = -EBUSY;
|
||||
goto err_no_region;
|
||||
}
|
||||
|
||||
dev->virtbase = ioremap(res->start, resource_size(res));
|
||||
dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
|
||||
if (!dev->virtbase) {
|
||||
ret = -ENOMEM;
|
||||
goto err_no_ioremap;
|
||||
}
|
||||
|
||||
dev->irq = platform_get_irq(pdev, 0);
|
||||
dev->irq = adev->irq[0];
|
||||
ret = request_irq(dev->irq, i2c_irq_handler, 0,
|
||||
DRIVER_NAME, dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "cannot claim the irq %d\n", dev->irq);
|
||||
dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq);
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
dev->regulator = regulator_get(&pdev->dev, "v-i2c");
|
||||
dev->regulator = regulator_get(&adev->dev, "v-i2c");
|
||||
if (IS_ERR(dev->regulator)) {
|
||||
dev_warn(&pdev->dev, "could not get i2c regulator\n");
|
||||
dev_warn(&adev->dev, "could not get i2c regulator\n");
|
||||
dev->regulator = NULL;
|
||||
}
|
||||
|
||||
pm_suspend_ignore_children(&pdev->dev, true);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_suspend_ignore_children(&adev->dev, true);
|
||||
|
||||
dev->clk = clk_get(&pdev->dev, NULL);
|
||||
dev->clk = clk_get(&adev->dev, NULL);
|
||||
if (IS_ERR(dev->clk)) {
|
||||
dev_err(&pdev->dev, "could not get i2c clock\n");
|
||||
dev_err(&adev->dev, "could not get i2c clock\n");
|
||||
ret = PTR_ERR(dev->clk);
|
||||
goto err_no_clk;
|
||||
}
|
||||
|
||||
adap = &dev->adap;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
adap->dev.parent = &adev->dev;
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
adap->algo = &nmk_i2c_algo;
|
||||
adap->timeout = pdata->timeout ? msecs_to_jiffies(pdata->timeout) :
|
||||
msecs_to_jiffies(20000);
|
||||
adap->timeout = msecs_to_jiffies(pdata->timeout);
|
||||
adap->nr = atomic_read(&adapter_id);
|
||||
snprintf(adap->name, sizeof(adap->name),
|
||||
"Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
|
||||
|
||||
/* fetch the controller id */
|
||||
adap->nr = pdev->id;
|
||||
"Nomadik I2C%d at %pR", adap->nr, &adev->res);
|
||||
atomic_inc(&adapter_id);
|
||||
|
||||
/* fetch the controller configuration from machine */
|
||||
dev->cfg.clk_freq = pdata->clk_freq;
|
||||
@@ -982,16 +992,18 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
i2c_set_adapdata(adap, dev);
|
||||
|
||||
dev_info(&pdev->dev,
|
||||
dev_info(&adev->dev,
|
||||
"initialize %s on virtual base %p\n",
|
||||
adap->name, dev->virtbase);
|
||||
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add adapter\n");
|
||||
dev_err(&adev->dev, "failed to add adapter\n");
|
||||
goto err_add_adap;
|
||||
}
|
||||
|
||||
pm_runtime_put(&adev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_adap:
|
||||
@@ -999,25 +1011,21 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
|
||||
err_no_clk:
|
||||
if (dev->regulator)
|
||||
regulator_put(dev->regulator);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
free_irq(dev->irq, dev);
|
||||
err_irq:
|
||||
iounmap(dev->virtbase);
|
||||
err_no_ioremap:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
err_no_region:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
err_no_resource:
|
||||
amba_set_drvdata(adev, NULL);
|
||||
kfree(dev);
|
||||
err_no_mem:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit nmk_i2c_remove(struct platform_device *pdev)
|
||||
static int nmk_i2c_remove(struct amba_device *adev)
|
||||
{
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct nmk_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
struct resource *res = &adev->res;
|
||||
struct nmk_i2c_dev *dev = amba_get_drvdata(adev);
|
||||
|
||||
i2c_del_adapter(&dev->adap);
|
||||
flush_i2c_fifo(dev);
|
||||
@@ -1032,31 +1040,46 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
|
||||
clk_put(dev->clk);
|
||||
if (dev->regulator)
|
||||
regulator_put(dev->regulator);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
pm_runtime_disable(&adev->dev);
|
||||
amba_set_drvdata(adev, NULL);
|
||||
kfree(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver nmk_i2c_driver = {
|
||||
.driver = {
|
||||
static struct amba_id nmk_i2c_ids[] = {
|
||||
{
|
||||
.id = 0x00180024,
|
||||
.mask = 0x00ffffff,
|
||||
},
|
||||
{
|
||||
.id = 0x00380024,
|
||||
.mask = 0x00ffffff,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(amba, nmk_i2c_ids);
|
||||
|
||||
static struct amba_driver nmk_i2c_driver = {
|
||||
.drv = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
.pm = &nmk_i2c_pm,
|
||||
},
|
||||
.id_table = nmk_i2c_ids,
|
||||
.probe = nmk_i2c_probe,
|
||||
.remove = __devexit_p(nmk_i2c_remove),
|
||||
.remove = nmk_i2c_remove,
|
||||
};
|
||||
|
||||
static int __init nmk_i2c_init(void)
|
||||
{
|
||||
return platform_driver_register(&nmk_i2c_driver);
|
||||
return amba_driver_register(&nmk_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit nmk_i2c_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&nmk_i2c_driver);
|
||||
amba_driver_unregister(&nmk_i2c_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(nmk_i2c_init);
|
||||
@@ -1065,4 +1088,3 @@ module_exit(nmk_i2c_exit);
|
||||
MODULE_AUTHOR("Sachin Verma, Srinidhi KASAGAR");
|
||||
MODULE_DESCRIPTION("Nomadik/Ux500 I2C driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||
|
@@ -10,40 +10,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Device tree configuration:
|
||||
*
|
||||
* Required properties:
|
||||
* - compatible : "opencores,i2c-ocores"
|
||||
* - reg : bus address start and address range size of device
|
||||
* - interrupts : interrupt number
|
||||
* - regstep : size of device registers in bytes
|
||||
* - clock-frequency : frequency of bus clock in Hz
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* i2c0: ocores@a0000000 {
|
||||
* compatible = "opencores,i2c-ocores";
|
||||
* reg = <0xa0000000 0x8>;
|
||||
* interrupts = <10>;
|
||||
*
|
||||
* regstep = <1>;
|
||||
* clock-frequency = <20000000>;
|
||||
*
|
||||
* -- Devices connected on this I2C bus get
|
||||
* -- defined here; address- and size-cells
|
||||
* -- apply to these child devices
|
||||
*
|
||||
* #address-cells = <1>;
|
||||
* #size-cells = <0>;
|
||||
*
|
||||
* dummy@60 {
|
||||
* compatible = "dummy";
|
||||
* reg = <60>;
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* This driver can be used from the device tree, see
|
||||
* Documentation/devicetree/bindings/i2c/ocore-i2c.txt
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
@@ -56,10 +25,12 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_i2c.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
struct ocores_i2c {
|
||||
void __iomem *base;
|
||||
int regstep;
|
||||
u32 reg_shift;
|
||||
u32 reg_io_width;
|
||||
wait_queue_head_t wait;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_msg *msg;
|
||||
@@ -102,12 +73,22 @@ struct ocores_i2c {
|
||||
|
||||
static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
|
||||
{
|
||||
iowrite8(value, i2c->base + reg * i2c->regstep);
|
||||
if (i2c->reg_io_width == 4)
|
||||
iowrite32(value, i2c->base + (reg << i2c->reg_shift));
|
||||
else if (i2c->reg_io_width == 2)
|
||||
iowrite16(value, i2c->base + (reg << i2c->reg_shift));
|
||||
else
|
||||
iowrite8(value, i2c->base + (reg << i2c->reg_shift));
|
||||
}
|
||||
|
||||
static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
|
||||
{
|
||||
return ioread8(i2c->base + reg * i2c->regstep);
|
||||
if (i2c->reg_io_width == 4)
|
||||
return ioread32(i2c->base + (reg << i2c->reg_shift));
|
||||
else if (i2c->reg_io_width == 2)
|
||||
return ioread16(i2c->base + (reg << i2c->reg_shift));
|
||||
else
|
||||
return ioread8(i2c->base + (reg << i2c->reg_shift));
|
||||
}
|
||||
|
||||
static void ocores_process(struct ocores_i2c *i2c)
|
||||
@@ -247,26 +228,35 @@ static struct i2c_adapter ocores_adapter = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int ocores_i2c_of_probe(struct platform_device* pdev,
|
||||
struct ocores_i2c* i2c)
|
||||
static int ocores_i2c_of_probe(struct platform_device *pdev,
|
||||
struct ocores_i2c *i2c)
|
||||
{
|
||||
const __be32* val;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u32 val;
|
||||
|
||||
val = of_get_property(pdev->dev.of_node, "regstep", NULL);
|
||||
if (!val) {
|
||||
dev_err(&pdev->dev, "Missing required parameter 'regstep'");
|
||||
return -ENODEV;
|
||||
if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) {
|
||||
/* no 'reg-shift', check for deprecated 'regstep' */
|
||||
if (!of_property_read_u32(np, "regstep", &val)) {
|
||||
if (!is_power_of_2(val)) {
|
||||
dev_err(&pdev->dev, "invalid regstep %d\n",
|
||||
val);
|
||||
return -EINVAL;
|
||||
}
|
||||
i2c->reg_shift = ilog2(val);
|
||||
dev_warn(&pdev->dev,
|
||||
"regstep property deprecated, use reg-shift\n");
|
||||
}
|
||||
}
|
||||
i2c->regstep = be32_to_cpup(val);
|
||||
|
||||
val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL);
|
||||
if (!val) {
|
||||
if (of_property_read_u32(np, "clock-frequency", &val)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Missing required parameter 'clock-frequency'");
|
||||
"Missing required parameter 'clock-frequency'\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
i2c->clock_khz = be32_to_cpup(val) / 1000;
|
||||
i2c->clock_khz = val / 1000;
|
||||
|
||||
of_property_read_u32(pdev->dev.of_node, "reg-io-width",
|
||||
&i2c->reg_io_width);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
@@ -308,7 +298,8 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata) {
|
||||
i2c->regstep = pdata->regstep;
|
||||
i2c->reg_shift = pdata->reg_shift;
|
||||
i2c->reg_io_width = pdata->reg_io_width;
|
||||
i2c->clock_khz = pdata->clock_khz;
|
||||
} else {
|
||||
ret = ocores_i2c_of_probe(pdev, i2c);
|
||||
@@ -316,6 +307,9 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (i2c->reg_io_width == 0)
|
||||
i2c->reg_io_width = 1; /* Set to default value */
|
||||
|
||||
ocores_init(i2c);
|
||||
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
@@ -351,7 +345,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit ocores_i2c_remove(struct platform_device* pdev)
|
||||
static int __devexit ocores_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ocores_i2c *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
@@ -367,9 +361,9 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ocores_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int ocores_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct ocores_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct ocores_i2c *i2c = dev_get_drvdata(dev);
|
||||
u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
|
||||
|
||||
/* make sure the device is disabled */
|
||||
@@ -378,17 +372,19 @@ static int ocores_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ocores_i2c_resume(struct platform_device *pdev)
|
||||
static int ocores_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct ocores_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct ocores_i2c *i2c = dev_get_drvdata(dev);
|
||||
|
||||
ocores_init(i2c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume);
|
||||
#define OCORES_I2C_PM (&ocores_i2c_pm)
|
||||
#else
|
||||
#define ocores_i2c_suspend NULL
|
||||
#define ocores_i2c_resume NULL
|
||||
#define OCORES_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static struct of_device_id ocores_i2c_match[] = {
|
||||
@@ -400,12 +396,11 @@ MODULE_DEVICE_TABLE(of, ocores_i2c_match);
|
||||
static struct platform_driver ocores_i2c_driver = {
|
||||
.probe = ocores_i2c_probe,
|
||||
.remove = __devexit_p(ocores_i2c_remove),
|
||||
.suspend = ocores_i2c_suspend,
|
||||
.resume = ocores_i2c_resume,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ocores-i2c",
|
||||
.of_match_table = ocores_i2c_match,
|
||||
.pm = OCORES_I2C_PM,
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* (C) Copyright 2009-2010
|
||||
* Nokia Siemens Networks, michael.lawnick.ext@nsn.com
|
||||
*
|
||||
* Portions Copyright (C) 2010 Cavium Networks, Inc.
|
||||
* Portions Copyright (C) 2010, 2011 Cavium Networks, Inc.
|
||||
*
|
||||
* This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
|
||||
*
|
||||
@@ -11,17 +11,18 @@
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <asm/octeon/octeon.h>
|
||||
|
||||
@@ -65,7 +66,7 @@ struct octeon_i2c {
|
||||
wait_queue_head_t queue;
|
||||
struct i2c_adapter adap;
|
||||
int irq;
|
||||
int twsi_freq;
|
||||
u32 twsi_freq;
|
||||
int sys_freq;
|
||||
resource_size_t twsi_phys;
|
||||
void __iomem *twsi_base;
|
||||
@@ -121,10 +122,8 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
|
||||
*/
|
||||
static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
|
||||
{
|
||||
u64 tmp;
|
||||
|
||||
__raw_writeq(data, i2c->twsi_base + TWSI_INT);
|
||||
tmp = __raw_readq(i2c->twsi_base + TWSI_INT);
|
||||
__raw_readq(i2c->twsi_base + TWSI_INT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -515,7 +514,6 @@ static int __devinit octeon_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
int irq, result = 0;
|
||||
struct octeon_i2c *i2c;
|
||||
struct octeon_i2c_data *i2c_data;
|
||||
struct resource *res_mem;
|
||||
|
||||
/* All adaptors have an irq. */
|
||||
@@ -523,86 +521,90 @@ static int __devinit octeon_i2c_probe(struct platform_device *pdev)
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
|
||||
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
|
||||
if (!i2c) {
|
||||
dev_err(&pdev->dev, "kzalloc failed\n");
|
||||
result = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
i2c->dev = &pdev->dev;
|
||||
i2c_data = pdev->dev.platform_data;
|
||||
|
||||
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
if (res_mem == NULL) {
|
||||
dev_err(i2c->dev, "found no memory resource\n");
|
||||
result = -ENXIO;
|
||||
goto fail_region;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (i2c_data == NULL) {
|
||||
dev_err(i2c->dev, "no I2C frequency data\n");
|
||||
result = -ENXIO;
|
||||
goto fail_region;
|
||||
}
|
||||
|
||||
i2c->twsi_phys = res_mem->start;
|
||||
i2c->regsize = resource_size(res_mem);
|
||||
i2c->twsi_freq = i2c_data->i2c_freq;
|
||||
i2c->sys_freq = i2c_data->sys_freq;
|
||||
|
||||
if (!request_mem_region(i2c->twsi_phys, i2c->regsize, res_mem->name)) {
|
||||
dev_err(i2c->dev, "request_mem_region failed\n");
|
||||
goto fail_region;
|
||||
/*
|
||||
* "clock-rate" is a legacy binding, the official binding is
|
||||
* "clock-frequency". Try the official one first and then
|
||||
* fall back if it doesn't exist.
|
||||
*/
|
||||
if (of_property_read_u32(pdev->dev.of_node,
|
||||
"clock-frequency", &i2c->twsi_freq) &&
|
||||
of_property_read_u32(pdev->dev.of_node,
|
||||
"clock-rate", &i2c->twsi_freq)) {
|
||||
dev_err(i2c->dev,
|
||||
"no I2C 'clock-rate' or 'clock-frequency' property\n");
|
||||
result = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
i2c->twsi_base = ioremap(i2c->twsi_phys, i2c->regsize);
|
||||
|
||||
i2c->sys_freq = octeon_get_io_clock_rate();
|
||||
|
||||
if (!devm_request_mem_region(&pdev->dev, i2c->twsi_phys, i2c->regsize,
|
||||
res_mem->name)) {
|
||||
dev_err(i2c->dev, "request_mem_region failed\n");
|
||||
goto out;
|
||||
}
|
||||
i2c->twsi_base = devm_ioremap(&pdev->dev, i2c->twsi_phys, i2c->regsize);
|
||||
|
||||
init_waitqueue_head(&i2c->queue);
|
||||
|
||||
i2c->irq = irq;
|
||||
|
||||
result = request_irq(i2c->irq, octeon_i2c_isr, 0, DRV_NAME, i2c);
|
||||
result = devm_request_irq(&pdev->dev, i2c->irq,
|
||||
octeon_i2c_isr, 0, DRV_NAME, i2c);
|
||||
if (result < 0) {
|
||||
dev_err(i2c->dev, "failed to attach interrupt\n");
|
||||
goto fail_irq;
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = octeon_i2c_initlowlevel(i2c);
|
||||
if (result) {
|
||||
dev_err(i2c->dev, "init low level failed\n");
|
||||
goto fail_add;
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = octeon_i2c_setclock(i2c);
|
||||
if (result) {
|
||||
dev_err(i2c->dev, "clock init failed\n");
|
||||
goto fail_add;
|
||||
goto out;
|
||||
}
|
||||
|
||||
i2c->adap = octeon_i2c_ops;
|
||||
i2c->adap.dev.parent = &pdev->dev;
|
||||
i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
|
||||
i2c->adap.dev.of_node = pdev->dev.of_node;
|
||||
i2c_set_adapdata(&i2c->adap, i2c);
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
result = i2c_add_numbered_adapter(&i2c->adap);
|
||||
result = i2c_add_adapter(&i2c->adap);
|
||||
if (result < 0) {
|
||||
dev_err(i2c->dev, "failed to add adapter\n");
|
||||
goto fail_add;
|
||||
}
|
||||
|
||||
dev_info(i2c->dev, "version %s\n", DRV_VERSION);
|
||||
|
||||
return result;
|
||||
of_i2c_register_devices(&i2c->adap);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_add:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
free_irq(i2c->irq, i2c);
|
||||
fail_irq:
|
||||
iounmap(i2c->twsi_base);
|
||||
release_mem_region(i2c->twsi_phys, i2c->regsize);
|
||||
fail_region:
|
||||
kfree(i2c);
|
||||
out:
|
||||
return result;
|
||||
};
|
||||
@@ -613,19 +615,24 @@ static int __devexit octeon_i2c_remove(struct platform_device *pdev)
|
||||
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
free_irq(i2c->irq, i2c);
|
||||
iounmap(i2c->twsi_base);
|
||||
release_mem_region(i2c->twsi_phys, i2c->regsize);
|
||||
kfree(i2c);
|
||||
return 0;
|
||||
};
|
||||
|
||||
static struct of_device_id octeon_i2c_match[] = {
|
||||
{
|
||||
.compatible = "cavium,octeon-3860-twsi",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, octeon_i2c_match);
|
||||
|
||||
static struct platform_driver octeon_i2c_driver = {
|
||||
.probe = octeon_i2c_probe,
|
||||
.remove = __devexit_p(octeon_i2c_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRV_NAME,
|
||||
.of_match_table = octeon_i2c_match,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -635,4 +642,3 @@ MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
|
||||
MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
@@ -49,8 +49,8 @@
|
||||
|
||||
/* I2C controller revisions present on specific hardware */
|
||||
#define OMAP_I2C_REV_ON_2430 0x36
|
||||
#define OMAP_I2C_REV_ON_3430 0x3C
|
||||
#define OMAP_I2C_REV_ON_3530_4430 0x40
|
||||
#define OMAP_I2C_REV_ON_3430_3530 0x3C
|
||||
#define OMAP_I2C_REV_ON_3630_4430 0x40
|
||||
|
||||
/* timeout waiting for the controller to respond */
|
||||
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
||||
@@ -173,7 +173,7 @@ enum {
|
||||
|
||||
/* Errata definitions */
|
||||
#define I2C_OMAP_ERRATA_I207 (1 << 0)
|
||||
#define I2C_OMAP3_1P153 (1 << 1)
|
||||
#define I2C_OMAP_ERRATA_I462 (1 << 1)
|
||||
|
||||
struct omap_i2c_dev {
|
||||
struct device *dev;
|
||||
@@ -269,47 +269,6 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
|
||||
(i2c_dev->regs[reg] << i2c_dev->reg_shift));
|
||||
}
|
||||
|
||||
static void omap_i2c_unidle(struct omap_i2c_dev *dev)
|
||||
{
|
||||
if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't write to this register if the IE state is 0 as it can
|
||||
* cause deadlock.
|
||||
*/
|
||||
if (dev->iestate)
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
|
||||
}
|
||||
|
||||
static void omap_i2c_idle(struct omap_i2c_dev *dev)
|
||||
{
|
||||
u16 iv;
|
||||
|
||||
dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
|
||||
if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1);
|
||||
else
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
|
||||
|
||||
if (dev->rev < OMAP_I2C_OMAP1_REV_2) {
|
||||
iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
|
||||
} else {
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
|
||||
|
||||
/* Flush posted write */
|
||||
omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
|
||||
}
|
||||
}
|
||||
|
||||
static int omap_i2c_init(struct omap_i2c_dev *dev)
|
||||
{
|
||||
u16 psc = 0, scll = 0, sclh = 0, buf = 0;
|
||||
@@ -346,7 +305,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
|
||||
SYSC_AUTOIDLE_MASK);
|
||||
|
||||
} else if (dev->rev >= OMAP_I2C_REV_ON_3430) {
|
||||
} else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) {
|
||||
dev->syscstate = SYSC_AUTOIDLE_MASK;
|
||||
dev->syscstate |= SYSC_ENAWAKEUP_MASK;
|
||||
dev->syscstate |= (SYSC_IDLEMODE_SMART <<
|
||||
@@ -468,11 +427,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
||||
/* Take the I2C module out of reset: */
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
||||
|
||||
dev->errata = 0;
|
||||
|
||||
if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
|
||||
dev->errata |= I2C_OMAP_ERRATA_I207;
|
||||
|
||||
/* Enable interrupts */
|
||||
dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
|
||||
OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
|
||||
@@ -514,7 +468,7 @@ 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;
|
||||
unsigned long timeout;
|
||||
u16 w;
|
||||
|
||||
dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
|
||||
@@ -536,7 +490,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
||||
w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
|
||||
|
||||
init_completion(&dev->cmd_complete);
|
||||
INIT_COMPLETION(dev->cmd_complete);
|
||||
dev->cmd_err = 0;
|
||||
|
||||
w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
|
||||
@@ -545,6 +499,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
||||
if (dev->speed > 400)
|
||||
w |= OMAP_I2C_CON_OPMODE_HS;
|
||||
|
||||
if (msg->flags & I2C_M_STOP)
|
||||
stop = 1;
|
||||
if (msg->flags & I2C_M_TEN)
|
||||
w |= OMAP_I2C_CON_XA;
|
||||
if (!(msg->flags & I2C_M_RD))
|
||||
@@ -582,12 +538,10 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
||||
* REVISIT: We should abort the transfer on signals, but the bus goes
|
||||
* into arbitration and we're currently unable to recover from it.
|
||||
*/
|
||||
r = wait_for_completion_timeout(&dev->cmd_complete,
|
||||
OMAP_I2C_TIMEOUT);
|
||||
timeout = wait_for_completion_timeout(&dev->cmd_complete,
|
||||
OMAP_I2C_TIMEOUT);
|
||||
dev->buf_len = 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
if (timeout == 0) {
|
||||
dev_err(dev->dev, "controller timed out\n");
|
||||
omap_i2c_init(dev);
|
||||
return -ETIMEDOUT;
|
||||
@@ -628,7 +582,9 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
int i;
|
||||
int r;
|
||||
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
r = pm_runtime_get_sync(dev->dev);
|
||||
if (IS_ERR_VALUE(r))
|
||||
goto out;
|
||||
|
||||
r = omap_i2c_wait_for_bb(dev);
|
||||
if (r < 0)
|
||||
@@ -658,7 +614,8 @@ out:
|
||||
static u32
|
||||
omap_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
|
||||
I2C_FUNC_PROTOCOL_MANGLING;
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -764,11 +721,11 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing
|
||||
* OMAP3430 Errata i462: When an XRDY/XDR is hit, wait for XUDF before writing
|
||||
* data to DATA_REG. Otherwise some data bytes can be lost while transferring
|
||||
* them from the memory to the I2C interface.
|
||||
*/
|
||||
static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
|
||||
static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err)
|
||||
{
|
||||
unsigned long timeout = 10000;
|
||||
|
||||
@@ -776,7 +733,6 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
|
||||
if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
|
||||
omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
|
||||
OMAP_I2C_STAT_XDR));
|
||||
*err |= OMAP_I2C_STAT_XUDF;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
@@ -789,6 +745,7 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
|
||||
return 0;
|
||||
}
|
||||
|
||||
*err |= OMAP_I2C_STAT_XUDF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -927,8 +884,8 @@ complete:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((dev->errata & I2C_OMAP3_1P153) &&
|
||||
errata_omap3_1p153(dev, &stat, &err))
|
||||
if ((dev->errata & I2C_OMAP_ERRATA_I462) &&
|
||||
errata_omap3_i462(dev, &stat, &err))
|
||||
goto complete;
|
||||
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
|
||||
@@ -1045,6 +1002,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
init_completion(&dev->cmd_complete);
|
||||
|
||||
dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
|
||||
|
||||
@@ -1054,12 +1012,19 @@ omap_i2c_probe(struct platform_device *pdev)
|
||||
dev->regs = (u8 *)reg_map_ip_v1;
|
||||
|
||||
pm_runtime_enable(dev->dev);
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
r = pm_runtime_get_sync(dev->dev);
|
||||
if (IS_ERR_VALUE(r))
|
||||
goto err_free_mem;
|
||||
|
||||
dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
|
||||
|
||||
if (dev->rev <= OMAP_I2C_REV_ON_3430)
|
||||
dev->errata |= I2C_OMAP3_1P153;
|
||||
dev->errata = 0;
|
||||
|
||||
if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
|
||||
dev->errata |= I2C_OMAP_ERRATA_I207;
|
||||
|
||||
if (dev->rev <= OMAP_I2C_REV_ON_3430_3530)
|
||||
dev->errata |= I2C_OMAP_ERRATA_I462;
|
||||
|
||||
if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) {
|
||||
u16 s;
|
||||
@@ -1076,7 +1041,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
dev->fifo_size = (dev->fifo_size / 2);
|
||||
|
||||
if (dev->rev >= OMAP_I2C_REV_ON_3530_4430)
|
||||
if (dev->rev >= OMAP_I2C_REV_ON_3630_4430)
|
||||
dev->b_hw = 0; /* Disable hardware fixes */
|
||||
else
|
||||
dev->b_hw = 1; /* Enable hardware fixes */
|
||||
@@ -1092,7 +1057,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
|
||||
omap_i2c_isr;
|
||||
r = request_irq(dev->irq, isr, 0, pdev->name, dev);
|
||||
r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
|
||||
|
||||
if (r) {
|
||||
dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
|
||||
@@ -1102,8 +1067,6 @@ omap_i2c_probe(struct platform_device *pdev)
|
||||
dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
|
||||
dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
|
||||
|
||||
pm_runtime_put(dev->dev);
|
||||
|
||||
adap = &dev->adapter;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
adap->owner = THIS_MODULE;
|
||||
@@ -1123,6 +1086,8 @@ omap_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
of_i2c_register_devices(adap);
|
||||
|
||||
pm_runtime_put(dev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
@@ -1131,6 +1096,7 @@ err_unuse_clocks:
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
||||
pm_runtime_put(dev->dev);
|
||||
iounmap(dev->base);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
err_free_mem:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(dev);
|
||||
@@ -1140,17 +1106,23 @@ err_release_region:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
omap_i2c_remove(struct platform_device *pdev)
|
||||
static int __devexit omap_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
struct resource *mem;
|
||||
int ret;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
free_irq(dev->irq, dev);
|
||||
i2c_del_adapter(&dev->adapter);
|
||||
ret = pm_runtime_get_sync(&pdev->dev);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
||||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
iounmap(dev->base);
|
||||
kfree(dev);
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@@ -1158,13 +1130,26 @@ omap_i2c_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int omap_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
|
||||
u16 iv;
|
||||
|
||||
omap_i2c_idle(_dev);
|
||||
_dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
|
||||
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
|
||||
|
||||
if (_dev->rev < OMAP_I2C_OMAP1_REV_2) {
|
||||
iv = omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */
|
||||
} else {
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate);
|
||||
|
||||
/* Flush posted write */
|
||||
omap_i2c_read_reg(_dev, OMAP_I2C_STAT_REG);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1174,23 +1159,40 @@ static int omap_i2c_runtime_resume(struct device *dev)
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
|
||||
|
||||
omap_i2c_unidle(_dev);
|
||||
if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_SCLL_REG, _dev->scllstate);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't write to this register if the IE state is 0 as it can
|
||||
* cause deadlock.
|
||||
*/
|
||||
if (_dev->iestate)
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, _dev->iestate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_RUNTIME */
|
||||
|
||||
static struct dev_pm_ops omap_i2c_pm_ops = {
|
||||
.runtime_suspend = omap_i2c_runtime_suspend,
|
||||
.runtime_resume = omap_i2c_runtime_resume,
|
||||
SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend,
|
||||
omap_i2c_runtime_resume, NULL)
|
||||
};
|
||||
#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
|
||||
#else
|
||||
#define OMAP_I2C_PM_OPS NULL
|
||||
#endif
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct platform_driver omap_i2c_driver = {
|
||||
.probe = omap_i2c_probe,
|
||||
.remove = omap_i2c_remove,
|
||||
.remove = __devexit_p(omap_i2c_remove),
|
||||
.driver = {
|
||||
.name = "omap_i2c",
|
||||
.owner = THIS_MODULE,
|
||||
|
@@ -415,19 +415,8 @@ static struct pci_driver pasemi_smb_driver = {
|
||||
.remove = __devexit_p(pasemi_smb_remove),
|
||||
};
|
||||
|
||||
static int __init pasemi_smb_init(void)
|
||||
{
|
||||
return pci_register_driver(&pasemi_smb_driver);
|
||||
}
|
||||
|
||||
static void __exit pasemi_smb_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&pasemi_smb_driver);
|
||||
}
|
||||
module_pci_driver(pasemi_smb_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
|
||||
MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver");
|
||||
|
||||
module_init(pasemi_smb_init);
|
||||
module_exit(pasemi_smb_exit);
|
||||
|
@@ -21,11 +21,12 @@
|
||||
Supports:
|
||||
Intel PIIX4, 440MX
|
||||
Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
|
||||
ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
|
||||
ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800
|
||||
AMD Hudson-2
|
||||
SMSC Victory66
|
||||
|
||||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
Note: we assume there can only be one device, with one or more
|
||||
SMBus interfaces.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@@ -94,10 +95,8 @@ MODULE_PARM_DESC(force_addr,
|
||||
"Forcibly enable the PIIX4 at the given address. "
|
||||
"EXTREMELY DANGEROUS!");
|
||||
|
||||
static unsigned short piix4_smba;
|
||||
static int srvrworks_csb5_delay;
|
||||
static struct pci_driver piix4_driver;
|
||||
static struct i2c_adapter piix4_adapter;
|
||||
|
||||
static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = {
|
||||
{
|
||||
@@ -127,10 +126,15 @@ static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
struct i2c_piix4_adapdata {
|
||||
unsigned short smba;
|
||||
};
|
||||
|
||||
static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
unsigned char temp;
|
||||
unsigned short piix4_smba;
|
||||
|
||||
if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
|
||||
(PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5))
|
||||
@@ -206,7 +210,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
|
||||
dev_err(&PIIX4_dev->dev,
|
||||
"Host SMBus controller not enabled!\n");
|
||||
release_region(piix4_smba, SMBIOSIZE);
|
||||
piix4_smba = 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
@@ -224,12 +227,13 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
|
||||
"SMBus Host Controller at 0x%x, revision %d\n",
|
||||
piix4_smba, temp);
|
||||
|
||||
return 0;
|
||||
return piix4_smba;
|
||||
}
|
||||
|
||||
static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
unsigned short piix4_smba;
|
||||
unsigned short smba_idx = 0xcd6;
|
||||
u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
|
||||
|
||||
@@ -273,7 +277,6 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
|
||||
dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region "
|
||||
"0x%x already in use!\n", piix4_smba + i2ccfg_offset);
|
||||
release_region(piix4_smba, SMBIOSIZE);
|
||||
piix4_smba = 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
i2ccfg = inb_p(piix4_smba + i2ccfg_offset);
|
||||
@@ -288,30 +291,72 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
|
||||
"SMBus Host Controller at 0x%x, revision %d\n",
|
||||
piix4_smba, i2ccfg >> 4);
|
||||
|
||||
return 0;
|
||||
return piix4_smba;
|
||||
}
|
||||
|
||||
static int piix4_transaction(void)
|
||||
static int __devinit piix4_setup_aux(struct pci_dev *PIIX4_dev,
|
||||
const struct pci_device_id *id,
|
||||
unsigned short base_reg_addr)
|
||||
{
|
||||
/* Set up auxiliary SMBus controllers found on some
|
||||
* AMD chipsets e.g. SP5100 (SB700 derivative) */
|
||||
|
||||
unsigned short piix4_smba;
|
||||
|
||||
/* Read address of auxiliary SMBus controller */
|
||||
pci_read_config_word(PIIX4_dev, base_reg_addr, &piix4_smba);
|
||||
if ((piix4_smba & 1) == 0) {
|
||||
dev_dbg(&PIIX4_dev->dev,
|
||||
"Auxiliary SMBus controller not enabled\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
piix4_smba &= 0xfff0;
|
||||
if (piix4_smba == 0) {
|
||||
dev_dbg(&PIIX4_dev->dev,
|
||||
"Auxiliary SMBus base address uninitialized\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
|
||||
return -ENODEV;
|
||||
|
||||
if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
|
||||
dev_err(&PIIX4_dev->dev, "Auxiliary SMBus region 0x%x "
|
||||
"already in use!\n", piix4_smba);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
dev_info(&PIIX4_dev->dev,
|
||||
"Auxiliary SMBus Host Controller at 0x%x\n",
|
||||
piix4_smba);
|
||||
|
||||
return piix4_smba;
|
||||
}
|
||||
|
||||
static int piix4_transaction(struct i2c_adapter *piix4_adapter)
|
||||
{
|
||||
struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter);
|
||||
unsigned short piix4_smba = adapdata->smba;
|
||||
int temp;
|
||||
int result = 0;
|
||||
int timeout = 0;
|
||||
|
||||
dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
|
||||
dev_dbg(&piix4_adapter->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
|
||||
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
|
||||
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
|
||||
inb_p(SMBHSTDAT1));
|
||||
|
||||
/* Make sure the SMBus host is ready to start transmitting */
|
||||
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
|
||||
dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). "
|
||||
dev_dbg(&piix4_adapter->dev, "SMBus busy (%02x). "
|
||||
"Resetting...\n", temp);
|
||||
outb_p(temp, SMBHSTSTS);
|
||||
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
|
||||
dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
|
||||
dev_err(&piix4_adapter->dev, "Failed! (%02x)\n", temp);
|
||||
return -EBUSY;
|
||||
} else {
|
||||
dev_dbg(&piix4_adapter.dev, "Successful!\n");
|
||||
dev_dbg(&piix4_adapter->dev, "Successful!\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,35 +375,35 @@ static int piix4_transaction(void)
|
||||
|
||||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout == MAX_TIMEOUT) {
|
||||
dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
|
||||
dev_err(&piix4_adapter->dev, "SMBus Timeout!\n");
|
||||
result = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (temp & 0x10) {
|
||||
result = -EIO;
|
||||
dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n");
|
||||
dev_err(&piix4_adapter->dev, "Error: Failed bus transaction\n");
|
||||
}
|
||||
|
||||
if (temp & 0x08) {
|
||||
result = -EIO;
|
||||
dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be "
|
||||
dev_dbg(&piix4_adapter->dev, "Bus collision! SMBus may be "
|
||||
"locked until next hard reset. (sorry!)\n");
|
||||
/* Clock stops and slave is stuck in mid-transmission */
|
||||
}
|
||||
|
||||
if (temp & 0x04) {
|
||||
result = -ENXIO;
|
||||
dev_dbg(&piix4_adapter.dev, "Error: no response!\n");
|
||||
dev_dbg(&piix4_adapter->dev, "Error: no response!\n");
|
||||
}
|
||||
|
||||
if (inb_p(SMBHSTSTS) != 0x00)
|
||||
outb_p(inb(SMBHSTSTS), SMBHSTSTS);
|
||||
|
||||
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
|
||||
dev_err(&piix4_adapter.dev, "Failed reset at end of "
|
||||
dev_err(&piix4_adapter->dev, "Failed reset at end of "
|
||||
"transaction (%02x)\n", temp);
|
||||
}
|
||||
dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
|
||||
dev_dbg(&piix4_adapter->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
|
||||
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
|
||||
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
|
||||
inb_p(SMBHSTDAT1));
|
||||
@@ -370,6 +415,8 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data * data)
|
||||
{
|
||||
struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
|
||||
unsigned short piix4_smba = adapdata->smba;
|
||||
int i, len;
|
||||
int status;
|
||||
|
||||
@@ -426,7 +473,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
|
||||
|
||||
outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
|
||||
|
||||
status = piix4_transaction();
|
||||
status = piix4_transaction(adap);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@@ -466,12 +513,6 @@ static const struct i2c_algorithm smbus_algorithm = {
|
||||
.functionality = piix4_func,
|
||||
};
|
||||
|
||||
static struct i2c_adapter piix4_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
};
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
|
||||
@@ -496,6 +537,57 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
|
||||
|
||||
MODULE_DEVICE_TABLE (pci, piix4_ids);
|
||||
|
||||
static struct i2c_adapter *piix4_main_adapter;
|
||||
static struct i2c_adapter *piix4_aux_adapter;
|
||||
|
||||
static int __devinit piix4_add_adapter(struct pci_dev *dev,
|
||||
unsigned short smba,
|
||||
struct i2c_adapter **padap)
|
||||
{
|
||||
struct i2c_adapter *adap;
|
||||
struct i2c_piix4_adapdata *adapdata;
|
||||
int retval;
|
||||
|
||||
adap = kzalloc(sizeof(*adap), GFP_KERNEL);
|
||||
if (adap == NULL) {
|
||||
release_region(smba, SMBIOSIZE);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
adap->algo = &smbus_algorithm;
|
||||
|
||||
adapdata = kzalloc(sizeof(*adapdata), GFP_KERNEL);
|
||||
if (adapdata == NULL) {
|
||||
kfree(adap);
|
||||
release_region(smba, SMBIOSIZE);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
adapdata->smba = smba;
|
||||
|
||||
/* set up the sysfs linkage to our parent device */
|
||||
adap->dev.parent = &dev->dev;
|
||||
|
||||
snprintf(adap->name, sizeof(adap->name),
|
||||
"SMBus PIIX4 adapter at %04x", smba);
|
||||
|
||||
i2c_set_adapdata(adap, adapdata);
|
||||
|
||||
retval = i2c_add_adapter(adap);
|
||||
if (retval) {
|
||||
dev_err(&dev->dev, "Couldn't register adapter!\n");
|
||||
kfree(adapdata);
|
||||
kfree(adap);
|
||||
release_region(smba, SMBIOSIZE);
|
||||
return retval;
|
||||
}
|
||||
|
||||
*padap = adap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit piix4_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
@@ -510,30 +602,52 @@ static int __devinit piix4_probe(struct pci_dev *dev,
|
||||
else
|
||||
retval = piix4_setup(dev, id);
|
||||
|
||||
if (retval)
|
||||
/* If no main SMBus found, give up */
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
/* set up the sysfs linkage to our parent device */
|
||||
piix4_adapter.dev.parent = &dev->dev;
|
||||
/* Try to register main SMBus adapter, give up if we can't */
|
||||
retval = piix4_add_adapter(dev, retval, &piix4_main_adapter);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
|
||||
"SMBus PIIX4 adapter at %04x", piix4_smba);
|
||||
|
||||
if ((retval = i2c_add_adapter(&piix4_adapter))) {
|
||||
dev_err(&dev->dev, "Couldn't register adapter!\n");
|
||||
release_region(piix4_smba, SMBIOSIZE);
|
||||
piix4_smba = 0;
|
||||
/* Check for auxiliary SMBus on some AMD chipsets */
|
||||
if (dev->vendor == PCI_VENDOR_ID_ATI &&
|
||||
dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
|
||||
dev->revision < 0x40) {
|
||||
retval = piix4_setup_aux(dev, id, 0x58);
|
||||
if (retval > 0) {
|
||||
/* Try to add the aux adapter if it exists,
|
||||
* piix4_add_adapter will clean up if this fails */
|
||||
piix4_add_adapter(dev, retval, &piix4_aux_adapter);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit piix4_adap_remove(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
|
||||
|
||||
if (adapdata->smba) {
|
||||
i2c_del_adapter(adap);
|
||||
release_region(adapdata->smba, SMBIOSIZE);
|
||||
kfree(adapdata);
|
||||
kfree(adap);
|
||||
}
|
||||
}
|
||||
|
||||
static void __devexit piix4_remove(struct pci_dev *dev)
|
||||
{
|
||||
if (piix4_smba) {
|
||||
i2c_del_adapter(&piix4_adapter);
|
||||
release_region(piix4_smba, SMBIOSIZE);
|
||||
piix4_smba = 0;
|
||||
if (piix4_main_adapter) {
|
||||
piix4_adap_remove(piix4_main_adapter);
|
||||
piix4_main_adapter = NULL;
|
||||
}
|
||||
|
||||
if (piix4_aux_adapter) {
|
||||
piix4_adap_remove(piix4_aux_adapter);
|
||||
piix4_aux_adapter = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,20 +658,9 @@ static struct pci_driver piix4_driver = {
|
||||
.remove = __devexit_p(piix4_remove),
|
||||
};
|
||||
|
||||
static int __init i2c_piix4_init(void)
|
||||
{
|
||||
return pci_register_driver(&piix4_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_piix4_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&piix4_driver);
|
||||
}
|
||||
module_pci_driver(piix4_driver);
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
|
||||
"Philip Edelbrock <phil@netroedge.com>");
|
||||
MODULE_DESCRIPTION("PIIX4 SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_piix4_init);
|
||||
module_exit(i2c_piix4_exit);
|
||||
|
@@ -306,8 +306,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
|
||||
pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
|
||||
if (pmcmsptwi_data.irq) {
|
||||
rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
|
||||
IRQF_SHARED | IRQF_SAMPLE_RANDOM,
|
||||
pldev->name, &pmcmsptwi_data);
|
||||
IRQF_SHARED, pldev->name, &pmcmsptwi_data);
|
||||
if (rc == 0) {
|
||||
/*
|
||||
* Enable 'DONE' interrupt only.
|
||||
|
@@ -587,25 +587,27 @@ static struct i2c_algorithm pnx_algorithm = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int i2c_pnx_controller_suspend(struct platform_device *pdev,
|
||||
pm_message_t state)
|
||||
static int i2c_pnx_controller_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
|
||||
struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable(alg_data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_pnx_controller_resume(struct platform_device *pdev)
|
||||
static int i2c_pnx_controller_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
|
||||
struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev);
|
||||
|
||||
return clk_enable(alg_data->clk);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(i2c_pnx_pm,
|
||||
i2c_pnx_controller_suspend, i2c_pnx_controller_resume);
|
||||
#define PNX_I2C_PM (&i2c_pnx_pm)
|
||||
#else
|
||||
#define i2c_pnx_controller_suspend NULL
|
||||
#define i2c_pnx_controller_resume NULL
|
||||
#define PNX_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static int __devinit i2c_pnx_probe(struct platform_device *pdev)
|
||||
@@ -783,11 +785,10 @@ static struct platform_driver i2c_pnx_driver = {
|
||||
.name = "pnx-i2c",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(i2c_pnx_of_match),
|
||||
.pm = PNX_I2C_PM,
|
||||
},
|
||||
.probe = i2c_pnx_probe,
|
||||
.remove = __devexit_p(i2c_pnx_remove),
|
||||
.suspend = i2c_pnx_controller_suspend,
|
||||
.resume = i2c_pnx_controller_resume,
|
||||
};
|
||||
|
||||
static int __init i2c_adap_pnx_init(void)
|
||||
|
@@ -227,28 +227,138 @@ static int __devexit i2c_powermac_remove(struct platform_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 __devinit i2c_powermac_get_addr(struct i2c_adapter *adap,
|
||||
struct pmac_i2c_bus *bus,
|
||||
struct device_node *node)
|
||||
{
|
||||
const __be32 *prop;
|
||||
int len;
|
||||
|
||||
/* First check for valid "reg" */
|
||||
prop = of_get_property(node, "reg", &len);
|
||||
if (prop && (len >= sizeof(int)))
|
||||
return (be32_to_cpup(prop) & 0xff) >> 1;
|
||||
|
||||
/* Then check old-style "i2c-address" */
|
||||
prop = of_get_property(node, "i2c-address", &len);
|
||||
if (prop && (len >= sizeof(int)))
|
||||
return (be32_to_cpup(prop) & 0xff) >> 1;
|
||||
|
||||
/* Now handle some devices with missing "reg" properties */
|
||||
if (!strcmp(node->name, "cereal"))
|
||||
return 0x60;
|
||||
else if (!strcmp(node->name, "deq"))
|
||||
return 0x34;
|
||||
|
||||
dev_warn(&adap->dev, "No i2c address for %s\n", node->full_name);
|
||||
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
static void __devinit i2c_powermac_create_one(struct i2c_adapter *adap,
|
||||
const char *type,
|
||||
u32 addr)
|
||||
{
|
||||
struct i2c_board_info info = {};
|
||||
struct i2c_client *newdev;
|
||||
|
||||
strncpy(info.type, type, sizeof(info.type));
|
||||
info.addr = addr;
|
||||
newdev = i2c_new_device(adap, &info);
|
||||
if (!newdev)
|
||||
dev_err(&adap->dev,
|
||||
"i2c-powermac: Failure to register missing %s\n",
|
||||
type);
|
||||
}
|
||||
|
||||
static void __devinit i2c_powermac_add_missing(struct i2c_adapter *adap,
|
||||
struct pmac_i2c_bus *bus,
|
||||
bool found_onyx)
|
||||
{
|
||||
struct device_node *busnode = pmac_i2c_get_bus_node(bus);
|
||||
int rc;
|
||||
|
||||
/* Check for the onyx audio codec */
|
||||
#define ONYX_REG_CONTROL 67
|
||||
if (of_device_is_compatible(busnode, "k2-i2c") && !found_onyx) {
|
||||
union i2c_smbus_data data;
|
||||
|
||||
rc = i2c_smbus_xfer(adap, 0x46, 0, I2C_SMBUS_READ,
|
||||
ONYX_REG_CONTROL, I2C_SMBUS_BYTE_DATA,
|
||||
&data);
|
||||
if (rc >= 0)
|
||||
i2c_powermac_create_one(adap, "MAC,pcm3052", 0x46);
|
||||
|
||||
rc = i2c_smbus_xfer(adap, 0x47, 0, I2C_SMBUS_READ,
|
||||
ONYX_REG_CONTROL, I2C_SMBUS_BYTE_DATA,
|
||||
&data);
|
||||
if (rc >= 0)
|
||||
i2c_powermac_create_one(adap, "MAC,pcm3052", 0x47);
|
||||
}
|
||||
}
|
||||
|
||||
static bool __devinit i2c_powermac_get_type(struct i2c_adapter *adap,
|
||||
struct device_node *node,
|
||||
u32 addr, char *type, int type_size)
|
||||
{
|
||||
char tmp[16];
|
||||
|
||||
/* Note: we to _NOT_ want the standard
|
||||
* i2c drivers to match with any of our powermac stuff
|
||||
* unless they have been specifically modified to handle
|
||||
* it on a case by case basis. For example, for thermal
|
||||
* control, things like lm75 etc... shall match with their
|
||||
* corresponding windfarm drivers, _NOT_ the generic ones,
|
||||
* so we force a prefix of AAPL, onto the modalias to
|
||||
* make that happen
|
||||
*/
|
||||
|
||||
/* First try proper modalias */
|
||||
if (of_modalias_node(node, tmp, sizeof(tmp)) >= 0) {
|
||||
snprintf(type, type_size, "MAC,%s", tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Now look for known workarounds */
|
||||
if (!strcmp(node->name, "deq")) {
|
||||
/* Apple uses address 0x34 for TAS3001 and 0x35 for TAS3004 */
|
||||
if (addr == 0x34) {
|
||||
snprintf(type, type_size, "MAC,tas3001");
|
||||
return true;
|
||||
} else if (addr == 0x35) {
|
||||
snprintf(type, type_size, "MAC,tas3004");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(&adap->dev, "i2c-powermac: modalias failure"
|
||||
" on %s\n", node->full_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __devinit i2c_powermac_register_devices(struct i2c_adapter *adap,
|
||||
struct pmac_i2c_bus *bus)
|
||||
{
|
||||
struct i2c_client *newdev;
|
||||
struct device_node *node;
|
||||
bool found_onyx = 0;
|
||||
|
||||
/*
|
||||
* In some cases we end up with the via-pmu node itself, in this
|
||||
* case we skip this function completely as the device-tree will
|
||||
* not contain anything useful.
|
||||
*/
|
||||
if (!strcmp(adap->dev.of_node->name, "via-pmu"))
|
||||
return;
|
||||
|
||||
for_each_child_of_node(adap->dev.of_node, node) {
|
||||
struct i2c_board_info info = {};
|
||||
struct dev_archdata dev_ad = {};
|
||||
const __be32 *reg;
|
||||
char tmp[16];
|
||||
u32 addr;
|
||||
int len;
|
||||
|
||||
/* Get address & channel */
|
||||
reg = of_get_property(node, "reg", &len);
|
||||
if (!reg || (len < sizeof(int))) {
|
||||
dev_err(&adap->dev, "i2c-powermac: invalid reg on %s\n",
|
||||
node->full_name);
|
||||
addr = i2c_powermac_get_addr(adap, bus, node);
|
||||
if (addr == 0xffffffff)
|
||||
continue;
|
||||
}
|
||||
addr = be32_to_cpup(reg);
|
||||
|
||||
/* Multibus setup, check channel */
|
||||
if (!pmac_i2c_match_adapter(node, adap))
|
||||
@@ -257,27 +367,23 @@ static void __devinit i2c_powermac_register_devices(struct i2c_adapter *adap,
|
||||
dev_dbg(&adap->dev, "i2c-powermac: register %s\n",
|
||||
node->full_name);
|
||||
|
||||
/* Make up a modalias. Note: we to _NOT_ want the standard
|
||||
* i2c drivers to match with any of our powermac stuff
|
||||
* unless they have been specifically modified to handle
|
||||
* it on a case by case basis. For example, for thermal
|
||||
* control, things like lm75 etc... shall match with their
|
||||
* corresponding windfarm drivers, _NOT_ the generic ones,
|
||||
* so we force a prefix of AAPL, onto the modalias to
|
||||
* make that happen
|
||||
/*
|
||||
* Keep track of some device existence to handle
|
||||
* workarounds later.
|
||||
*/
|
||||
if (of_modalias_node(node, tmp, sizeof(tmp)) < 0) {
|
||||
dev_err(&adap->dev, "i2c-powermac: modalias failure"
|
||||
" on %s\n", node->full_name);
|
||||
if (of_device_is_compatible(node, "pcm3052"))
|
||||
found_onyx = true;
|
||||
|
||||
/* Make up a modalias */
|
||||
if (!i2c_powermac_get_type(adap, node, addr,
|
||||
info.type, sizeof(info.type))) {
|
||||
continue;
|
||||
}
|
||||
snprintf(info.type, sizeof(info.type), "MAC,%s", tmp);
|
||||
|
||||
/* Fill out the rest of the info structure */
|
||||
info.addr = (addr & 0xff) >> 1;
|
||||
info.addr = addr;
|
||||
info.irq = irq_of_parse_and_map(node, 0);
|
||||
info.of_node = of_node_get(node);
|
||||
info.archdata = &dev_ad;
|
||||
|
||||
newdev = i2c_new_device(adap, &info);
|
||||
if (!newdev) {
|
||||
@@ -292,6 +398,9 @@ static void __devinit i2c_powermac_register_devices(struct i2c_adapter *adap,
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Additional workarounds */
|
||||
i2c_powermac_add_missing(adap, bus, found_onyx);
|
||||
}
|
||||
|
||||
static int __devinit i2c_powermac_probe(struct platform_device *dev)
|
||||
|
@@ -254,7 +254,7 @@ static int __devexit puv3_i2c_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state)
|
||||
static int puv3_i2c_suspend(struct device *dev)
|
||||
{
|
||||
int poll_count;
|
||||
/* Disable the IIC */
|
||||
@@ -267,23 +267,20 @@ static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int puv3_i2c_resume(struct platform_device *dev)
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
static SIMPLE_DEV_PM_OPS(puv3_i2c_pm, puv3_i2c_suspend, NULL);
|
||||
#define PUV3_I2C_PM (&puv3_i2c_pm)
|
||||
|
||||
#else
|
||||
#define puv3_i2c_suspend NULL
|
||||
#define puv3_i2c_resume NULL
|
||||
#define PUV3_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver puv3_i2c_driver = {
|
||||
.probe = puv3_i2c_probe,
|
||||
.remove = __devexit_p(puv3_i2c_remove),
|
||||
.suspend = puv3_i2c_suspend,
|
||||
.resume = puv3_i2c_resume,
|
||||
.driver = {
|
||||
.name = "PKUnity-v3-I2C",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = PUV3_I2C_PM,
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -163,17 +163,7 @@ static struct pci_driver ce4100_i2c_driver = {
|
||||
.remove = __devexit_p(ce4100_i2c_remove),
|
||||
};
|
||||
|
||||
static int __init ce4100_i2c_init(void)
|
||||
{
|
||||
return pci_register_driver(&ce4100_i2c_driver);
|
||||
}
|
||||
module_init(ce4100_i2c_init);
|
||||
|
||||
static void __exit ce4100_i2c_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&ce4100_i2c_driver);
|
||||
}
|
||||
module_exit(ce4100_i2c_exit);
|
||||
module_pci_driver(ce4100_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@@ -41,13 +41,6 @@
|
||||
|
||||
#include <asm/irq.h>
|
||||
|
||||
#ifndef CONFIG_HAVE_CLK
|
||||
#define clk_get(dev, id) NULL
|
||||
#define clk_put(clk) do { } while (0)
|
||||
#define clk_disable(clk) do { } while (0)
|
||||
#define clk_enable(clk) do { } while (0)
|
||||
#endif
|
||||
|
||||
struct pxa_reg_layout {
|
||||
u32 ibmr;
|
||||
u32 idbr;
|
||||
|
@@ -122,7 +122,7 @@ static inline unsigned int s3c24xx_get_device_quirks(struct platform_device *pde
|
||||
{
|
||||
if (pdev->dev.of_node) {
|
||||
const struct of_device_id *match;
|
||||
match = of_match_node(&s3c24xx_i2c_match, pdev->dev.of_node);
|
||||
match = of_match_node(s3c24xx_i2c_match, pdev->dev.of_node);
|
||||
return (unsigned int)match->data;
|
||||
}
|
||||
|
||||
@@ -609,7 +609,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
|
||||
|
||||
if (ret != -EAGAIN) {
|
||||
clk_disable(i2c->clk);
|
||||
pm_runtime_put_sync(&adap->dev);
|
||||
pm_runtime_put(&adap->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -619,7 +619,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
|
||||
}
|
||||
|
||||
clk_disable(i2c->clk);
|
||||
pm_runtime_put_sync(&adap->dev);
|
||||
pm_runtime_put(&adap->dev);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
|
@@ -513,21 +513,8 @@ static struct pci_driver sis630_driver = {
|
||||
.remove = __devexit_p(sis630_remove),
|
||||
};
|
||||
|
||||
static int __init i2c_sis630_init(void)
|
||||
{
|
||||
return pci_register_driver(&sis630_driver);
|
||||
}
|
||||
|
||||
|
||||
static void __exit i2c_sis630_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&sis630_driver);
|
||||
}
|
||||
|
||||
module_pci_driver(sis630_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Alexander Malysh <amalysh@web.de>");
|
||||
MODULE_DESCRIPTION("SIS630 SMBus driver");
|
||||
|
||||
module_init(i2c_sis630_init);
|
||||
module_exit(i2c_sis630_exit);
|
||||
|
@@ -324,21 +324,8 @@ static struct pci_driver sis96x_driver = {
|
||||
.remove = __devexit_p(sis96x_remove),
|
||||
};
|
||||
|
||||
static int __init i2c_sis96x_init(void)
|
||||
{
|
||||
return pci_register_driver(&sis96x_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_sis96x_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&sis96x_driver);
|
||||
}
|
||||
module_pci_driver(sis96x_driver);
|
||||
|
||||
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
|
||||
MODULE_DESCRIPTION("SiS96x SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Register initialization functions using helper macros */
|
||||
module_init(i2c_sis96x_init);
|
||||
module_exit(i2c_sis96x_exit);
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2009 ST-Ericsson AB
|
||||
* Copyright (C) 2007-2012 ST-Ericsson AB
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
* ST DDC I2C master mode driver, used in e.g. U300 series platforms.
|
||||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
@@ -139,8 +139,6 @@ module_param(scl_frequency, uint, 0644);
|
||||
* struct stu300_dev - the stu300 driver state holder
|
||||
* @pdev: parent platform device
|
||||
* @adapter: corresponding I2C adapter
|
||||
* @phybase: location of I/O area in memory
|
||||
* @physize: size of I/O area in memory
|
||||
* @clk: hardware block clock
|
||||
* @irq: assigned interrupt line
|
||||
* @cmd_issue_lock: this locks the following cmd_ variables
|
||||
@@ -155,8 +153,6 @@ module_param(scl_frequency, uint, 0644);
|
||||
struct stu300_dev {
|
||||
struct platform_device *pdev;
|
||||
struct i2c_adapter adapter;
|
||||
resource_size_t phybase;
|
||||
resource_size_t physize;
|
||||
void __iomem *virtbase;
|
||||
struct clk *clk;
|
||||
int irq;
|
||||
@@ -873,64 +869,44 @@ stu300_probe(struct platform_device *pdev)
|
||||
int ret = 0;
|
||||
char clk_name[] = "I2C0";
|
||||
|
||||
dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL);
|
||||
dev = devm_kzalloc(&pdev->dev, sizeof(struct stu300_dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
dev_err(&pdev->dev, "could not allocate device struct\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_no_devmem;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bus_nr = pdev->id;
|
||||
clk_name[3] += (char)bus_nr;
|
||||
dev->clk = clk_get(&pdev->dev, clk_name);
|
||||
dev->clk = devm_clk_get(&pdev->dev, clk_name);
|
||||
if (IS_ERR(dev->clk)) {
|
||||
ret = PTR_ERR(dev->clk);
|
||||
dev_err(&pdev->dev, "could not retrieve i2c bus clock\n");
|
||||
goto err_no_clk;
|
||||
return PTR_ERR(dev->clk);
|
||||
}
|
||||
|
||||
dev->pdev = pdev;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENOENT;
|
||||
goto err_no_resource;
|
||||
}
|
||||
if (!res)
|
||||
return -ENOENT;
|
||||
|
||||
dev->phybase = res->start;
|
||||
dev->physize = resource_size(res);
|
||||
|
||||
if (request_mem_region(dev->phybase, dev->physize,
|
||||
NAME " I/O Area") == NULL) {
|
||||
ret = -EBUSY;
|
||||
goto err_no_ioregion;
|
||||
}
|
||||
|
||||
dev->virtbase = ioremap(dev->phybase, dev->physize);
|
||||
dev->virtbase = devm_request_and_ioremap(&pdev->dev, res);
|
||||
dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual "
|
||||
"base %p\n", bus_nr, dev->virtbase);
|
||||
if (!dev->virtbase) {
|
||||
ret = -ENOMEM;
|
||||
goto err_no_ioremap;
|
||||
}
|
||||
if (!dev->virtbase)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->irq = platform_get_irq(pdev, 0);
|
||||
if (request_irq(dev->irq, stu300_irh, 0,
|
||||
NAME, dev)) {
|
||||
ret = -EIO;
|
||||
goto err_no_irq;
|
||||
}
|
||||
ret = devm_request_irq(&pdev->dev, dev->irq, stu300_irh, 0, NAME, dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev->speed = scl_frequency;
|
||||
|
||||
clk_enable(dev->clk);
|
||||
clk_prepare_enable(dev->clk);
|
||||
ret = stu300_init_hw(dev);
|
||||
clk_disable(dev->clk);
|
||||
|
||||
if (ret != 0) {
|
||||
dev_err(&dev->pdev->dev, "error initializing hardware.\n");
|
||||
goto err_init_hw;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* IRQ event handling initialization */
|
||||
@@ -952,57 +928,43 @@ stu300_probe(struct platform_device *pdev)
|
||||
/* i2c device drivers may be active on return from add_adapter() */
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
if (ret) {
|
||||
dev_err(&dev->pdev->dev, "failure adding ST Micro DDC "
|
||||
dev_err(&pdev->dev, "failure adding ST Micro DDC "
|
||||
"I2C adapter\n");
|
||||
goto err_add_adapter;
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_add_adapter:
|
||||
err_init_hw:
|
||||
free_irq(dev->irq, dev);
|
||||
err_no_irq:
|
||||
iounmap(dev->virtbase);
|
||||
err_no_ioremap:
|
||||
release_mem_region(dev->phybase, dev->physize);
|
||||
err_no_ioregion:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
err_no_resource:
|
||||
clk_put(dev->clk);
|
||||
err_no_clk:
|
||||
kfree(dev);
|
||||
err_no_devmem:
|
||||
dev_err(&pdev->dev, "failed to add " NAME " adapter: %d\n",
|
||||
pdev->id);
|
||||
return ret;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int stu300_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int stu300_suspend(struct device *device)
|
||||
{
|
||||
struct stu300_dev *dev = platform_get_drvdata(pdev);
|
||||
struct stu300_dev *dev = dev_get_drvdata(device);
|
||||
|
||||
/* Turn off everything */
|
||||
stu300_wr8(0x00, dev->virtbase + I2C_CR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stu300_resume(struct platform_device *pdev)
|
||||
static int stu300_resume(struct device *device)
|
||||
{
|
||||
int ret = 0;
|
||||
struct stu300_dev *dev = platform_get_drvdata(pdev);
|
||||
struct stu300_dev *dev = dev_get_drvdata(device);
|
||||
|
||||
clk_enable(dev->clk);
|
||||
ret = stu300_init_hw(dev);
|
||||
clk_disable(dev->clk);
|
||||
|
||||
if (ret != 0)
|
||||
dev_err(&pdev->dev, "error re-initializing hardware.\n");
|
||||
dev_err(device, "error re-initializing hardware.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(stu300_pm, stu300_suspend, stu300_resume);
|
||||
#define STU300_I2C_PM (&stu300_pm)
|
||||
#else
|
||||
#define stu300_suspend NULL
|
||||
#define stu300_resume NULL
|
||||
#define STU300_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static int __exit
|
||||
@@ -1013,12 +975,7 @@ stu300_remove(struct platform_device *pdev)
|
||||
i2c_del_adapter(&dev->adapter);
|
||||
/* Turn off everything */
|
||||
stu300_wr8(0x00, dev->virtbase + I2C_CR);
|
||||
free_irq(dev->irq, dev);
|
||||
iounmap(dev->virtbase);
|
||||
release_mem_region(dev->phybase, dev->physize);
|
||||
clk_put(dev->clk);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1026,10 +983,9 @@ static struct platform_driver stu300_i2c_driver = {
|
||||
.driver = {
|
||||
.name = NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = STU300_I2C_PM,
|
||||
},
|
||||
.remove = __exit_p(stu300_remove),
|
||||
.suspend = stu300_suspend,
|
||||
.resume = stu300_resume,
|
||||
|
||||
};
|
||||
|
||||
|
@@ -97,8 +97,21 @@
|
||||
#define I2C_HEADER_10BIT_ADDR (1<<18)
|
||||
#define I2C_HEADER_IE_ENABLE (1<<17)
|
||||
#define I2C_HEADER_REPEAT_START (1<<16)
|
||||
#define I2C_HEADER_CONTINUE_XFER (1<<15)
|
||||
#define I2C_HEADER_MASTER_ADDR_SHIFT 12
|
||||
#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
|
||||
/*
|
||||
* msg_end_type: The bus control which need to be send at end of transfer.
|
||||
* @MSG_END_STOP: Send stop pulse at end of transfer.
|
||||
* @MSG_END_REPEAT_START: Send repeat start at end of transfer.
|
||||
* @MSG_END_CONTINUE: The following on message is coming and so do not send
|
||||
* stop or repeat start.
|
||||
*/
|
||||
enum msg_end_type {
|
||||
MSG_END_STOP,
|
||||
MSG_END_REPEAT_START,
|
||||
MSG_END_CONTINUE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tegra_i2c_dev - per device i2c context
|
||||
@@ -106,7 +119,6 @@
|
||||
* @adapter: core i2c layer adapter information
|
||||
* @clk: clock reference for i2c controller
|
||||
* @i2c_clk: clock reference for i2c bus
|
||||
* @iomem: memory resource for registers
|
||||
* @base: ioremapped registers cookie
|
||||
* @cont_id: i2c controller id, used for for packet header
|
||||
* @irq: irq number of transfer complete interrupt
|
||||
@@ -124,7 +136,6 @@ struct tegra_i2c_dev {
|
||||
struct i2c_adapter adapter;
|
||||
struct clk *clk;
|
||||
struct clk *i2c_clk;
|
||||
struct resource *iomem;
|
||||
void __iomem *base;
|
||||
int cont_id;
|
||||
int irq;
|
||||
@@ -165,6 +176,10 @@ static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
||||
unsigned long reg)
|
||||
{
|
||||
writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
|
||||
/* Read back register to make sure that register writes completed */
|
||||
if (reg != I2C_TX_FIFO)
|
||||
readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
}
|
||||
|
||||
static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
|
||||
@@ -341,7 +356,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
||||
u32 val;
|
||||
int err = 0;
|
||||
|
||||
clk_enable(i2c_dev->clk);
|
||||
clk_prepare_enable(i2c_dev->clk);
|
||||
|
||||
tegra_periph_reset_assert(i2c_dev->clk);
|
||||
udelay(2);
|
||||
@@ -372,7 +387,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
||||
if (tegra_i2c_flush_fifos(i2c_dev))
|
||||
err = -ETIMEDOUT;
|
||||
|
||||
clk_disable(i2c_dev->clk);
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
|
||||
if (i2c_dev->irq_disabled) {
|
||||
i2c_dev->irq_disabled = 0;
|
||||
@@ -449,7 +464,7 @@ err:
|
||||
}
|
||||
|
||||
static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||
struct i2c_msg *msg, int stop)
|
||||
struct i2c_msg *msg, enum msg_end_type end_state)
|
||||
{
|
||||
u32 packet_header;
|
||||
u32 int_mask;
|
||||
@@ -476,7 +491,9 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||
i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
|
||||
|
||||
packet_header = I2C_HEADER_IE_ENABLE;
|
||||
if (!stop)
|
||||
if (end_state == MSG_END_CONTINUE)
|
||||
packet_header |= I2C_HEADER_CONTINUE_XFER;
|
||||
else if (end_state == MSG_END_REPEAT_START)
|
||||
packet_header |= I2C_HEADER_REPEAT_START;
|
||||
if (msg->flags & I2C_M_TEN) {
|
||||
packet_header |= msg->addr;
|
||||
@@ -546,20 +563,27 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||||
if (i2c_dev->is_suspended)
|
||||
return -EBUSY;
|
||||
|
||||
clk_enable(i2c_dev->clk);
|
||||
clk_prepare_enable(i2c_dev->clk);
|
||||
for (i = 0; i < num; i++) {
|
||||
int stop = (i == (num - 1)) ? 1 : 0;
|
||||
ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop);
|
||||
enum msg_end_type end_type = MSG_END_STOP;
|
||||
if (i < (num - 1)) {
|
||||
if (msgs[i + 1].flags & I2C_M_NOSTART)
|
||||
end_type = MSG_END_CONTINUE;
|
||||
else
|
||||
end_type = MSG_END_REPEAT_START;
|
||||
}
|
||||
ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], end_type);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
clk_disable(i2c_dev->clk);
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
return ret ?: i;
|
||||
}
|
||||
|
||||
static u32 tegra_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
|
||||
I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm tegra_i2c_algo = {
|
||||
@@ -572,7 +596,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
|
||||
struct tegra_i2c_dev *i2c_dev;
|
||||
struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct resource *res;
|
||||
struct resource *iomem;
|
||||
struct clk *clk;
|
||||
struct clk *i2c_clk;
|
||||
const unsigned int *prop;
|
||||
@@ -585,50 +608,41 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "no mem resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
iomem = request_mem_region(res->start, resource_size(res), pdev->name);
|
||||
if (!iomem) {
|
||||
dev_err(&pdev->dev, "I2C region already claimed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
base = ioremap(iomem->start, resource_size(iomem));
|
||||
base = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!base) {
|
||||
dev_err(&pdev->dev, "Cannot ioremap I2C region\n");
|
||||
return -ENOMEM;
|
||||
dev_err(&pdev->dev, "Cannot request/ioremap I2C registers\n");
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "no irq resource\n");
|
||||
ret = -EINVAL;
|
||||
goto err_iounmap;
|
||||
return -EINVAL;
|
||||
}
|
||||
irq = res->start;
|
||||
|
||||
clk = clk_get(&pdev->dev, NULL);
|
||||
clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "missing controller clock");
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_release_region;
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
i2c_clk = clk_get(&pdev->dev, "i2c");
|
||||
i2c_clk = devm_clk_get(&pdev->dev, "i2c");
|
||||
if (IS_ERR(i2c_clk)) {
|
||||
dev_err(&pdev->dev, "missing bus clock");
|
||||
ret = PTR_ERR(i2c_clk);
|
||||
goto err_clk_put;
|
||||
return PTR_ERR(i2c_clk);
|
||||
}
|
||||
|
||||
i2c_dev = kzalloc(sizeof(struct tegra_i2c_dev), GFP_KERNEL);
|
||||
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
|
||||
if (!i2c_dev) {
|
||||
ret = -ENOMEM;
|
||||
goto err_i2c_clk_put;
|
||||
dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i2c_dev->base = base;
|
||||
i2c_dev->clk = clk;
|
||||
i2c_dev->i2c_clk = i2c_clk;
|
||||
i2c_dev->iomem = iomem;
|
||||
i2c_dev->adapter.algo = &tegra_i2c_algo;
|
||||
i2c_dev->irq = irq;
|
||||
i2c_dev->cont_id = pdev->id;
|
||||
@@ -657,16 +671,17 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
|
||||
ret = tegra_i2c_init(i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to initialize i2c controller");
|
||||
goto err_free;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_irq(i2c_dev->irq, tegra_i2c_isr, 0, pdev->name, i2c_dev);
|
||||
ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
|
||||
tegra_i2c_isr, 0, pdev->name, i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
|
||||
goto err_free;
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_enable(i2c_dev->i2c_clk);
|
||||
clk_prepare_enable(i2c_dev->i2c_clk);
|
||||
|
||||
i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
|
||||
i2c_dev->adapter.owner = THIS_MODULE;
|
||||
@@ -681,45 +696,26 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
|
||||
ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add I2C adapter\n");
|
||||
goto err_free_irq;
|
||||
clk_disable_unprepare(i2c_dev->i2c_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
of_i2c_register_devices(&i2c_dev->adapter);
|
||||
|
||||
return 0;
|
||||
err_free_irq:
|
||||
free_irq(i2c_dev->irq, i2c_dev);
|
||||
err_free:
|
||||
kfree(i2c_dev);
|
||||
err_i2c_clk_put:
|
||||
clk_put(i2c_clk);
|
||||
err_clk_put:
|
||||
clk_put(clk);
|
||||
err_release_region:
|
||||
release_mem_region(iomem->start, resource_size(iomem));
|
||||
err_iounmap:
|
||||
iounmap(base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit tegra_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
i2c_del_adapter(&i2c_dev->adapter);
|
||||
free_irq(i2c_dev->irq, i2c_dev);
|
||||
clk_put(i2c_dev->i2c_clk);
|
||||
clk_put(i2c_dev->clk);
|
||||
release_mem_region(i2c_dev->iomem->start,
|
||||
resource_size(i2c_dev->iomem));
|
||||
iounmap(i2c_dev->base);
|
||||
kfree(i2c_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tegra_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
i2c_lock_adapter(&i2c_dev->adapter);
|
||||
i2c_dev->is_suspended = true;
|
||||
@@ -728,9 +724,9 @@ static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_i2c_resume(struct platform_device *pdev)
|
||||
static int tegra_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
i2c_lock_adapter(&i2c_dev->adapter);
|
||||
@@ -748,6 +744,11 @@ static int tegra_i2c_resume(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume);
|
||||
#define TEGRA_I2C_PM (&tegra_i2c_pm)
|
||||
#else
|
||||
#define TEGRA_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
@@ -758,21 +759,16 @@ static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
|
||||
#else
|
||||
#define tegra_i2c_of_match NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver tegra_i2c_driver = {
|
||||
.probe = tegra_i2c_probe,
|
||||
.remove = __devexit_p(tegra_i2c_remove),
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = tegra_i2c_suspend,
|
||||
.resume = tegra_i2c_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = "tegra-i2c",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = tegra_i2c_of_match,
|
||||
.of_match_table = of_match_ptr(tegra_i2c_of_match),
|
||||
.pm = TEGRA_I2C_PM,
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -143,6 +143,7 @@ static const struct i2c_algorithm usb_algorithm = {
|
||||
static const struct usb_device_id i2c_tiny_usb_table[] = {
|
||||
{ USB_DEVICE(0x0403, 0xc631) }, /* FTDI */
|
||||
{ USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */
|
||||
{ USB_DEVICE(0x1964, 0x0001) }, /* Robofuzz OSIF */
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
|
@@ -161,20 +161,8 @@ static struct pci_driver vt586b_driver = {
|
||||
.remove = __devexit_p(vt586b_remove),
|
||||
};
|
||||
|
||||
static int __init i2c_vt586b_init(void)
|
||||
{
|
||||
return pci_register_driver(&vt586b_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_vt586b_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&vt586b_driver);
|
||||
}
|
||||
|
||||
module_pci_driver(vt586b_driver);
|
||||
|
||||
MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
|
||||
MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_vt586b_init);
|
||||
module_exit(i2c_vt586b_exit);
|
||||
|
@@ -1311,6 +1311,37 @@ module_exit(i2c_exit);
|
||||
* ----------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* __i2c_transfer - unlocked flavor of i2c_transfer
|
||||
* @adap: Handle to I2C bus
|
||||
* @msgs: One or more messages to execute before STOP is issued to
|
||||
* terminate the operation; each message begins with a START.
|
||||
* @num: Number of messages to be executed.
|
||||
*
|
||||
* Returns negative errno, else the number of messages executed.
|
||||
*
|
||||
* Adapter lock must be held when calling this function. No debug logging
|
||||
* takes place. adap->algo->master_xfer existence isn't checked.
|
||||
*/
|
||||
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
unsigned long orig_jiffies;
|
||||
int ret, try;
|
||||
|
||||
/* Retry automatically on arbitration loss */
|
||||
orig_jiffies = jiffies;
|
||||
for (ret = 0, try = 0; try <= adap->retries; try++) {
|
||||
ret = adap->algo->master_xfer(adap, msgs, num);
|
||||
if (ret != -EAGAIN)
|
||||
break;
|
||||
if (time_after(jiffies, orig_jiffies + adap->timeout))
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(__i2c_transfer);
|
||||
|
||||
/**
|
||||
* i2c_transfer - execute a single or combined I2C message
|
||||
* @adap: Handle to I2C bus
|
||||
@@ -1325,8 +1356,7 @@ module_exit(i2c_exit);
|
||||
*/
|
||||
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
unsigned long orig_jiffies;
|
||||
int ret, try;
|
||||
int ret;
|
||||
|
||||
/* REVISIT the fault reporting model here is weak:
|
||||
*
|
||||
@@ -1364,15 +1394,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
i2c_lock_adapter(adap);
|
||||
}
|
||||
|
||||
/* Retry automatically on arbitration loss */
|
||||
orig_jiffies = jiffies;
|
||||
for (ret = 0, try = 0; try <= adap->retries; try++) {
|
||||
ret = adap->algo->master_xfer(adap, msgs, num);
|
||||
if (ret != -EAGAIN)
|
||||
break;
|
||||
if (time_after(jiffies, orig_jiffies + adap->timeout))
|
||||
break;
|
||||
}
|
||||
ret = __i2c_transfer(adap, msgs, num);
|
||||
i2c_unlock_adapter(adap);
|
||||
|
||||
return ret;
|
||||
@@ -2122,7 +2144,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
|
||||
int try;
|
||||
s32 res;
|
||||
|
||||
flags &= I2C_M_TEN | I2C_CLIENT_PEC;
|
||||
flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
|
||||
|
||||
if (adapter->algo->smbus_xfer) {
|
||||
i2c_lock_adapter(adapter);
|
||||
@@ -2140,11 +2162,17 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
|
||||
break;
|
||||
}
|
||||
i2c_unlock_adapter(adapter);
|
||||
} else
|
||||
res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
|
||||
command, protocol, data);
|
||||
|
||||
return res;
|
||||
if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
|
||||
return res;
|
||||
/*
|
||||
* Fall back to i2c_smbus_xfer_emulated if the adapter doesn't
|
||||
* implement native support for the SMBus operation.
|
||||
*/
|
||||
}
|
||||
|
||||
return i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
|
||||
command, protocol, data);
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_xfer);
|
||||
|
||||
|
@@ -245,18 +245,7 @@ int i2c_handle_smbus_alert(struct i2c_client *ara)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
|
||||
|
||||
static int __init i2c_smbus_init(void)
|
||||
{
|
||||
return i2c_add_driver(&smbalert_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_smbus_exit(void)
|
||||
{
|
||||
i2c_del_driver(&smbalert_driver);
|
||||
}
|
||||
|
||||
module_init(i2c_smbus_init);
|
||||
module_exit(i2c_smbus_exit);
|
||||
module_i2c_driver(smbalert_driver);
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||
MODULE_DESCRIPTION("SMBus protocol extensions support");
|
||||
|
@@ -396,6 +396,6 @@ static struct i2c_driver pca9541_driver = {
|
||||
|
||||
module_i2c_driver(pca9541_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
|
||||
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
|
||||
MODULE_DESCRIPTION("PCA9541 I2C master selector driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
Reference in New Issue
Block a user