aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhangfei Gao <zhangfei.gao@linaro.org>2013-01-31 16:37:05 +0800
committerGuodong Xu <guodong.xu@linaro.org>2013-02-21 16:12:29 +0800
commitfde95916f3324ed278ce1e797c174e0f6cf64e9d (patch)
treec0ca2da3e471a415b3a2c03d9fd285e8a03aba0a
parentd53a8ef37e5e56bc74371cafbb9b8dbb2ec47a1f (diff)
i2c: designware: Add i2c-designware-hs.c
Add support hisilicon i2c driver, which reuse designware i2c ip Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-designware-hs.txt30
-rw-r--r--drivers/i2c/busses/Kconfig10
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-designware-hs.c203
4 files changed, 244 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware-hs.txt b/Documentation/devicetree/bindings/i2c/i2c-designware-hs.txt
new file mode 100644
index 000000000000..08908fa16a1d
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-designware-hs.txt
@@ -0,0 +1,30 @@
+* Hisilicon I2C Controller
+
+Required properties :
+
+ - compatible : should be "hisilicon,designware-i2c"
+ - reg : Offset and length of the register set for the device
+ - interrupts : <IRQ> where IRQ is the interrupt number.
+
+Example :
+
+ i2c0: i2c@fcb08000 {
+ compatible = "hs,designware-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xfcb08000 0x1000>;
+ interrupts = <0 28 4>;
+ clocks = <&pclk>;
+ status = "disabled";
+ };
+
+ Client in i2c0 bus with add 0x58 could be added as example
+ i2c0: i2c@fcb08000 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pmx_func &i2c0_cfg_func>;
+ i2c_client1: i2c_client@58 {
+ compatible = "hisilicon,i2c_client_tpa2028";
+ reg = <0x58>;
+ };
+ };
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index bdca5111eb9d..4871d9e7b115 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -395,6 +395,16 @@ config I2C_DESIGNWARE_PCI
This driver can also be built as a module. If so, the module
will be called i2c-designware-pci.
+config I2C_DESIGNWARE_HS
+ tristate "Synopsys DesignWare Hisilicon"
+ depends on ARCH_HS
+ depends on HAVE_CLK
+ select I2C_DESIGNWARE_CORE
+ help
+ If you say yes to this option, support will be included for the
+ Synopsys DesignWare I2C adapter on Hisilicon.
+ Only master mode is supported.
+
config I2C_EG20T
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 6181f3ff263f..f43b7ecf15c6 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
i2c-designware-platform-objs := i2c-designware-platdrv.o
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
i2c-designware-pci-objs := i2c-designware-pcidrv.o
+obj-$(CONFIG_I2C_DESIGNWARE_HS) += i2c-designware-hs.o
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
diff --git a/drivers/i2c/busses/i2c-designware-hs.c b/drivers/i2c/busses/i2c-designware-hs.c
new file mode 100644
index 000000000000..db0712fb9128
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-hs.c
@@ -0,0 +1,203 @@
+/*
+ * Hisilicon Synopsys DesignWare I2C adapter driver (master only).
+ *
+ * Copyright (c) 2012-2013 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/of_i2c.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pinctrl/consumer.h>
+#include "i2c-designware-core.h"
+
+static struct i2c_algorithm hs_i2c_dw_algo = {
+ .master_xfer = i2c_dw_xfer,
+ .functionality = i2c_dw_func,
+};
+static u32 hs_i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
+{
+ return clk_get_rate(dev->clk)/1000;
+}
+
+static int hs_dw_i2c_probe(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *d;
+ struct i2c_adapter *adap;
+ struct resource *iores;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_default;
+ int r;
+
+ d = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
+
+ /* NOTE: driver uses the static register mapping */
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iores)
+ return -EINVAL;
+
+ d->base = devm_request_and_ioremap(&pdev->dev, iores);
+ if (!d->base)
+ return -EADDRNOTAVAIL;
+
+ d->irq = platform_get_irq(pdev, 0);
+ if (d->irq < 0) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return d->irq; /* -ENXIO */
+ }
+
+ r = devm_request_irq(&pdev->dev, d->irq,
+ i2c_dw_isr, IRQF_DISABLED, pdev->name, d);
+ if (r) {
+ dev_err(&pdev->dev, "failure requesting irq %i\n", d->irq);
+ return -EINVAL;
+ }
+
+ pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ return PTR_ERR(pinctrl);
+
+ pins_default = pinctrl_lookup_state(pinctrl,
+ PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(pins_default)) {
+ dev_warn(&pdev->dev, "could not get default pinstate\n");
+ } else {
+ r = pinctrl_select_state(pinctrl, pins_default);
+ if (r)
+ dev_warn(&pdev->dev,
+ "could not set default pins\n");
+ }
+
+ d->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(d->clk))
+ return -ENODEV;
+
+ d->get_clk_rate_khz = hs_i2c_dw_get_clk_rate_khz;
+ clk_prepare_enable(d->clk);
+ init_completion(&d->cmd_complete);
+ mutex_init(&d->lock);
+ d->dev = get_device(&pdev->dev);
+
+ d->functionality =
+ I2C_FUNC_I2C |
+ I2C_FUNC_10BIT_ADDR |
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+ d->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+ DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
+ d->accessor_flags = ACCESS_32BIT;
+ d->tx_fifo_depth = 16;
+ d->rx_fifo_depth = 16;
+
+ r = i2c_dw_init(d);
+ if (r)
+ goto err;
+
+ i2c_dw_disable_int(d);
+
+ adap = &d->adapter;
+ i2c_set_adapdata(adap, d);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
+ sizeof(adap->name));
+ adap->algo = &hs_i2c_dw_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ adap->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
+ if (r) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err;
+ }
+ of_i2c_register_devices(adap);
+ platform_set_drvdata(pdev, d);
+
+ return 0;
+err:
+ clk_disable_unprepare(d->clk);
+ put_device(&pdev->dev);
+ return r;
+}
+
+static int hs_dw_i2c_remove(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *d = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&d->adapter);
+ put_device(&pdev->dev);
+ clk_disable_unprepare(d->clk);
+ i2c_dw_disable(d);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id hs_dw_i2c_of_match[] = {
+ { .compatible = "hisilicon,designware-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, hs_dw_i2c_of_match);
+#endif
+
+#ifdef CONFIG_PM
+static int hs_dw_i2c_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(i_dev->clk);
+
+ return 0;
+}
+
+static int hs_dw_i2c_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
+
+ clk_prepare_enable(i_dev->clk);
+ i2c_dw_init(i_dev);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(hs_dw_i2c_dev_pm_ops, hs_dw_i2c_suspend, hs_dw_i2c_resume);
+
+static struct platform_driver hs_dw_i2c_driver = {
+ .probe = hs_dw_i2c_probe,
+ .remove = hs_dw_i2c_remove,
+ .driver = {
+ .name = "i2c_designware-hs",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(hs_dw_i2c_of_match),
+ .pm = &hs_dw_i2c_dev_pm_ops,
+ },
+};
+module_platform_driver(hs_dw_i2c_driver);
+
+MODULE_DESCRIPTION("HS Synopsys DesignWare I2C bus adapter");
+MODULE_ALIAS("platform:i2c_designware-hs");
+MODULE_LICENSE("GPL");