diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-eg20t.c')
| -rw-r--r-- | drivers/i2c/busses/i2c-eg20t.c | 319 |
1 files changed, 94 insertions, 225 deletions
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index ca887764104..a44ea13d143 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -18,7 +18,6 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> -#include <linux/init.h> #include <linux/errno.h> #include <linux/i2c.h> #include <linux/fs.h> @@ -187,7 +186,7 @@ static DEFINE_MUTEX(pch_mutex); #define PCI_DEVICE_ID_ML7223_I2C 0x8010 #define PCI_DEVICE_ID_ML7831_I2C 0x8817 -static DEFINE_PCI_DEVICE_TABLE(pch_pcidev_id) = { +static const struct pci_device_id pch_pcidev_id[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, }, @@ -263,38 +262,39 @@ static void pch_i2c_init(struct i2c_algo_pch_data *adap) init_waitqueue_head(&pch_event); } -static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2) -{ - return cmp1.tv64 < cmp2.tv64; -} - /** * pch_i2c_wait_for_bus_idle() - check the status of bus. * @adap: Pointer to struct i2c_algo_pch_data. - * @timeout: waiting time counter (us). + * @timeout: waiting time counter (ms). */ static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap, s32 timeout) { void __iomem *p = adap->pch_base_address; - ktime_t ns_val; + int schedule = 0; + unsigned long end = jiffies + msecs_to_jiffies(timeout); + + while (ioread32(p + PCH_I2CSR) & I2CMBB_BIT) { + if (time_after(jiffies, end)) { + pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR)); + pch_err(adap, "%s: Timeout Error.return%d\n", + __func__, -ETIME); + pch_i2c_init(adap); - if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0) - return 0; + return -ETIME; + } - /* MAX timeout value is timeout*1000*1000nsec */ - ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000); - do { - msleep(20); - if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0) - return 0; - } while (ktime_lt(ktime_get(), ns_val)); + if (!schedule) + /* Retry after some usecs */ + udelay(5); + else + /* Wait a bit more without consuming CPU */ + usleep_range(20, 1000); - pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR)); - pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME); - pch_i2c_init(adap); + schedule = 1; + } - return -ETIME; + return 0; } /** @@ -311,63 +311,52 @@ static void pch_i2c_start(struct i2c_algo_pch_data *adap) } /** - * pch_i2c_wait_for_xfer_complete() - initiates a wait for the tx complete event + * pch_i2c_stop() - generate stop condition in normal mode. * @adap: Pointer to struct i2c_algo_pch_data. */ -static s32 pch_i2c_wait_for_xfer_complete(struct i2c_algo_pch_data *adap) +static void pch_i2c_stop(struct i2c_algo_pch_data *adap) +{ + void __iomem *p = adap->pch_base_address; + pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL)); + /* clear the start bit */ + pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_START); +} + +static int pch_i2c_wait_for_check_xfer(struct i2c_algo_pch_data *adap) { long ret; - ret = wait_event_timeout(pch_event, - (adap->pch_event_flag != 0), msecs_to_jiffies(50)); + void __iomem *p = adap->pch_base_address; - if (ret == 0) { - pch_err(adap, "timeout: %x\n", adap->pch_event_flag); + ret = wait_event_timeout(pch_event, + (adap->pch_event_flag != 0), msecs_to_jiffies(1000)); + if (!ret) { + pch_err(adap, "%s:wait-event timeout\n", __func__); adap->pch_event_flag = 0; + pch_i2c_stop(adap); + pch_i2c_init(adap); return -ETIMEDOUT; } if (adap->pch_event_flag & I2C_ERROR_MASK) { - pch_err(adap, "error bits set: %x\n", adap->pch_event_flag); + pch_err(adap, "Lost Arbitration\n"); adap->pch_event_flag = 0; - return -EIO; + pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT); + pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT); + pch_i2c_init(adap); + return -EAGAIN; } adap->pch_event_flag = 0; - return 0; -} - -/** - * pch_i2c_getack() - to confirm ACK/NACK - * @adap: Pointer to struct i2c_algo_pch_data. - */ -static s32 pch_i2c_getack(struct i2c_algo_pch_data *adap) -{ - u32 reg_val; - void __iomem *p = adap->pch_base_address; - reg_val = ioread32(p + PCH_I2CSR) & PCH_GETACK; - - if (reg_val != 0) { - pch_err(adap, "return%d\n", -EPROTO); - return -EPROTO; + if (ioread32(p + PCH_I2CSR) & PCH_GETACK) { + pch_dbg(adap, "Receive NACK for slave address setting\n"); + return -ENXIO; } return 0; } /** - * pch_i2c_stop() - generate stop condition in normal mode. - * @adap: Pointer to struct i2c_algo_pch_data. - */ -static void pch_i2c_stop(struct i2c_algo_pch_data *adap) -{ - void __iomem *p = adap->pch_base_address; - pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL)); - /* clear the start bit */ - pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_START); -} - -/** * pch_i2c_repstart() - generate repeated start condition in normal mode * @adap: Pointer to struct i2c_algo_pch_data. */ @@ -421,27 +410,12 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, if (first) pch_i2c_start(adap); - rtn = pch_i2c_wait_for_xfer_complete(adap); - if (rtn == 0) { - if (pch_i2c_getack(adap)) { - pch_dbg(adap, "Receive NACK for slave address" - "setting\n"); - return -EIO; - } - addr_8_lsb = (addr & I2C_ADDR_MSK); - iowrite32(addr_8_lsb, p + PCH_I2CDR); - } else if (rtn == -EIO) { /* Arbitration Lost */ - pch_err(adap, "Lost Arbitration\n"); - pch_clrbit(adap->pch_base_address, PCH_I2CSR, - I2CMAL_BIT); - pch_clrbit(adap->pch_base_address, PCH_I2CSR, - I2CMIF_BIT); - pch_i2c_init(adap); - return -EAGAIN; - } else { /* wait-event timeout */ - pch_i2c_stop(adap); - return -ETIME; - } + rtn = pch_i2c_wait_for_check_xfer(adap); + if (rtn) + return rtn; + + addr_8_lsb = (addr & I2C_ADDR_MSK); + iowrite32(addr_8_lsb, p + PCH_I2CDR); } else { /* set 7 bit slave address and R/W bit as 0 */ iowrite32(addr << 1, p + PCH_I2CDR); @@ -449,44 +423,21 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, pch_i2c_start(adap); } - rtn = pch_i2c_wait_for_xfer_complete(adap); - if (rtn == 0) { - if (pch_i2c_getack(adap)) { - pch_dbg(adap, "Receive NACK for slave address" - "setting\n"); - return -EIO; - } - } else if (rtn == -EIO) { /* Arbitration Lost */ - pch_err(adap, "Lost Arbitration\n"); - pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT); - pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT); - pch_i2c_init(adap); - return -EAGAIN; - } else { /* wait-event timeout */ - pch_i2c_stop(adap); - return -ETIME; - } + rtn = pch_i2c_wait_for_check_xfer(adap); + if (rtn) + return rtn; for (wrcount = 0; wrcount < length; ++wrcount) { /* write buffer value to I2C data register */ iowrite32(buf[wrcount], p + PCH_I2CDR); pch_dbg(adap, "writing %x to Data register\n", buf[wrcount]); - rtn = pch_i2c_wait_for_xfer_complete(adap); - if (rtn == 0) { - if (pch_i2c_getack(adap)) { - pch_dbg(adap, "Receive NACK for slave address" - "setting\n"); - return -EIO; - } - pch_clrbit(adap->pch_base_address, PCH_I2CSR, - I2CMCF_BIT); - pch_clrbit(adap->pch_base_address, PCH_I2CSR, - I2CMIF_BIT); - } else { /* wait-event timeout */ - pch_i2c_stop(adap); - return -ETIME; - } + rtn = pch_i2c_wait_for_check_xfer(adap); + if (rtn) + return rtn; + + pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMCF_BIT); + pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT); } /* check if this is the last message */ @@ -574,50 +525,21 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, if (first) pch_i2c_start(adap); - rtn = pch_i2c_wait_for_xfer_complete(adap); - if (rtn == 0) { - if (pch_i2c_getack(adap)) { - pch_dbg(adap, "Receive NACK for slave address" - "setting\n"); - return -EIO; - } - addr_8_lsb = (addr & I2C_ADDR_MSK); - iowrite32(addr_8_lsb, p + PCH_I2CDR); - } else if (rtn == -EIO) { /* Arbitration Lost */ - pch_err(adap, "Lost Arbitration\n"); - pch_clrbit(adap->pch_base_address, PCH_I2CSR, - I2CMAL_BIT); - pch_clrbit(adap->pch_base_address, PCH_I2CSR, - I2CMIF_BIT); - pch_i2c_init(adap); - return -EAGAIN; - } else { /* wait-event timeout */ - pch_i2c_stop(adap); - return -ETIME; - } + rtn = pch_i2c_wait_for_check_xfer(adap); + if (rtn) + return rtn; + + addr_8_lsb = (addr & I2C_ADDR_MSK); + iowrite32(addr_8_lsb, p + PCH_I2CDR); + pch_i2c_restart(adap); - rtn = pch_i2c_wait_for_xfer_complete(adap); - if (rtn == 0) { - if (pch_i2c_getack(adap)) { - pch_dbg(adap, "Receive NACK for slave address" - "setting\n"); - return -EIO; - } - addr_2_msb |= I2C_RD; - iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, - p + PCH_I2CDR); - } else if (rtn == -EIO) { /* Arbitration Lost */ - pch_err(adap, "Lost Arbitration\n"); - pch_clrbit(adap->pch_base_address, PCH_I2CSR, - I2CMAL_BIT); - pch_clrbit(adap->pch_base_address, PCH_I2CSR, - I2CMIF_BIT); - pch_i2c_init(adap); - return -EAGAIN; - } else { /* wait-event timeout */ - pch_i2c_stop(adap); - return -ETIME; - } + + rtn = pch_i2c_wait_for_check_xfer(adap); + if (rtn) + return rtn; + + addr_2_msb |= I2C_RD; + iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); } else { /* 7 address bits + R/W bit */ addr = (((addr) << 1) | (I2C_RD)); @@ -628,23 +550,9 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, if (first) pch_i2c_start(adap); - rtn = pch_i2c_wait_for_xfer_complete(adap); - if (rtn == 0) { - if (pch_i2c_getack(adap)) { - pch_dbg(adap, "Receive NACK for slave address" - "setting\n"); - return -EIO; - } - } else if (rtn == -EIO) { /* Arbitration Lost */ - pch_err(adap, "Lost Arbitration\n"); - pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT); - pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT); - pch_i2c_init(adap); - return -EAGAIN; - } else { /* wait-event timeout */ - pch_i2c_stop(adap); - return -ETIME; - } + rtn = pch_i2c_wait_for_check_xfer(adap); + if (rtn) + return rtn; if (length == 0) { pch_i2c_stop(adap); @@ -663,18 +571,9 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, if (loop != 1) read_index++; - rtn = pch_i2c_wait_for_xfer_complete(adap); - if (rtn == 0) { - if (pch_i2c_getack(adap)) { - pch_dbg(adap, "Receive NACK for slave" - "address setting\n"); - return -EIO; - } - } else { /* wait-event timeout */ - pch_i2c_stop(adap); - return -ETIME; - } - + rtn = pch_i2c_wait_for_check_xfer(adap); + if (rtn) + return rtn; } /* end for */ pch_i2c_sendnack(adap); @@ -684,17 +583,9 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, if (length != 1) read_index++; - rtn = pch_i2c_wait_for_xfer_complete(adap); - if (rtn == 0) { - if (pch_i2c_getack(adap)) { - pch_dbg(adap, "Receive NACK for slave" - "address setting\n"); - return -EIO; - } - } else { /* wait-event timeout */ - pch_i2c_stop(adap); - return -ETIME; - } + rtn = pch_i2c_wait_for_check_xfer(adap); + if (rtn) + return rtn; if (last) pch_i2c_stop(adap); @@ -778,15 +669,13 @@ static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *pmsg; u32 i = 0; u32 status; - u32 msglen; - u32 subaddrlen; s32 ret; struct i2c_algo_pch_data *adap = i2c_adap->algo_data; ret = mutex_lock_interruptible(&pch_mutex); if (ret) - return -ERESTARTSYS; + return ret; if (adap->p_adapter_info->pch_i2c_suspended) { mutex_unlock(&pch_mutex); @@ -804,12 +693,6 @@ static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap, status = pmsg->flags; pch_dbg(adap, "After invoking I2C_MODE_SEL :flag= 0x%x\n", status); - /* calculate sub address length and message length */ - /* these are applicable only for buffer mode */ - subaddrlen = pmsg->buf[0]; - /* calculate actual message length excluding - * the sub address fields */ - msglen = (pmsg->len) - (subaddrlen + 1); if ((status & (I2C_M_RD)) != false) { ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num), @@ -856,7 +739,7 @@ static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap) iowrite32(BUFFER_MODE_INTR_DISBL, p + PCH_I2CBUFMSK); } -static int __devinit pch_i2c_probe(struct pci_dev *pdev, +static int pch_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id) { void __iomem *base_addr; @@ -868,10 +751,8 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev, pch_pci_dbg(pdev, "Entered.\n"); adap_info = kzalloc((sizeof(struct adapter_info)), GFP_KERNEL); - if (adap_info == NULL) { - pch_pci_err(pdev, "Memory allocation FAILED\n"); + if (adap_info == NULL) return -ENOMEM; - } ret = pci_enable_device(pdev); if (ret) { @@ -911,7 +792,7 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev, pch_adap->owner = THIS_MODULE; pch_adap->class = I2C_CLASS_HWMON; - strcpy(pch_adap->name, KBUILD_MODNAME); + strlcpy(pch_adap->name, KBUILD_MODNAME, sizeof(pch_adap->name)); pch_adap->algo = &pch_algorithm; pch_adap->algo_data = &adap_info->pch_data[i]; @@ -949,7 +830,7 @@ err_pci_enable: return ret; } -static void __devexit pch_i2c_remove(struct pci_dev *pdev) +static void pch_i2c_remove(struct pci_dev *pdev) { int i; struct adapter_info *adap_info = pci_get_drvdata(pdev); @@ -965,9 +846,7 @@ static void __devexit pch_i2c_remove(struct pci_dev *pdev) pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address); for (i = 0; i < adap_info->ch_num; i++) - adap_info->pch_data[i].pch_base_address = 0; - - pci_set_drvdata(pdev, NULL); + adap_info->pch_data[i].pch_base_address = NULL; pci_release_regions(pdev); @@ -1046,25 +925,15 @@ static struct pci_driver pch_pcidriver = { .name = KBUILD_MODNAME, .id_table = pch_pcidev_id, .probe = pch_i2c_probe, - .remove = __devexit_p(pch_i2c_remove), + .remove = pch_i2c_remove, .suspend = pch_i2c_suspend, .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"); -MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.lapis-semi.com>"); +MODULE_AUTHOR("Tomoya MORINAGA. <tomoya.rohm@gmail.com>"); module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR)); module_param(pch_clk, int, (S_IRUSR | S_IWUSR)); |
