[linux-yocto] [PATCH 47/78] drivers/i2c: New I2C bus driver

Paul Butler butler.paul at gmail.com
Tue Nov 19 20:23:23 PST 2013


From: Anders Berg <anders.berg at lsi.com>

Signed-off-by: Anders Berg <anders.berg at lsi.com>
---
 arch/arm/boot/dts/axm55xx.dts  |   6 +
 arch/arm/mach-axxia/clock.c    |   7 +-
 drivers/i2c/busses/Makefile    |   2 +-
 drivers/i2c/busses/i2c-axxia.c | 569 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 582 insertions(+), 2 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-axxia.c

diff --git a/arch/arm/boot/dts/axm55xx.dts b/arch/arm/boot/dts/axm55xx.dts
index 72cc760..9315ef2 100644
--- a/arch/arm/boot/dts/axm55xx.dts
+++ b/arch/arm/boot/dts/axm55xx.dts
@@ -299,6 +299,12 @@
                 port = <1>;
                 reg = <0x20 0x10085000 0x00 0x1000>;
 		interrupts = <0 20 4>;
+
+                eeprom at 54 {
+                        compatible = "24c1024";
+                        reg = <0x54>;
+			pagesize = <128>;
+                };
         };
 
         I2C2: i2c at 0x02010086000 {
diff --git a/arch/arm/mach-axxia/clock.c b/arch/arm/mach-axxia/clock.c
index 4ad8cb9..49ca80b 100644
--- a/arch/arm/mach-axxia/clock.c
+++ b/arch/arm/mach-axxia/clock.c
@@ -90,7 +90,7 @@ static struct of_device_id cpu_pll[] __initconst = {
 };
 
 /*
-  -------------------------------------------------------------------------------
+  --------------------------------------------------------------------
   axxia_init_clocks
 
   Clock setup for Emulation/ASIC systems.
@@ -134,6 +134,11 @@ axxia_init_clocks(void)
 	clk_register_clkdev(clk, NULL, "2010083000.uart");
 	/* PL022 SSP */
 	clk_register_clkdev(clk, NULL, "ssp");
+	/* I2C */
+	clk_register_clkdev(clk, NULL, "2010084000.i2c");
+	clk_register_clkdev(clk, NULL, "2010085000.i2c");
+	clk_register_clkdev(clk, NULL, "2010086000.i2c");
+	clk_register_clkdev(clk, NULL, "2010087000.i2c");
 	/* SP804 timers */
 	clk_register_clkdev(clk, NULL, "sp804");
 	for (i = 0; i < 8; i++)
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index b325ee6..2de3ab5 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
 # Embedded system I2C/SMBus host controller drivers
 obj-$(CONFIG_I2C_AT91)		+= i2c-at91.o
 obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o
+obj-$(CONFIG_I2C_AXXIA)		+= i2c-axxia.o
 obj-$(CONFIG_I2C_BLACKFIN_TWI)	+= i2c-bfin-twi.o
 obj-$(CONFIG_I2C_CPM)		+= i2c-cpm.o
 obj-$(CONFIG_I2C_DAVINCI)	+= i2c-davinci.o
@@ -92,5 +93,4 @@ obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
 
-obj-$(CONFIG_I2C_AXXIA)	+= ai2c/
 obj-$(CONFIG_ACP3400_I2C)	+= acp3400-i2c.o
diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
new file mode 100644
index 0000000..1dd58d9
--- /dev/null
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -0,0 +1,569 @@
+/*
+ * drivers/i2c/busses/i2c-axxia.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_i2c.h>
+#include <linux/module.h>
+
+#define I2C_TIMEOUT   (msecs_to_jiffies(1000))
+#define TX_FIFO_SIZE  8
+#define RX_FIFO_SIZE  8
+
+struct i2c_regs {
+	__le32 global_control;
+	__le32 interrupt_status;
+	__le32 interrupt_enable;
+	__le32 wait_timer_control;
+	__le32 ibml_timeout;
+	__le32 ibml_low_mext;
+	__le32 ibml_low_sext;
+	__le32 timer_clock_div;
+	__le32 i2c_bus_monitor;
+	__le32 soft_reset;
+	__le32 mst_command;
+#define CMD_MANUAL 0x08
+#define CMD_AUTO   0x09
+	__le32 mst_rx_xfer;
+	__le32 mst_tx_xfer;
+	__le32 mst_addr_1;
+	__le32 mst_addr_2;
+#define CHIP_READ(_chip)  (((_chip) << 1) | 1)
+#define CHIP_WRITE(_chip) (((_chip) << 1) | 0)
+	__le32 mst_data;
+	__le32 mst_tx_fifo;
+	__le32 mst_rx_fifo;
+	__le32 mst_int_enable;
+	__le32 mst_int_status;
+#define MST_STATUS_RFL (1<<13) /* RX FIFO serivce */
+#define MST_STATUS_TFL (1<<12) /* TX FIFO service */
+#define MST_STATUS_SNS (1<<11) /* Manual mode done */
+#define MST_STATUS_SS  (1<<10) /* Automatic mode done */
+#define MST_STATUS_SCC (1<<9)  /* Stop complete */
+#define MST_STATUS_TSS (1<<7)  /* Timeout */
+#define MST_STATUS_AL  (1<<6)  /* Arbitration lost */
+#define MST_STATUS_NAK (MST_STATUS_NA | MST_STATUS_ND)
+#define MST_STATUS_ND  (1<<5)  /* NAK on data phase */
+#define MST_STATUS_NA  (1<<4)  /* NAK on address phase */
+#define MST_STATUS_ERR (MST_STATUS_NAK | MST_STATUS_AL | MST_STATUS_TSS)
+	__le32 mst_tx_bytes_xfrd;
+	__le32 mst_rx_bytes_xfrd;
+	__le32 slv_addr_dec_ctl;
+	__le32 slv_addr_1;
+	__le32 slv_addr_2;
+	__le32 slv_rx_ctl;
+	__le32 slv_data;
+	__le32 slv_rx_fifo;
+	__le32 slv_int_enable;
+	__le32 slv_int_status;
+	__le32 slv_read_dummy;
+	__le32 reserved;
+	__le32 scl_high_period;
+	__le32 scl_low_period;
+	__le32 spike_fltr_len;
+	__le32 sda_setup_time;
+	__le32 sda_hold_time;
+	__le32 smb_alert;
+	__le32 udid_w7;
+	__le32 udid_w6;
+	__le32 udid_w5;
+	__le32 udid_w4;
+	__le32 udid_w3;
+	__le32 udid_w2;
+	__le32 udid_w1;
+	__le32 udid_w0;
+	__le32 arppec_cfg_stat;
+	__le32 slv_arp_int_enable;
+	__le32 slv_arp_int_status;
+	__le32 mst_arp_int_enable;
+	__le32 mst_arp_int_status;
+};
+
+
+/**
+ * I2C device context
+ */
+struct axxia_i2c_dev {
+	/** device reference */
+	struct device *dev;
+	/** core i2c abstraction */
+	struct i2c_adapter adapter;
+	/* clock reference for i2c input clock */
+	struct clk *i2c_clk;
+	/* ioremapped registers cookie */
+	void __iomem *base;
+	/* pointer to register struct */
+	struct i2c_regs __iomem *regs;
+	/* irq number */
+	int irq;
+	/* xfer completion object */
+	struct completion msg_complete;
+	/* pointer to current message data */
+	u8 *msg_buf;
+	/* size of unsent data in the message buffer */
+	size_t msg_buf_remaining;
+	/* identifies read transfers */
+	int msg_read;
+	/* error code for completed message */
+	int msg_err;
+	/* current i2c bus clock rate */
+	u32 bus_clk_rate;
+};
+
+static void
+i2c_int_disable(struct axxia_i2c_dev *idev, u32 mask)
+{
+	u32 int_mask = readl(&idev->regs->mst_int_enable);
+	int_mask &= ~mask;
+	writel(int_mask, &idev->regs->mst_int_enable);
+}
+
+static void
+i2c_int_enable(struct axxia_i2c_dev *idev, u32 mask)
+{
+	u32 int_mask = readl(&idev->regs->mst_int_enable);
+	int_mask |= mask;
+	writel(int_mask, &idev->regs->mst_int_enable);
+}
+
+/**
+ * Convert nanoseconds to clock cycles for the given clock frequency.
+ */
+static u32
+ns_to_clk(u64 ns, u32 clk_mhz)
+{
+	return div64_u64(ns*clk_mhz, 1000ULL);
+}
+
+static int
+axxia_i2c_init(struct axxia_i2c_dev *idev)
+{
+	u32 divisor = clk_get_rate(idev->i2c_clk) / idev->bus_clk_rate;
+	u32 clk_mhz = clk_get_rate(idev->i2c_clk) / 1000000;
+	u32 t_setup;
+
+	dev_dbg(idev->dev, "rate=%uHz per_clk=%uMHz -> ratio=1:%u\n",
+		idev->bus_clk_rate, clk_mhz, divisor);
+
+	/* Enable Master Mode */
+	writel(0x1, &idev->regs->global_control);
+
+	/* SCL High Time */
+	writel(divisor/2, &idev->regs->scl_high_period);
+	/* SCL Low Time */
+	writel(divisor/2, &idev->regs->scl_low_period);
+
+	t_setup = (idev->bus_clk_rate <= 100000) ?
+		ns_to_clk(250, clk_mhz) : /* Standard mode tSU:DAT = 250 ns */
+		ns_to_clk(100, clk_mhz); /* Fast mode tSU:DAT = 100 ns */
+
+	/* SDA Setup Time */
+	writel(t_setup, &idev->regs->sda_setup_time);
+	/* SDA Hold Time, 5ns */
+	writel(ns_to_clk(5, clk_mhz), &idev->regs->sda_hold_time);
+	/* Filter <50ns spikes */
+	writel(ns_to_clk(50, clk_mhz), &idev->regs->spike_fltr_len);
+
+	/* Configure Time-Out Registers */
+
+	/* Divide by 32 (2^5) */
+	writel(5, &idev->regs->timer_clock_div);
+
+	/* Desired Time-Out = 250ms */
+	writel(ns_to_clk(25000000, clk_mhz), &idev->regs->wait_timer_control);
+
+	/* Interrupt enable */
+	writel(0x01, &idev->regs->interrupt_enable);
+
+	dev_dbg(idev->dev, "SDA_SETUP:        %08x\n",
+		readl(&idev->regs->sda_setup_time));
+	dev_dbg(idev->dev, "SDA_HOLD:         %08x\n",
+		readl(&idev->regs->sda_hold_time));
+	dev_dbg(idev->dev, "SPIKE_FILTER_LEN: %08x\n",
+		readl(&idev->regs->spike_fltr_len));
+	dev_dbg(idev->dev, "TIMER_DIV:        %08x\n",
+		readl(&idev->regs->timer_clock_div));
+	dev_dbg(idev->dev, "WAIT_TIMER:       %08x\n",
+		readl(&idev->regs->wait_timer_control));
+
+	return 0;
+}
+
+static int
+axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev)
+{
+	size_t rx_fifo_avail = readl(&idev->regs->mst_rx_fifo);
+	int bytes_to_transfer = min(rx_fifo_avail, idev->msg_buf_remaining);
+
+	idev->msg_buf_remaining -= bytes_to_transfer;
+
+	while (0 < bytes_to_transfer--)
+		*idev->msg_buf++ = readl(&idev->regs->mst_data);
+
+	return 0;
+}
+
+static int
+axxia_i2c_fill_tx_fifo(struct axxia_i2c_dev *idev)
+{
+	size_t tx_fifo_avail = TX_FIFO_SIZE - readl(&idev->regs->mst_tx_fifo);
+	int bytes_to_transfer = min(tx_fifo_avail, idev->msg_buf_remaining);
+
+	idev->msg_buf_remaining -= bytes_to_transfer;
+
+	while (0 < bytes_to_transfer--)
+		writel(*idev->msg_buf++, &idev->regs->mst_data);
+
+	return 0;
+}
+
+#ifdef DEBUG
+static char *
+status_str(u32 status)
+{
+	static char buf[128];
+
+	buf[0] = '\0';
+
+	if (status & MST_STATUS_RFL)
+		strcat(buf, "RFL ");
+	if (status & MST_STATUS_TFL)
+		strcat(buf, "TFL ");
+	if (status & MST_STATUS_SNS)
+		strcat(buf, "SNS ");
+	if (status & MST_STATUS_SS)
+		strcat(buf, "SS ");
+	if (status & MST_STATUS_SCC)
+		strcat(buf, "SCC ");
+	if (status & MST_STATUS_TSS)
+		strcat(buf, "TSS ");
+	if (status & MST_STATUS_AL)
+		strcat(buf, "AL ");
+	if (status & MST_STATUS_ND)
+		strcat(buf, "ND ");
+	if (status & MST_STATUS_NA)
+		strcat(buf, "NA ");
+	return buf;
+}
+#endif
+
+static irqreturn_t
+axxia_i2c_isr(int irq, void *_dev)
+{
+	struct axxia_i2c_dev *idev = _dev;
+	u32 status = readl(&idev->regs->mst_int_status);
+
+	/* Clear interrupt */
+	writel(0x01, &idev->regs->interrupt_status);
+
+	if (status & MST_STATUS_ERR) {
+		idev->msg_err = status & MST_STATUS_ERR;
+		i2c_int_disable(idev, ~0);
+		dev_err(idev->dev, "error %#x, rx=%u/%u tx=%u/%u\n",
+			idev->msg_err,
+			readl(&idev->regs->mst_rx_bytes_xfrd),
+			readl(&idev->regs->mst_rx_xfer),
+			readl(&idev->regs->mst_tx_bytes_xfrd),
+			readl(&idev->regs->mst_tx_xfer));
+		complete(&idev->msg_complete);
+		return IRQ_HANDLED;
+	}
+
+	/* Transfer done? */
+	if (status & (MST_STATUS_SNS | MST_STATUS_SS)) {
+		if (idev->msg_read && idev->msg_buf_remaining > 0)
+			axxia_i2c_empty_rx_fifo(idev);
+		WARN_ON(idev->msg_buf_remaining > 0);
+		i2c_int_disable(idev, ~0);
+		complete(&idev->msg_complete);
+	}
+
+	/* RX FIFO needs service? */
+	if (idev->msg_read && (status & MST_STATUS_RFL)) {
+		WARN_ON(idev->msg_buf_remaining == 0);
+		axxia_i2c_empty_rx_fifo(idev);
+	}
+
+	/* TX FIFO needs service? */
+	if (!idev->msg_read && (status & MST_STATUS_TFL)) {
+		if (idev->msg_buf_remaining)
+			axxia_i2c_fill_tx_fifo(idev);
+		else
+			i2c_int_disable(idev, MST_STATUS_TFL);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int
+axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg, int stop)
+{
+	u32 int_mask;
+	int ret;
+
+	dev_dbg(idev->dev, "xfer_msg: chip=%#x, buffer=[%02x %02x %02x %02x], len=%d, stop=%d\n",
+		msg->addr, msg->buf[0], msg->buf[1], msg->buf[2], msg->buf[3],
+		msg->len, stop);
+
+	if (msg->len == 0 || msg->len > 255)
+		return -EINVAL;
+
+	idev->msg_buf           = msg->buf;
+	idev->msg_buf_remaining = msg->len;
+	idev->msg_err           = 0;
+	idev->msg_read          = (msg->flags & I2C_M_RD);
+	INIT_COMPLETION(idev->msg_complete);
+
+	if (msg->flags & I2C_M_RD) {
+		/* TX 0 bytes */
+		writel(0, &idev->regs->mst_tx_xfer);
+		/* RX # bytes */
+		writel(msg->len, &idev->regs->mst_rx_xfer);
+		/* Chip address for write */
+		writel(CHIP_READ(msg->addr & 0xfe), &idev->regs->mst_addr_1);
+	} else {
+		/* TX # bytes */
+		writel(msg->len, &idev->regs->mst_tx_xfer);
+		/* RX 0 bytes */
+		writel(0, &idev->regs->mst_rx_xfer);
+		/* Chip address for write */
+		writel(CHIP_WRITE(msg->addr & 0xfe), &idev->regs->mst_addr_1);
+	}
+	writel(msg->addr >> 8, &idev->regs->mst_addr_2);
+
+	if (!(msg->flags & I2C_M_RD))
+		axxia_i2c_fill_tx_fifo(idev);
+
+	int_mask = MST_STATUS_ERR;
+	int_mask |= stop ? MST_STATUS_SS : MST_STATUS_SNS;
+	if (msg->flags & I2C_M_RD)
+		int_mask |= MST_STATUS_RFL;
+	else if (idev->msg_buf_remaining)
+		int_mask |= MST_STATUS_TFL;
+
+	/* Start manual mode */
+	writel(stop ? 0x9 : 0x8, &idev->regs->mst_command);
+
+	i2c_int_enable(idev, int_mask);
+
+	ret = wait_for_completion_timeout(&idev->msg_complete, I2C_TIMEOUT);
+
+	i2c_int_disable(idev, int_mask);
+
+	if (WARN_ON(ret == 0)) {
+		dev_warn(idev->dev, "i2c transfer timed out\n");
+		/* Reset i2c controller and re-initialize */
+		writel(0x01, &idev->regs->soft_reset);
+		while (readl(&idev->regs->soft_reset) & 1)
+			cpu_relax();
+		axxia_i2c_init(idev);
+		return -ETIMEDOUT;
+	}
+
+	dev_dbg(idev->dev, "transfer complete: %d %d %#x\n",
+		ret, completion_done(&idev->msg_complete), idev->msg_err);
+
+	if (likely(idev->msg_err == 0))
+		return 0;
+
+	return -EIO;
+}
+
+static int
+axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct axxia_i2c_dev *idev = i2c_get_adapdata(adap);
+	int i;
+	int ret = 0;
+
+	for (i = 0; ret == 0 && i < num; i++) {
+		int stop = (i == num-1);
+		ret = axxia_i2c_xfer_msg(idev, &msgs[i], stop);
+	}
+
+	return ret ?: i;
+}
+
+static u32
+axxia_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+
+}
+
+static const struct i2c_algorithm axxia_i2c_algo = {
+	.master_xfer	= axxia_i2c_xfer,
+	.functionality	= axxia_i2c_func,
+};
+
+static int __devinit
+axxia_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct axxia_i2c_dev *idev = NULL;
+	struct clk *i2c_clk = NULL;
+	void __iomem *base = NULL;
+	u32 port = 0;
+	int irq = 0;
+	int ret = 0;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		dev_err(&pdev->dev, "failed to iomap registers\n");
+		ret = -ENOMEM;
+		goto err_cleanup;
+	}
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (irq == 0) {
+		dev_err(&pdev->dev, "no irq property\n");
+		ret = -EINVAL;
+		goto err_cleanup;
+	}
+
+	i2c_clk = clk_get(&pdev->dev, "i2c");
+	if (IS_ERR(i2c_clk)) {
+		dev_err(&pdev->dev, "missing bus clock");
+		ret = PTR_ERR(i2c_clk);
+		goto err_cleanup;
+	}
+
+	idev = kzalloc(sizeof(struct axxia_i2c_dev), GFP_KERNEL);
+	if (!idev) {
+		ret = -ENOMEM;
+		goto err_cleanup;
+	}
+
+	idev->base         = base;
+	idev->regs         = (struct __iomem i2c_regs *) base;
+	idev->i2c_clk      = i2c_clk;
+	idev->dev          = &pdev->dev;
+	init_completion(&idev->msg_complete);
+
+	of_property_read_u32(np, "port", &port);
+
+	of_property_read_u32(np, "clock-frequency", &idev->bus_clk_rate);
+
+	if (idev->bus_clk_rate == 0)
+		idev->bus_clk_rate = 100000; /* default clock rate */
+
+	platform_set_drvdata(pdev, idev);
+
+	ret = axxia_i2c_init(idev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to initialize i2c controller");
+		goto err_cleanup;
+	}
+
+	ret = request_irq(irq, axxia_i2c_isr, 0, pdev->name, idev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request irq %i\n", idev->irq);
+		goto err_cleanup;
+	}
+	idev->irq = irq;
+
+	clk_enable(idev->i2c_clk);
+
+	i2c_set_adapdata(&idev->adapter, idev);
+	idev->adapter.owner = THIS_MODULE;
+	idev->adapter.class = I2C_CLASS_HWMON;
+	snprintf(idev->adapter.name, sizeof(idev->adapter.name),
+		 "Axxia I2C%u", port);
+	idev->adapter.algo = &axxia_i2c_algo;
+	idev->adapter.dev.parent = &pdev->dev;
+	idev->adapter.nr = pdev->id;
+	idev->adapter.dev.of_node = pdev->dev.of_node;
+
+	ret = i2c_add_numbered_adapter(&idev->adapter);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to add I2C adapter\n");
+		goto err_cleanup;
+	}
+
+	of_i2c_register_devices(&idev->adapter);
+
+	return 0;
+
+err_cleanup:
+	if (!IS_ERR_OR_NULL(i2c_clk))
+		clk_put(i2c_clk);
+	if (base)
+		iounmap(base);
+	if (idev && idev->irq)
+		free_irq(irq, idev);
+	kfree(idev);
+
+	return ret;
+}
+
+static int __devexit
+axxia_i2c_remove(struct platform_device *pdev)
+{
+	struct axxia_i2c_dev *idev = platform_get_drvdata(pdev);
+	i2c_del_adapter(&idev->adapter);
+	free_irq(idev->irq, idev);
+	clk_put(idev->i2c_clk);
+	iounmap(idev->base);
+	kfree(idev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int axxia_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return -EOPNOTSUPP;
+}
+
+static int axxia_i2c_resume(struct platform_device *pdev)
+{
+	return -EOPNOTSUPP;
+}
+#else
+#define axxia_i2c_suspend NULL
+#define axxia_i2c_resume NULL
+#endif
+
+/* Match table for of_platform binding */
+static const struct of_device_id axxia_i2c_of_match[] __devinitconst = {
+	{ .compatible = "lsi,api2c", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, axxia_i2c_of_match);
+
+static struct platform_driver axxia_i2c_driver = {
+	.probe   = axxia_i2c_probe,
+	.remove  = __devexit_p(axxia_i2c_remove),
+	.suspend = axxia_i2c_suspend,
+	.resume  = axxia_i2c_resume,
+	.driver  = {
+		.name  = "axxia-i2c",
+		.owner = THIS_MODULE,
+		.of_match_table = axxia_i2c_of_match,
+	},
+};
+
+module_platform_driver(axxia_i2c_driver);
+
+MODULE_DESCRIPTION("Axxia I2C Bus driver");
+MODULE_AUTHOR("Anders Berg <anders.berg at lsi.com>");
+MODULE_LICENSE("GPL v2");
-- 
1.8.4.3



More information about the linux-yocto mailing list