diff options
Diffstat (limited to 'drivers/i2c')
-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-ibm_iic.c | 9 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mpc.c | 22 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ocores.c | 14 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-puv3.c | 306 | ||||
-rw-r--r-- | drivers/i2c/i2c-core.c | 2 |
8 files changed, 338 insertions, 36 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a6ac86e09a85..230601e8853f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -533,6 +533,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 94ab2665665f..3878c959d4fa 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -52,6 +52,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 f2de3be35df3..3a20961bef1e 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-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 6e3c38240336..e4f88dca99b5 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 b74e6dc6886c..75b984c519ac 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 61653f079671..1b46a9d9f907 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -330,9 +330,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) i2c->adap = ocores_adapter; i2c_set_adapdata(&i2c->adap, i2c); i2c->adap.dev.parent = &pdev->dev; -#ifdef CONFIG_OF i2c->adap.dev.of_node = pdev->dev.of_node; -#endif /* add i2c adapter to i2c tree */ ret = i2c_add_adapter(&i2c->adap); @@ -390,15 +388,11 @@ static int ocores_i2c_resume(struct platform_device *pdev) #define ocores_i2c_resume NULL #endif -#ifdef CONFIG_OF static struct of_device_id ocores_i2c_match[] = { - { - .compatible = "opencores,i2c-ocores", - }, - {}, + { .compatible = "opencores,i2c-ocores", }, + {}, }; MODULE_DEVICE_TABLE(of, ocores_i2c_match); -#endif /* work with hotplug and coldplug */ MODULE_ALIAS("platform:ocores-i2c"); @@ -411,9 +405,7 @@ static struct platform_driver ocores_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = "ocores-i2c", -#ifdef CONFIG_OF - .of_match_table = ocores_i2c_match, -#endif + .of_match_table = ocores_i2c_match, }, }; diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c new file mode 100644 index 000000000000..fac673940849 --- /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"); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index f0bd5bcdf563..045ba6efea48 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -537,9 +537,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; -#ifdef CONFIG_OF client->dev.of_node = info->of_node; -#endif dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), client->addr); |