From: "Jayachandran C." <jayachandranc@netlogicmicro.com>
To: linux-i2c@vger.kernel.org
Cc: linux-mips@linux-mips.org, ganesanr@netlogicmicro.com
Subject: [PATCH] i2c: Support for Netlogic XLR/XLS on-chip I2C controller.
Date: Thu, 23 Jun 2011 19:21:03 +0530 [thread overview]
Message-ID: <20110623135057.GA26772@jayachandranc.netlogicmicro.com> (raw)
From: Ganesan Ramalingam <ganesanr@netlogicmicro.com>
- platform.c : add i2c platform device
- i2c-xlr.c : algorithm and i2c adaptor
- Kconfig/Makefile: add CONFIG_I2C_XLR option
Signed-off-by: Ganesan Ramalingam <ganesanr@netlogicmicro.com>
Signed-off-by: Jayachandran C <jayachandranc@netlogicmicro.com>
---
arch/mips/configs/nlm_xlr_defconfig | 4 +
arch/mips/netlogic/xlr/platform.c | 29 +++
drivers/i2c/busses/Kconfig | 11 ++
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-xlr.c | 335 +++++++++++++++++++++++++++++++++++
5 files changed, 380 insertions(+), 0 deletions(-)
create mode 100644 drivers/i2c/busses/i2c-xlr.c
diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig
index e4b399f..6431fd3 100644
--- a/arch/mips/configs/nlm_xlr_defconfig
+++ b/arch/mips/configs/nlm_xlr_defconfig
@@ -365,6 +365,10 @@ CONFIG_SERIAL_8250_RSA=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_TIMERIOMEM=m
CONFIG_RAW_DRIVER=m
+CONFIG_I2C=y
+CONFIG_I2C_XLR=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1374=y
# CONFIG_HWMON is not set
# CONFIG_VGA_CONSOLE is not set
# CONFIG_HID_SUPPORT is not set
diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c
index 609ec25..2cd2d3c 100644
--- a/arch/mips/netlogic/xlr/platform.c
+++ b/arch/mips/netlogic/xlr/platform.c
@@ -14,6 +14,7 @@
#include <linux/resource.h>
#include <linux/serial_8250.h>
#include <linux/serial_reg.h>
+#include <linux/i2c.h>
#include <asm/netlogic/xlr/iomap.h>
#include <asm/netlogic/xlr/pic.h>
@@ -66,6 +67,34 @@ void nlm_xlr_uart_out(struct uart_port *p, int offset, int value)
.serial_out = nlm_xlr_uart_out, \
}
+#ifdef CONFIG_I2C
+static struct i2c_board_info nlm_i2c_info1[] __initdata = {
+ /* All XLR boards have this RTC and Max6657 Temp Chip */
+ {"ds1374", 0, 0x68, 0, 0, 0},
+ {"lm90", 0, 0x4c, 0, 0, 0},
+};
+
+static struct platform_device nlm_xlr_i2c_1 = {
+ .name = "xlr_i2cbus",
+ .id = 1,
+};
+
+static int __init nlm_i2c_init(void)
+{
+ int err = 0;
+
+ platform_device_register(&nlm_xlr_i2c_1);
+
+ err = i2c_register_board_info(1, nlm_i2c_info1,
+ ARRAY_SIZE(nlm_i2c_info1));
+ if (err < 0)
+ pr_err("nlm-i2c: cannot register board I2C devices\n");
+ return err;
+}
+
+arch_initcall(nlm_i2c_init);
+#endif
+
static struct plat_serial8250_port xlr_uart_data[] = {
PORT(PIC_UART_0_IRQ),
PORT(PIC_UART_1_IRQ),
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 646068e..a75af78 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -309,6 +309,17 @@ config I2C_AU1550
This driver can also be built as a module. If so, the module
will be called i2c-au1550.
+config I2C_XLR
+ tristate "XLR I2C support"
+ depends on I2C && CPU_XLR
+ help
+ This driver enables support for the on-chip I2C interface of
+ the Netlogic XLR/XLS MIPS processors.
+
+ Say yes to this option if you have a Netlogic XLR/XLS based
+ board and you need to access the I2C devices (typically the
+ RTC, sensors, EEPROM) connected to this interface.
+
config I2C_BLACKFIN_TWI
tristate "Blackfin TWI I2C support"
depends on BLACKFIN
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index e6cf294..14e7a76 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
+obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
# External I2C/SMBus adapter drivers
diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c
new file mode 100644
index 0000000..ac3d989
--- /dev/null
+++ b/drivers/i2c/busses/i2c-xlr.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2011, Netlogic Microsystems Inc.
+ * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <asm/netlogic/xlr/iomap.h>
+
+/* XLR I2C REGISTERS */
+#define XLR_I2C_CFG 0x00
+#define XLR_I2C_CLKDIV 0x01
+#define XLR_I2C_DEVADDR 0x02
+#define XLR_I2C_ADDR 0x03
+#define XLR_I2C_DATAOUT 0x04
+#define XLR_I2C_DATAIN 0x05
+#define XLR_I2C_STATUS 0x06
+#define XLR_I2C_STARTXFR 0x07
+#define XLR_I2C_BYTECNT 0x08
+#define XLR_I2C_HDSTATIM 0x09
+
+/* XLR I2C REGISTERS FLAGS */
+#define XLR_I2C_BUS_BUSY 0x01
+#define XLR_I2C_SDOEMPTY 0x02
+#define XLR_I2C_RXRDY 0x04
+#define XLR_I2C_ACK_ERR 0x08
+#define XLR_I2C_ARB_STARTERR 0x30
+
+/* Register Programming Values!! Change as required */
+#define XLR_I2C_CFG_ADDR 0xF8 /* 8-Bit dev Addr + POR Values */
+#define XLR_I2C_CFG_NOADDR 0xFA /* 8-Bit reg Addr + POR Values */
+#define XLR_I2C_STARTXFR_ND 0x02 /* No data , only addr */
+#define XLR_I2C_STARTXFR_RD 0x01 /* Read */
+#define XLR_I2C_STARTXFR_WR 0x00 /* Write */
+#define XLR_I2C_CLKDIV_DEF 0x14A /* 0x00000052 */
+#define XLR_I2C_HDSTATIM_DEF 0x107 /* 0x00000000 */
+
+struct xlr_i2c_private {
+ struct i2c_adapter adap;
+ u32 *iobase_i2c_regs;
+};
+static struct xlr_i2c_private xlr_i2c_priv;
+
+u32 *get_i2c_base(unsigned short bus)
+{
+ nlm_reg_t *mmio = 0;
+
+ if (bus == 0)
+ mmio = netlogic_io_mmio(NETLOGIC_IO_I2C_0_OFFSET);
+ else
+ mmio = netlogic_io_mmio(NETLOGIC_IO_I2C_1_OFFSET);
+
+ return (u32 *)mmio;
+}
+
+static void xlr_i2c_write(u32 *iobase_i2c_regs, int reg, int val)
+{
+ netlogic_write_reg(iobase_i2c_regs, reg, val);
+}
+
+static u32 xlr_i2c_read(u32 *iobase_i2c_regs, int reg)
+{
+ u32 retVal = netlogic_read_reg(iobase_i2c_regs, reg);
+ return retVal;
+}
+
+static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len,
+ u8 *buf, u16 addr, u8 offset)
+{
+ u32 i2c_status = 0x00;
+ u8 nb;
+ int pos;
+
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_ADDR, offset);
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_DEVADDR, addr);
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_CFG, XLR_I2C_CFG_ADDR);
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_BYTECNT, len - 1);
+
+retry:
+ pos = 0;
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_DATAOUT, buf[pos]);
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_STARTXFR,
+ XLR_I2C_STARTXFR_WR);
+
+ while (1) {
+ i2c_status = xlr_i2c_read(priv->iobase_i2c_regs,
+ XLR_I2C_STATUS);
+
+ if (i2c_status & XLR_I2C_SDOEMPTY) {
+ pos++;
+ nb = (pos < len) ? buf[pos] : 0;
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_DATAOUT,
+ nb);
+ }
+
+ if (i2c_status & XLR_I2C_ARB_STARTERR)
+ goto retry;
+
+ if (i2c_status & XLR_I2C_ACK_ERR) {
+ dev_err(&priv->adap.dev, "ACK ERR\n");
+ return -1;
+ }
+
+ if (i2c_status & XLR_I2C_BUS_BUSY)
+ continue;
+
+ if (pos >= len)
+ break;
+ }
+
+ return 0;
+}
+
+static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len,
+ u8 *buf, u16 addr, u8 offset)
+{
+ u32 i2c_status = 0x00;
+ int pos = 0;
+ int timeOut = 0;
+ struct i2c_adapter *adap = &priv->adap;
+
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_ADDR, offset);
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_DEVADDR, addr);
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_CFG, XLR_I2C_CFG_ADDR);
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_BYTECNT, 0);
+
+retry_nd:
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_STARTXFR,
+ XLR_I2C_STARTXFR_ND);
+ while (1) {
+ if (timeOut++ > 0x1000) {
+ dev_err(&adap->dev, "XLR_I2C_STARTXFR_ND Rx Timeout\n");
+ return -1;
+ }
+
+ i2c_status = xlr_i2c_read(priv->iobase_i2c_regs,
+ XLR_I2C_STATUS);
+ if (i2c_status & XLR_I2C_ARB_STARTERR)
+ goto retry_nd;
+
+ if (i2c_status & XLR_I2C_ACK_ERR) {
+ dev_err(&adap->dev, "XLR_I2C_STARTXFR_ND ACK ERR\n");
+ return -1;
+ }
+ if ((i2c_status & XLR_I2C_BUS_BUSY) == 0)
+ break;
+ udelay(1);
+ }
+
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR);
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_BYTECNT, len-1);
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_ADDR, offset);
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_DEVADDR, addr);
+ timeOut = 0;
+
+retry:
+ xlr_i2c_write(priv->iobase_i2c_regs, XLR_I2C_STARTXFR,
+ XLR_I2C_STARTXFR_RD);
+
+ while (1) {
+ if (timeOut++ > 0x1000) {
+ dev_err(&adap->dev, "XLR_I2C_STARTXFR_RD Rx Timeout\n");
+ return -1;
+ }
+
+ i2c_status = xlr_i2c_read(priv->iobase_i2c_regs,
+ XLR_I2C_STATUS);
+ if (i2c_status & XLR_I2C_RXRDY) {
+ buf[pos++] = (u8)xlr_i2c_read(priv->iobase_i2c_regs,
+ XLR_I2C_DATAIN);
+ }
+
+ if (i2c_status & XLR_I2C_ARB_STARTERR)
+ goto retry;
+
+ if (i2c_status & XLR_I2C_ACK_ERR) {
+ dev_err(&adap->dev, "XLR_I2C_STARTXFR_ND ACK ERR\n");
+ return -1;
+ }
+
+ if (i2c_status & XLR_I2C_BUS_BUSY) {
+ udelay(1);
+ continue;
+ }
+ break;
+ }
+ return 0;
+}
+
+static int smbus_xfer(struct i2c_adapter *i2c_adap,
+ u16 addr,
+ unsigned short flags,
+ char read_write,
+ u8 command,
+ int protocol,
+ union i2c_smbus_data *data)
+{
+ struct xlr_i2c_private *priv = i2c_adap->algo_data;
+ int err;
+ int len;
+
+ switch (protocol) {
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ)
+ err = xlr_i2c_rx(priv, 1, &data->byte, addr, command);
+ else
+ err = xlr_i2c_tx(priv, 1, &data->byte, addr, command);
+
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_READ)
+ err = xlr_i2c_rx(priv, 1, &data->byte, addr, command);
+ else
+ err = xlr_i2c_tx(priv, 1, &data->byte, addr, command);
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ if (read_write == I2C_SMBUS_READ)
+ err = xlr_i2c_rx(priv, 2, (u8 *)&data->word,
+ addr, command);
+ else
+ err = xlr_i2c_tx(priv, 2, (u8 *)&data->word,
+ addr, command);
+
+ break;
+ case I2C_FUNC_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ len = (data->block[0] > I2C_SMBUS_BLOCK_MAX) ?
+ I2C_SMBUS_BLOCK_MAX : data->block[0];
+ if (read_write == I2C_SMBUS_READ)
+ err = xlr_i2c_rx(priv, len, &data->block[1],
+ addr, command);
+ else
+ err = xlr_i2c_tx(priv, len, &data->block[1],
+ addr, command);
+
+ break;
+ default:
+ err = -1;
+ }
+ return err;
+}
+
+static u32 xlr_func(struct i2c_adapter *adap)
+{
+ /* We emulate SMBUS over I2C */
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm xlr_i2c_algo = {
+ .smbus_xfer = smbus_xfer,
+ .functionality = xlr_func,
+};
+
+int xlr_i2c_add_bus(struct xlr_i2c_private *priv)
+{
+ priv->adap.owner = THIS_MODULE;
+ priv->adap.algo_data = priv;
+ priv->adap.nr = 1;
+ priv->adap.algo = &xlr_i2c_algo;
+ priv->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ snprintf(priv->adap.name, sizeof(priv->adap.name),
+ "SMBus XLR I2C Adapter");
+
+ /* register new adapter to i2c module... */
+ if (i2c_add_numbered_adapter(&priv->adap))
+ return -1;
+
+ return 0;
+}
+
+int xlr_i2c_del_bus(struct i2c_adapter *adap)
+{
+ return i2c_del_adapter(adap);
+}
+
+static int __devinit xlr_i2c_probe(struct platform_device *pd)
+{
+ xlr_i2c_priv.iobase_i2c_regs = get_i2c_base(pd->id);
+
+ xlr_i2c_priv.adap.dev.parent = &pd->dev;
+ if (xlr_i2c_add_bus(&xlr_i2c_priv) < 0) {
+ dev_err(&xlr_i2c_priv.adap.dev, "Failed to add i2c bus\n");
+ goto out;
+ } else
+ dev_info(&xlr_i2c_priv.adap.dev, "Added I2C Bus.\n");
+
+ return 0;
+out:
+ return -ENODEV;
+}
+
+static int __devexit xlr_i2c_remove(struct platform_device *pd)
+{
+ return xlr_i2c_del_bus(&xlr_i2c_priv.adap);
+}
+
+static struct platform_driver xlr_i2c_driver = {
+ .probe = xlr_i2c_probe,
+ .remove = __devexit_p(xlr_i2c_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "xlr_i2cbus",
+ },
+};
+
+static int __init xlr_i2c_init(void)
+{
+ return platform_driver_register(&xlr_i2c_driver);
+}
+
+static void __exit xlr_i2c_exit(void)
+{
+ platform_driver_unregister(&xlr_i2c_driver);
+}
+
+MODULE_AUTHOR("Netlogic Microsystems Inc.");
+MODULE_DESCRIPTION("XLR I2C SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(xlr_i2c_init);
+module_exit(xlr_i2c_exit);
--
1.7.4.1
next reply other threads:[~2011-06-23 13:51 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-06-23 13:51 Jayachandran C. [this message]
[not found] ` <20110623135057.GA26772-l4W0uAg2RDvWG0bvociYJ/An/qbn1+6FOui0OUZsNXA@public.gmane.org>
2011-07-09 9:37 ` [RESEND] [PATCH] i2c: Support for Netlogic XLR/XLS on-chip I2C controller Mark Brown
[not found] ` <20110709093742.GA9247-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2011-07-11 7:02 ` Jayachandran C.
[not found] ` <20110711070202.GB31303-l4W0uAg2RDvWG0bvociYJ/An/qbn1+6FOui0OUZsNXA@public.gmane.org>
2011-07-11 7:14 ` Mark Brown
2011-07-13 21:56 ` Ben Dooks
2011-07-13 21:56 ` Ben Dooks
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110623135057.GA26772@jayachandranc.netlogicmicro.com \
--to=jayachandranc@netlogicmicro.com \
--cc=ganesanr@netlogicmicro.com \
--cc=linux-i2c@vger.kernel.org \
--cc=linux-mips@linux-mips.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.