diff options
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 11 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-cpm.c | 9 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-eg20t.c | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ibm_iic.c | 9 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mpc.c | 22 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ocores.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 4 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-puv3.c | 306 |
9 files changed, 338 insertions, 27 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 113505a6434..cbfcf6fb4a6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -523,6 +523,17 @@ config I2C_PNX This driver can also be built as a module. If so, the module will be called i2c-pnx. +config I2C_PUV3 + tristate "PKUnity v3 I2C bus support" + depends on UNICORE32 && ARCH_PUV3 + select I2C_ALGOBIT + help + This driver supports the I2C IP inside the PKUnity-v3 SoC. + This I2C bus controller is under AMBA/AXI bus. + + This driver can also be built as a module. If so, the module + will be called i2c-puv3. + config I2C_PXA tristate "Intel PXA2XX I2C adapter" depends on ARCH_PXA || ARCH_MMP diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 9d2d0ec7fb2..a83966acc5a 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o +obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_S6000) += i2c-s6000.o diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index f2de3be35df..3a20961bef1 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -634,8 +634,7 @@ static void cpm_i2c_shutdown(struct cpm_i2c *cpm) cpm_muram_free(cpm->i2c_addr); } -static int __devinit cpm_i2c_probe(struct platform_device *ofdev, - const struct of_device_id *match) +static int __devinit cpm_i2c_probe(struct platform_device *ofdev) { int result, len; struct cpm_i2c *cpm; @@ -718,7 +717,7 @@ static const struct of_device_id cpm_i2c_match[] = { MODULE_DEVICE_TABLE(of, cpm_i2c_match); -static struct of_platform_driver cpm_i2c_driver = { +static struct platform_driver cpm_i2c_driver = { .probe = cpm_i2c_probe, .remove = __devexit_p(cpm_i2c_remove), .driver = { @@ -730,12 +729,12 @@ static struct of_platform_driver cpm_i2c_driver = { static int __init cpm_i2c_init(void) { - return of_register_platform_driver(&cpm_i2c_driver); + return platform_driver_register(&cpm_i2c_driver); } static void __exit cpm_i2c_exit(void) { - of_unregister_platform_driver(&cpm_i2c_driver); + platform_driver_unregister(&cpm_i2c_driver); } module_init(cpm_i2c_init); diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 2e067dd2ee5..50ea1f43bdc 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -29,6 +29,7 @@ #include <linux/pci.h> #include <linux/mutex.h> #include <linux/ktime.h> +#include <linux/slab.h> #define PCH_EVENT_SET 0 /* I2C Interrupt Event Set Status */ #define PCH_EVENT_NONE 1 /* I2C Interrupt Event Clear Status */ diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 6e3c3824033..e4f88dca99b 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -691,8 +691,7 @@ static int __devinit iic_request_irq(struct platform_device *ofdev, /* * Register single IIC interface */ -static int __devinit iic_probe(struct platform_device *ofdev, - const struct of_device_id *match) +static int __devinit iic_probe(struct platform_device *ofdev) { struct device_node *np = ofdev->dev.of_node; struct ibm_iic_private *dev; @@ -806,7 +805,7 @@ static const struct of_device_id ibm_iic_match[] = { {} }; -static struct of_platform_driver ibm_iic_driver = { +static struct platform_driver ibm_iic_driver = { .driver = { .name = "ibm-iic", .owner = THIS_MODULE, @@ -818,12 +817,12 @@ static struct of_platform_driver ibm_iic_driver = { static int __init iic_init(void) { - return of_register_platform_driver(&ibm_iic_driver); + return platform_driver_register(&ibm_iic_driver); } static void __exit iic_exit(void) { - of_unregister_platform_driver(&ibm_iic_driver); + platform_driver_unregister(&ibm_iic_driver); } module_init(iic_init); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index b74e6dc6886..75b984c519a 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -560,8 +560,7 @@ static struct i2c_adapter mpc_ops = { .timeout = HZ, }; -static int __devinit fsl_i2c_probe(struct platform_device *op, - const struct of_device_id *match) +static int __devinit fsl_i2c_probe(struct platform_device *op) { struct mpc_i2c *i2c; const u32 *prop; @@ -569,6 +568,9 @@ static int __devinit fsl_i2c_probe(struct platform_device *op, int result = 0; int plen; + if (!op->dev.of_match) + return -EINVAL; + i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; @@ -603,8 +605,8 @@ static int __devinit fsl_i2c_probe(struct platform_device *op, clock = *prop; } - if (match->data) { - struct mpc_i2c_data *data = match->data; + if (op->dev.of_match->data) { + struct mpc_i2c_data *data = op->dev.of_match->data; data->setup(op->dev.of_node, i2c, clock, data->prescaler); } else { /* Backwards compatibility */ @@ -700,7 +702,7 @@ static const struct of_device_id mpc_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, mpc_i2c_of_match); /* Structure for a device driver */ -static struct of_platform_driver mpc_i2c_driver = { +static struct platform_driver mpc_i2c_driver = { .probe = fsl_i2c_probe, .remove = __devexit_p(fsl_i2c_remove), .driver = { @@ -712,18 +714,12 @@ static struct of_platform_driver mpc_i2c_driver = { static int __init fsl_i2c_init(void) { - int rv; - - rv = of_register_platform_driver(&mpc_i2c_driver); - if (rv) - printk(KERN_ERR DRV_NAME - " of_register_platform_driver failed (%i)\n", rv); - return rv; + return platform_driver_register(&mpc_i2c_driver); } static void __exit fsl_i2c_exit(void) { - of_unregister_platform_driver(&mpc_i2c_driver); + platform_driver_unregister(&mpc_i2c_driver); } module_init(fsl_i2c_init); diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index c2ef5ce1f1f..1b46a9d9f90 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -249,7 +249,7 @@ static struct i2c_adapter ocores_adapter = { static int ocores_i2c_of_probe(struct platform_device* pdev, struct ocores_i2c* i2c) { - __be32* val; + const __be32* val; val = of_get_property(pdev->dev.of_node, "regstep", NULL); if (!val) { diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 829a2a1029f..58a58c7eaa1 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -378,9 +378,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) * REVISIT: Some wkup sources might not be needed. */ dev->westate = OMAP_I2C_WE_ALL; - if (dev->rev < OMAP_I2C_REV_ON_4430) - omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, - dev->westate); + omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); } } omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c new file mode 100644 index 00000000000..fac67394084 --- /dev/null +++ b/drivers/i2c/busses/i2c-puv3.c @@ -0,0 +1,306 @@ +/* + * I2C driver for PKUnity-v3 SoC + * Code specific to PKUnity SoC and UniCore ISA + * + * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> + * Copyright (C) 2001-2010 Guan Xuetao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <mach/hardware.h> + +/* + * Poll the i2c status register until the specified bit is set. + * Returns 0 if timed out (100 msec). + */ +static short poll_status(unsigned long bit) +{ + int loop_cntr = 1000; + + if (bit & I2C_STATUS_TFNF) { + do { + udelay(10); + } while (!(readl(I2C_STATUS) & bit) && (--loop_cntr > 0)); + } else { + /* RXRDY handler */ + do { + if (readl(I2C_TAR) == I2C_TAR_EEPROM) + msleep(20); + else + udelay(10); + } while (!(readl(I2C_RXFLR) & 0xf) && (--loop_cntr > 0)); + } + + return (loop_cntr > 0); +} + +static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) +{ + int i2c_reg = *buf; + + /* Read data */ + while (length--) { + if (!poll_status(I2C_STATUS_TFNF)) { + dev_dbg(&adap->dev, "Tx FIFO Not Full timeout\n"); + return -ETIMEDOUT; + } + + /* send addr */ + writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD); + + /* get ready to next write */ + i2c_reg++; + + /* send read CMD */ + writel(I2C_DATACMD_READ, I2C_DATACMD); + + /* wait until the Rx FIFO have available */ + if (!poll_status(I2C_STATUS_RFNE)) { + dev_dbg(&adap->dev, "RXRDY timeout\n"); + return -ETIMEDOUT; + } + + /* read the data to buf */ + *buf = (readl(I2C_DATACMD) & I2C_DATACMD_DAT_MASK); + buf++; + } + + return 0; +} + +static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length) +{ + int i2c_reg = *buf; + + /* Do nothing but storing the reg_num to a static variable */ + if (i2c_reg == -1) { + printk(KERN_WARNING "Error i2c reg\n"); + return -ETIMEDOUT; + } + + if (length == 1) + return 0; + + buf++; + length--; + while (length--) { + /* send addr */ + writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD); + + /* send write CMD */ + writel(*buf | I2C_DATACMD_WRITE, I2C_DATACMD); + + /* wait until the Rx FIFO have available */ + msleep(20); + + /* read the data to buf */ + i2c_reg++; + buf++; + } + + return 0; +} + +/* + * Generic i2c master transfer entrypoint. + * + */ +static int puv3_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, + int num) +{ + int i, ret; + unsigned char swap; + + /* Disable i2c */ + writel(I2C_ENABLE_DISABLE, I2C_ENABLE); + + /* Set the work mode and speed*/ + writel(I2C_CON_MASTER | I2C_CON_SPEED_STD | I2C_CON_SLAVEDISABLE, I2C_CON); + + writel(pmsg->addr, I2C_TAR); + + /* Enable i2c */ + writel(I2C_ENABLE_ENABLE, I2C_ENABLE); + + dev_dbg(&adap->dev, "puv3_i2c_xfer: processing %d messages:\n", num); + + for (i = 0; i < num; i++) { + dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i, + pmsg->flags & I2C_M_RD ? "read" : "writ", + pmsg->len, pmsg->len > 1 ? "s" : "", + pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr); + + if (pmsg->len && pmsg->buf) { /* sanity check */ + if (pmsg->flags & I2C_M_RD) + ret = xfer_read(adap, pmsg->buf, pmsg->len); + else + ret = xfer_write(adap, pmsg->buf, pmsg->len); + + if (ret) + return ret; + + } + dev_dbg(&adap->dev, "transfer complete\n"); + pmsg++; /* next message */ + } + + /* XXX: fixup be16_to_cpu in bq27x00_battery.c */ + if (pmsg->addr == I2C_TAR_PWIC) { + swap = pmsg->buf[0]; + pmsg->buf[0] = pmsg->buf[1]; + pmsg->buf[1] = swap; + } + + return i; +} + +/* + * Return list of supported functionality. + */ +static u32 puv3_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm puv3_i2c_algorithm = { + .master_xfer = puv3_i2c_xfer, + .functionality = puv3_i2c_func, +}; + +/* + * Main initialization routine. + */ +static int __devinit puv3_i2c_probe(struct platform_device *pdev) +{ + struct i2c_adapter *adapter; + struct resource *mem; + int rc; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENODEV; + + if (!request_mem_region(mem->start, resource_size(mem), "puv3_i2c")) + return -EBUSY; + + adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); + if (adapter == NULL) { + dev_err(&pdev->dev, "can't allocate inteface!\n"); + rc = -ENOMEM; + goto fail_nomem; + } + snprintf(adapter->name, sizeof(adapter->name), "PUV3-I2C at 0x%08x", + mem->start); + adapter->algo = &puv3_i2c_algorithm; + adapter->class = I2C_CLASS_HWMON; + adapter->dev.parent = &pdev->dev; + + platform_set_drvdata(pdev, adapter); + + adapter->nr = pdev->id; + rc = i2c_add_numbered_adapter(adapter); + if (rc) { + dev_err(&pdev->dev, "Adapter '%s' registration failed\n", + adapter->name); + goto fail_add_adapter; + } + + dev_info(&pdev->dev, "PKUnity v3 i2c bus adapter.\n"); + return 0; + +fail_add_adapter: + platform_set_drvdata(pdev, NULL); + kfree(adapter); +fail_nomem: + release_mem_region(mem->start, resource_size(mem)); + + return rc; +} + +static int __devexit puv3_i2c_remove(struct platform_device *pdev) +{ + struct i2c_adapter *adapter = platform_get_drvdata(pdev); + struct resource *mem; + int rc; + + rc = i2c_del_adapter(adapter); + if (rc) { + dev_err(&pdev->dev, "Adapter '%s' delete fail\n", + adapter->name); + return rc; + } + + put_device(&pdev->dev); + platform_set_drvdata(pdev, NULL); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, resource_size(mem)); + + return rc; +} + +#ifdef CONFIG_PM +static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state) +{ + int poll_count; + /* Disable the IIC */ + writel(I2C_ENABLE_DISABLE, I2C_ENABLE); + for (poll_count = 0; poll_count < 50; poll_count++) { + if (readl(I2C_ENSTATUS) & I2C_ENSTATUS_ENABLE) + udelay(25); + } + + return 0; +} + +static int puv3_i2c_resume(struct platform_device *dev) +{ + return 0 ; +} +#else +#define puv3_i2c_suspend NULL +#define puv3_i2c_resume NULL +#endif + +MODULE_ALIAS("platform:puv3_i2c"); + +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, + } +}; + +static int __init puv3_i2c_init(void) +{ + return platform_driver_register(&puv3_i2c_driver); +} + +static void __exit puv3_i2c_exit(void) +{ + platform_driver_unregister(&puv3_i2c_driver); +} + +module_init(puv3_i2c_init); +module_exit(puv3_i2c_exit); + +MODULE_DESCRIPTION("PKUnity v3 I2C driver"); +MODULE_LICENSE("GPL v2"); |