diff for duplicates of <42095A0B.2080400@mvista.com> diff --git a/a/1.txt b/N1/1.txt index 670e08f..d2c0c1d 100644 --- a/a/1.txt +++ b/N1/1.txt @@ -48,681 +48,3 @@ http://archives.andrew.net.au/lm-sensors/msg29405.html Signed-off-by: Mark A. Greer <mgreer@mvista.com> -- --------------- next part -------------- -diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig ---- a/drivers/i2c/busses/Kconfig 2005-02-08 17:28:52 -07:00 -+++ b/drivers/i2c/busses/Kconfig 2005-02-08 17:28:52 -07:00 -@@ -486,4 +486,14 @@ - This driver can also be built as a module. If so, the module - will be called i2c-pca-isa. - -+config I2C_MV64XXX -+ tristate "Marvell mv64xxx I2C Controller" -+ depends on I2C && MV64X60 && EXPERIMENTAL -+ help -+ If you say yes to this option, support will be included for the -+ built-in I2C interface on the Marvell 64xxx line of host bridges. -+ -+ This driver can also be built as a module. If so, the module -+ will be called i2c-mv64xxx. -+ - endmenu -diff -Nru a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile ---- a/drivers/i2c/busses/Makefile 2005-02-08 17:28:52 -07:00 -+++ b/drivers/i2c/busses/Makefile 2005-02-08 17:28:52 -07:00 -@@ -21,6 +21,7 @@ - obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o - obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o - obj-$(CONFIG_I2C_MPC) += i2c-mpc.o -+obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o - obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o - obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o - obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o -diff -Nru a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c ---- /dev/null Wed Dec 31 16:00:00 196900 -+++ b/drivers/i2c/busses/i2c-mv64xxx.c 2005-02-08 17:28:52 -07:00 -@@ -0,0 +1,606 @@ -+/* -+ * drivers/i2c/busses/i2c-mv64xxx.c -+ * -+ * Driver for the i2c controller on the Marvell line of host bridges for MIPS -+ * and PPC (e.g, gt642[46]0, mv643[46]0, mv644[46]0). -+ * -+ * Author: Mark A. Greer <mgreer@mvista.com> -+ * -+ * 2005 (c) MontaVista, Software, Inc. 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/spinlock.h> -+#include <linux/i2c.h> -+#include <linux/interrupt.h> -+#include <linux/mv643xx.h> -+#include <asm/io.h> -+ -+/* Register defines */ -+#define MV64XXX_I2C_REG_SLAVE_ADDR 0x00 -+#define MV64XXX_I2C_REG_DATA 0x04 -+#define MV64XXX_I2C_REG_CONTROL 0x08 -+#define MV64XXX_I2C_REG_STATUS 0x0c -+#define MV64XXX_I2C_REG_BAUD 0x0c -+#define MV64XXX_I2C_REG_EXT_SLAVE_ADDR 0x10 -+#define MV64XXX_I2C_REG_SOFT_RESET 0x1c -+ -+#define MV64XXX_I2C_REG_CONTROL_ACK 0x00000004 -+#define MV64XXX_I2C_REG_CONTROL_IFLG 0x00000008 -+#define MV64XXX_I2C_REG_CONTROL_STOP 0x00000010 -+#define MV64XXX_I2C_REG_CONTROL_START 0x00000020 -+#define MV64XXX_I2C_REG_CONTROL_TWSIEN 0x00000040 -+#define MV64XXX_I2C_REG_CONTROL_INTEN 0x00000080 -+ -+/* Ctlr status values */ -+#define MV64XXX_I2C_STATUS_BUS_ERR 0x00 -+#define MV64XXX_I2C_STATUS_MAST_START 0x08 -+#define MV64XXX_I2C_STATUS_MAST_REPEAT_START 0x10 -+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK 0x18 -+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK 0x20 -+#define MV64XXX_I2C_STATUS_MAST_WR_ACK 0x28 -+#define MV64XXX_I2C_STATUS_MAST_WR_NO_ACK 0x30 -+#define MV64XXX_I2C_STATUS_MAST_LOST_ARB 0x38 -+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK 0x40 -+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK 0x48 -+#define MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK 0x50 -+#define MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK 0x58 -+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK 0xd0 -+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK 0xd8 -+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK 0xe0 -+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8 -+#define MV64XXX_I2C_STATUS_NO_STATUS 0xf8 -+ -+/* Driver states */ -+enum { -+ MV64XXX_I2C_STATE_INVALID, -+ MV64XXX_I2C_STATE_IDLE, -+ MV64XXX_I2C_STATE_WAITING_FOR_START_COND, -+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK, -+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK, -+ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK, -+ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA, -+ MV64XXX_I2C_STATE_ABORTING, -+}; -+ -+/* Driver actions */ -+enum { -+ MV64XXX_I2C_ACTION_INVALID, -+ MV64XXX_I2C_ACTION_CONTINUE, -+ MV64XXX_I2C_ACTION_SEND_START, -+ MV64XXX_I2C_ACTION_SEND_ADDR_1, -+ MV64XXX_I2C_ACTION_SEND_ADDR_2, -+ MV64XXX_I2C_ACTION_SEND_DATA, -+ MV64XXX_I2C_ACTION_RCV_DATA, -+ MV64XXX_I2C_ACTION_RCV_DATA_STOP, -+ MV64XXX_I2C_ACTION_SEND_STOP, -+}; -+ -+struct mv64xxx_i2c_data { -+ int irq; -+ u32 state; -+ u32 action; -+ u32 cntl_bits; -+ void __iomem *reg_base; -+ u32 reg_base_p; -+ u32 addr1; -+ u32 addr2; -+ u32 bytes_left; -+ u32 byte_posn; -+ u32 block; -+ int rc; -+ u32 freq_m; -+ u32 freq_n; -+ wait_queue_head_t waitq; -+ spinlock_t lock; -+ struct i2c_msg *msg; -+ struct i2c_adapter adapter; -+}; -+ -+/* -+ ***************************************************************************** -+ * -+ * Finite State Machine & Interrupt Routines -+ * -+ ***************************************************************************** -+ */ -+static void -+mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) -+{ -+ /* -+ * If state is idle, then this is likely the remnants of an old -+ * operation that driver has given up on or the user has killed. -+ * If so, issue the stop condition and go to idle. -+ */ -+ if (drv_data->state = MV64XXX_I2C_STATE_IDLE) { -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; -+ return; -+ } -+ -+ if (drv_data->state = MV64XXX_I2C_STATE_ABORTING) { -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; -+ drv_data->state = MV64XXX_I2C_STATE_IDLE; -+ return; -+ } -+ -+ /* The status from the ctlr [mostly] tells us what to do next */ -+ switch (status) { -+ /* Start condition interrupt */ -+ case MV64XXX_I2C_STATUS_MAST_START: /* 0x08 */ -+ case MV64XXX_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */ -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1; -+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK; -+ break; -+ -+ /* Performing a write */ -+ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */ -+ if (drv_data->msg->flags & I2C_M_TEN) { -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2; -+ drv_data->state + MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK; -+ break; -+ } -+ /* FALLTHRU */ -+ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */ -+ case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */ -+ if (drv_data->bytes_left > 0) { -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; -+ drv_data->state + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK; -+ drv_data->bytes_left--; -+ } else { -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; -+ drv_data->state = MV64XXX_I2C_STATE_IDLE; -+ } -+ break; -+ -+ /* Performing a read */ -+ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */ -+ if (drv_data->msg->flags & I2C_M_TEN) { -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2; -+ drv_data->state + MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK; -+ break; -+ } -+ /* FALLTHRU */ -+ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */ -+ if (drv_data->bytes_left = 0) { -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; -+ drv_data->state = MV64XXX_I2C_STATE_IDLE; -+ break; -+ } -+ /* FALLTHRU */ -+ case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */ -+ if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK) -+ drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; -+ else { -+ drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA; -+ drv_data->bytes_left--; -+ } -+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA; -+ -+ if (drv_data->bytes_left = 1) -+ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK; -+ break; -+ -+ case MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */ -+ drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP; -+ drv_data->state = MV64XXX_I2C_STATE_IDLE; -+ break; -+ -+ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */ -+ case MV64XXX_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */ -+ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */ -+ /* Doesn't seem to be a device at other end */ -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; -+ drv_data->state = MV64XXX_I2C_STATE_IDLE; -+ drv_data->rc = -ENODEV; -+ break; -+ -+ default: -+ dev_err(&drv_data->adapter.dev, -+ "mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, " -+ "status: 0x%x, addr: 0x%x, flags: 0x%x\n", -+ drv_data->state, status, drv_data->msg->addr, -+ drv_data->msg->flags); -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; -+ drv_data->state = MV64XXX_I2C_STATE_IDLE; -+ drv_data->rc = -EIO; -+ } -+ -+ return; -+} -+ -+static void -+mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) -+{ -+ switch(drv_data->action) { -+ case MV64XXX_I2C_ACTION_CONTINUE: -+ writel(drv_data->cntl_bits, -+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); -+ break; -+ -+ case MV64XXX_I2C_ACTION_SEND_START: -+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, -+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); -+ break; -+ -+ case MV64XXX_I2C_ACTION_SEND_ADDR_1: -+ writel(drv_data->addr1, -+ drv_data->reg_base + MV64XXX_I2C_REG_DATA); -+ writel(drv_data->cntl_bits, -+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); -+ break; -+ -+ case MV64XXX_I2C_ACTION_SEND_ADDR_2: -+ writel(drv_data->addr2, -+ drv_data->reg_base + MV64XXX_I2C_REG_DATA); -+ writel(drv_data->cntl_bits, -+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); -+ break; -+ -+ case MV64XXX_I2C_ACTION_SEND_DATA: -+ writel(drv_data->msg->buf[drv_data->byte_posn++], -+ drv_data->reg_base + MV64XXX_I2C_REG_DATA); -+ writel(drv_data->cntl_bits, -+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); -+ break; -+ -+ case MV64XXX_I2C_ACTION_RCV_DATA: -+ drv_data->msg->buf[drv_data->byte_posn++] + readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA); -+ writel(drv_data->cntl_bits, -+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); -+ break; -+ -+ case MV64XXX_I2C_ACTION_RCV_DATA_STOP: -+ drv_data->msg->buf[drv_data->byte_posn++] + readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA); -+ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; -+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, -+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); -+ drv_data->block = 0; -+ wake_up_interruptible(&drv_data->waitq); -+ break; -+ -+ case MV64XXX_I2C_ACTION_INVALID: -+ default: -+ dev_err(&drv_data->adapter.dev, -+ "mv64xxx_i2c_do_action: Invalid action: %d\n", -+ drv_data->action); -+ drv_data->rc = -EIO; -+ /* FALLTHRU */ -+ case MV64XXX_I2C_ACTION_SEND_STOP: -+ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; -+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, -+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); -+ drv_data->block = 0; -+ wake_up_interruptible(&drv_data->waitq); -+ break; -+ } -+ -+ return; -+} -+ -+static int -+mv64xxx_i2c_intr(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct mv64xxx_i2c_data *drv_data = dev_id; -+ u32 status; -+ long flags; -+ int rc = IRQ_NONE; -+ -+ spin_lock_irqsave(&drv_data->lock, flags); -+ while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) & -+ MV64XXX_I2C_REG_CONTROL_IFLG) { -+ status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS); -+ mv64xxx_i2c_fsm(drv_data, status); -+ mv64xxx_i2c_do_action(drv_data); -+ rc = IRQ_HANDLED; -+ } -+ spin_unlock_irqrestore(&drv_data->lock, flags); -+ -+ return rc; -+} -+ -+/* -+ ***************************************************************************** -+ * -+ * I2C Msg Execution Routines -+ * -+ ***************************************************************************** -+ */ -+static void -+mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, -+ struct i2c_msg *msg) -+{ -+ u32 dir = 0; -+ -+ drv_data->msg = msg; -+ drv_data->byte_posn = 0; -+ drv_data->bytes_left = msg->len; -+ drv_data->rc = 0; -+ drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK | -+ MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN; -+ -+ if (msg->flags & I2C_M_RD) -+ dir = 1; -+ -+ if (msg->flags & I2C_M_REV_DIR_ADDR) -+ dir ^= 1; -+ -+ if (msg->flags & I2C_M_TEN) { -+ drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir; -+ drv_data->addr2 = (u32)msg->addr & 0xff; -+ } else { -+ drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir; -+ drv_data->addr2 = 0; -+ } -+ -+ return; -+} -+ -+static void -+mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) -+{ -+ long flags, time_left; -+ char abort = 0; -+ -+ time_left = wait_event_interruptible_timeout(drv_data->waitq, -+ !drv_data->block, msecs_to_jiffies(drv_data->adapter.timeout)); -+ -+ spin_lock_irqsave(&drv_data->lock, flags); -+ if (!time_left) { /* Timed out */ -+ drv_data->rc = -ETIMEDOUT; -+ abort = 1; -+ } else if (time_left < 0) { /* Interrupted/Error */ -+ drv_data->rc = time_left; /* errno value */ -+ abort = 1; -+ } -+ -+ if (abort && drv_data->block) { -+ drv_data->state = MV64XXX_I2C_STATE_ABORTING; -+ spin_unlock_irqrestore(&drv_data->lock, flags); -+ -+ time_left = wait_event_timeout(drv_data->waitq, -+ !drv_data->block, -+ msecs_to_jiffies(drv_data->adapter.timeout)); -+ -+ if (time_left <= 0) { -+ drv_data->state = MV64XXX_I2C_STATE_IDLE; -+ dev_err(&drv_data->adapter.dev, -+ "mv64xxx: I2C bus locked\n"); -+ } -+ } else -+ spin_unlock_irqrestore(&drv_data->lock, flags); -+ -+ return; -+} -+ -+static int -+mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) -+{ -+ long flags; -+ -+ spin_lock_irqsave(&drv_data->lock, flags); -+ mv64xxx_i2c_prepare_for_io(drv_data, msg); -+ -+ if (unlikely(msg->flags & I2C_M_NOSTART)) { /* Skip start/addr phases */ -+ if (drv_data->msg->flags & I2C_M_RD) { -+ /* No action to do, wait for slave to send a byte */ -+ drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; -+ drv_data->state + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA; -+ } else { -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; -+ drv_data->state + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK; -+ drv_data->bytes_left--; -+ } -+ } else { -+ drv_data->action = MV64XXX_I2C_ACTION_SEND_START; -+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; -+ } -+ -+ drv_data->block = 1; -+ mv64xxx_i2c_do_action(drv_data); -+ spin_unlock_irqrestore(&drv_data->lock, flags); -+ -+ mv64xxx_i2c_wait_for_completion(drv_data); -+ return drv_data->rc; -+} -+ -+/* -+ ***************************************************************************** -+ * -+ * I2C Core Support Routines (Interface to higher level I2C code) -+ * -+ ***************************************************************************** -+ */ -+static u32 -+mv64xxx_i2c_functionality(struct i2c_adapter *adap) -+{ -+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; -+} -+ -+static int -+mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) -+{ -+ struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); -+ int i, rc = 0; -+ -+ for (i=0; i<num; i++) -+ if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) != 0) -+ break; -+ -+ return rc; -+} -+ -+static struct i2c_algorithm mv64xxx_i2c_algo = { -+ .name = MV64XXX_I2C_CTLR_NAME " algorithm", -+ .id = I2C_ALGO_MV64XXX, -+ .master_xfer = mv64xxx_i2c_xfer, -+ .functionality = mv64xxx_i2c_functionality, -+}; -+ -+/* -+ ***************************************************************************** -+ * -+ * Driver Interface & Early Init Routines -+ * -+ ***************************************************************************** -+ */ -+static void __init -+mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data) -+{ -+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET); -+ writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)), -+ drv_data->reg_base + MV64XXX_I2C_REG_BAUD); -+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR); -+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR); -+ writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP, -+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); -+ drv_data->state = MV64XXX_I2C_STATE_IDLE; -+ return; -+} -+ -+static int __init -+mv64xxx_i2c_map_regs(struct platform_device *pd, -+ struct mv64xxx_i2c_data *drv_data) -+{ -+ struct resource *r; -+ -+ if ((r = platform_get_resource(pd, IORESOURCE_MEM, 0)) && -+ request_mem_region(r->start, MV64XXX_I2C_REG_BLOCK_SIZE, -+ drv_data->adapter.name)) { -+ -+ drv_data->reg_base = ioremap(r->start, -+ MV64XXX_I2C_REG_BLOCK_SIZE); -+ drv_data->reg_base_p = r->start; -+ } else -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+static void __exit -+mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data) -+{ -+ if (drv_data->reg_base) { -+ iounmap(drv_data->reg_base); -+ release_mem_region(drv_data->reg_base_p, -+ MV64XXX_I2C_REG_BLOCK_SIZE); -+ } -+ -+ drv_data->reg_base = NULL; -+ drv_data->reg_base_p = 0; -+ return; -+} -+ -+static int __init -+mv64xxx_i2c_probe(struct device *dev) -+{ -+ struct platform_device *pd = to_platform_device(dev); -+ struct mv64xxx_i2c_data *drv_data; -+ struct mv64xxx_i2c_pdata *pdata = dev->platform_data; -+ int rc; -+ -+ if ((pd->id != 0) || !pdata) -+ return -ENODEV; -+ -+ drv_data = kmalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); -+ -+ if (!drv_data) -+ return -ENOMEM; -+ -+ memset(drv_data, 0, sizeof(struct mv64xxx_i2c_data)); -+ -+ if (mv64xxx_i2c_map_regs(pd, drv_data)) { -+ rc = -ENODEV; -+ goto exit_kfree; -+ } -+ -+ strncpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", -+ I2C_NAME_SIZE); -+ -+ init_waitqueue_head(&drv_data->waitq); -+ spin_lock_init(&drv_data->lock); -+ -+ drv_data->freq_m = pdata->freq_m; -+ drv_data->freq_n = pdata->freq_n; -+ drv_data->irq = platform_get_irq(pd, 0); -+ drv_data->adapter.id = I2C_ALGO_MV64XXX | I2C_HW_MV64XXX; -+ drv_data->adapter.algo = &mv64xxx_i2c_algo; -+ drv_data->adapter.timeout = pdata->timeout; -+ drv_data->adapter.retries = pdata->retries; -+ dev_set_drvdata(dev, drv_data); -+ i2c_set_adapdata(&drv_data->adapter, drv_data); -+ -+ if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0, -+ MV64XXX_I2C_CTLR_NAME, drv_data)) { -+ -+ dev_err(dev, "mv64xxx: Can't register intr handler " -+ "irq: %d\n", drv_data->irq); -+ rc = -EINVAL; -+ goto exit_unmap_regs; -+ } else if ((rc = i2c_add_adapter(&drv_data->adapter)) != 0) { -+ dev_err(dev, "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); -+ goto exit_free_irq; -+ } -+ -+ mv64xxx_i2c_hw_init(drv_data); -+ -+ return 0; -+ -+ exit_free_irq: -+ free_irq(drv_data->irq, drv_data); -+ exit_unmap_regs: -+ mv64xxx_i2c_unmap_regs(drv_data); -+ exit_kfree: -+ kfree(drv_data); -+ return rc; -+} -+ -+static int __exit -+mv64xxx_i2c_remove(struct device *dev) -+{ -+ struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev); -+ int rc; -+ -+ rc = i2c_del_adapter(&drv_data->adapter); -+ free_irq(drv_data->irq, drv_data); -+ mv64xxx_i2c_unmap_regs(drv_data); -+ kfree(drv_data); -+ -+ return rc; -+} -+ -+static struct device_driver mv64xxx_i2c_driver = { -+ .name = MV64XXX_I2C_CTLR_NAME, -+ .bus = &platform_bus_type, -+ .probe = mv64xxx_i2c_probe, -+ .remove = mv64xxx_i2c_remove, -+}; -+ -+static int __init -+mv64xxx_i2c_init(void) -+{ -+ return driver_register(&mv64xxx_i2c_driver); -+} -+ -+static void __exit -+mv64xxx_i2c_exit(void) -+{ -+ driver_unregister(&mv64xxx_i2c_driver); -+ return; -+} -+ -+module_init(mv64xxx_i2c_init); -+module_exit(mv64xxx_i2c_exit); -+ -+MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>"); -+MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver"); -+MODULE_LICENSE("GPL"); -diff -Nru a/include/linux/i2c-id.h b/include/linux/i2c-id.h ---- a/include/linux/i2c-id.h 2005-02-08 17:28:52 -07:00 -+++ b/include/linux/i2c-id.h 2005-02-08 17:28:52 -07:00 -@@ -311,4 +311,7 @@ - /* --- MCP107 adapter */ - #define I2C_HW_MPC107 0x00 - -+/* --- Marvell mv64xxx i2c adapter */ -+#define I2C_HW_MV64XXX 0x00 -+ - #endif /* LINUX_I2C_ID_H */ -diff -Nru a/include/linux/mv643xx.h b/include/linux/mv643xx.h ---- a/include/linux/mv643xx.h 2005-02-08 17:28:52 -07:00 -+++ b/include/linux/mv643xx.h 2005-02-08 17:28:52 -07:00 -@@ -977,12 +977,9 @@ - /* I2C Registers */ - /****************************************/ - --#define MV64340_I2C_SLAVE_ADDR 0xc000 --#define MV64340_I2C_EXTENDED_SLAVE_ADDR 0xc010 --#define MV64340_I2C_DATA 0xc004 --#define MV64340_I2C_CONTROL 0xc008 --#define MV64340_I2C_STATUS_BAUDE_RATE 0xc00C --#define MV64340_I2C_SOFT_RESET 0xc01c -+#define MV64XXX_I2C_CTLR_NAME "mv64xxx i2c" -+#define MV64XXX_I2C_OFFSET 0xc000 -+#define MV64XXX_I2C_REG_BLOCK_SIZE 0x0020 - - /****************************************/ - /* GPP Interface Registers */ -@@ -1083,6 +1080,14 @@ - u8 brg_can_tune; - u8 brg_clk_src; - u32 brg_clk_freq; -+}; -+ -+/* i2c Platform Device, Driver Data */ -+struct mv64xxx_i2c_pdata { -+ u32 freq_m; -+ u32 freq_n; -+ u32 timeout; /* In milliseconds */ -+ u32 retries; - }; - - #endif /* __ASM_MV64340_H */ diff --git a/N1/2.hdr b/N1/2.hdr new file mode 100644 index 0000000..c5b4288 --- /dev/null +++ b/N1/2.hdr @@ -0,0 +1,5 @@ +Content-Type: text/plain; + name="i2c_8.patch" +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; + filename="i2c_8.patch" diff --git a/N1/2.txt b/N1/2.txt new file mode 100644 index 0000000..d144a0d --- /dev/null +++ b/N1/2.txt @@ -0,0 +1,684 @@ +diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +--- a/drivers/i2c/busses/Kconfig 2005-02-08 17:28:52 -07:00 ++++ b/drivers/i2c/busses/Kconfig 2005-02-08 17:28:52 -07:00 +@@ -486,4 +486,14 @@ + This driver can also be built as a module. If so, the module + will be called i2c-pca-isa. + ++config I2C_MV64XXX ++ tristate "Marvell mv64xxx I2C Controller" ++ depends on I2C && MV64X60 && EXPERIMENTAL ++ help ++ If you say yes to this option, support will be included for the ++ built-in I2C interface on the Marvell 64xxx line of host bridges. ++ ++ This driver can also be built as a module. If so, the module ++ will be called i2c-mv64xxx. ++ + endmenu +diff -Nru a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +--- a/drivers/i2c/busses/Makefile 2005-02-08 17:28:52 -07:00 ++++ b/drivers/i2c/busses/Makefile 2005-02-08 17:28:52 -07:00 +@@ -21,6 +21,7 @@ + obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o + obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o + obj-$(CONFIG_I2C_MPC) += i2c-mpc.o ++obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o + obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o + obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o + obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o +diff -Nru a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c +--- /dev/null Wed Dec 31 16:00:00 196900 ++++ b/drivers/i2c/busses/i2c-mv64xxx.c 2005-02-08 17:28:52 -07:00 +@@ -0,0 +1,606 @@ ++/* ++ * drivers/i2c/busses/i2c-mv64xxx.c ++ * ++ * Driver for the i2c controller on the Marvell line of host bridges for MIPS ++ * and PPC (e.g, gt642[46]0, mv643[46]0, mv644[46]0). ++ * ++ * Author: Mark A. Greer <mgreer@mvista.com> ++ * ++ * 2005 (c) MontaVista, Software, Inc. 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/spinlock.h> ++#include <linux/i2c.h> ++#include <linux/interrupt.h> ++#include <linux/mv643xx.h> ++#include <asm/io.h> ++ ++/* Register defines */ ++#define MV64XXX_I2C_REG_SLAVE_ADDR 0x00 ++#define MV64XXX_I2C_REG_DATA 0x04 ++#define MV64XXX_I2C_REG_CONTROL 0x08 ++#define MV64XXX_I2C_REG_STATUS 0x0c ++#define MV64XXX_I2C_REG_BAUD 0x0c ++#define MV64XXX_I2C_REG_EXT_SLAVE_ADDR 0x10 ++#define MV64XXX_I2C_REG_SOFT_RESET 0x1c ++ ++#define MV64XXX_I2C_REG_CONTROL_ACK 0x00000004 ++#define MV64XXX_I2C_REG_CONTROL_IFLG 0x00000008 ++#define MV64XXX_I2C_REG_CONTROL_STOP 0x00000010 ++#define MV64XXX_I2C_REG_CONTROL_START 0x00000020 ++#define MV64XXX_I2C_REG_CONTROL_TWSIEN 0x00000040 ++#define MV64XXX_I2C_REG_CONTROL_INTEN 0x00000080 ++ ++/* Ctlr status values */ ++#define MV64XXX_I2C_STATUS_BUS_ERR 0x00 ++#define MV64XXX_I2C_STATUS_MAST_START 0x08 ++#define MV64XXX_I2C_STATUS_MAST_REPEAT_START 0x10 ++#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK 0x18 ++#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK 0x20 ++#define MV64XXX_I2C_STATUS_MAST_WR_ACK 0x28 ++#define MV64XXX_I2C_STATUS_MAST_WR_NO_ACK 0x30 ++#define MV64XXX_I2C_STATUS_MAST_LOST_ARB 0x38 ++#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK 0x40 ++#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK 0x48 ++#define MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK 0x50 ++#define MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK 0x58 ++#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK 0xd0 ++#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK 0xd8 ++#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK 0xe0 ++#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8 ++#define MV64XXX_I2C_STATUS_NO_STATUS 0xf8 ++ ++/* Driver states */ ++enum { ++ MV64XXX_I2C_STATE_INVALID, ++ MV64XXX_I2C_STATE_IDLE, ++ MV64XXX_I2C_STATE_WAITING_FOR_START_COND, ++ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK, ++ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK, ++ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK, ++ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA, ++ MV64XXX_I2C_STATE_ABORTING, ++}; ++ ++/* Driver actions */ ++enum { ++ MV64XXX_I2C_ACTION_INVALID, ++ MV64XXX_I2C_ACTION_CONTINUE, ++ MV64XXX_I2C_ACTION_SEND_START, ++ MV64XXX_I2C_ACTION_SEND_ADDR_1, ++ MV64XXX_I2C_ACTION_SEND_ADDR_2, ++ MV64XXX_I2C_ACTION_SEND_DATA, ++ MV64XXX_I2C_ACTION_RCV_DATA, ++ MV64XXX_I2C_ACTION_RCV_DATA_STOP, ++ MV64XXX_I2C_ACTION_SEND_STOP, ++}; ++ ++struct mv64xxx_i2c_data { ++ int irq; ++ u32 state; ++ u32 action; ++ u32 cntl_bits; ++ void __iomem *reg_base; ++ u32 reg_base_p; ++ u32 addr1; ++ u32 addr2; ++ u32 bytes_left; ++ u32 byte_posn; ++ u32 block; ++ int rc; ++ u32 freq_m; ++ u32 freq_n; ++ wait_queue_head_t waitq; ++ spinlock_t lock; ++ struct i2c_msg *msg; ++ struct i2c_adapter adapter; ++}; ++ ++/* ++ ***************************************************************************** ++ * ++ * Finite State Machine & Interrupt Routines ++ * ++ ***************************************************************************** ++ */ ++static void ++mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) ++{ ++ /* ++ * If state is idle, then this is likely the remnants of an old ++ * operation that driver has given up on or the user has killed. ++ * If so, issue the stop condition and go to idle. ++ */ ++ if (drv_data->state == MV64XXX_I2C_STATE_IDLE) { ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; ++ return; ++ } ++ ++ if (drv_data->state == MV64XXX_I2C_STATE_ABORTING) { ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; ++ drv_data->state = MV64XXX_I2C_STATE_IDLE; ++ return; ++ } ++ ++ /* The status from the ctlr [mostly] tells us what to do next */ ++ switch (status) { ++ /* Start condition interrupt */ ++ case MV64XXX_I2C_STATUS_MAST_START: /* 0x08 */ ++ case MV64XXX_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */ ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1; ++ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK; ++ break; ++ ++ /* Performing a write */ ++ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */ ++ if (drv_data->msg->flags & I2C_M_TEN) { ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2; ++ drv_data->state = ++ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK; ++ break; ++ } ++ /* FALLTHRU */ ++ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */ ++ case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */ ++ if (drv_data->bytes_left > 0) { ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; ++ drv_data->state = ++ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK; ++ drv_data->bytes_left--; ++ } else { ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; ++ drv_data->state = MV64XXX_I2C_STATE_IDLE; ++ } ++ break; ++ ++ /* Performing a read */ ++ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */ ++ if (drv_data->msg->flags & I2C_M_TEN) { ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2; ++ drv_data->state = ++ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK; ++ break; ++ } ++ /* FALLTHRU */ ++ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */ ++ if (drv_data->bytes_left == 0) { ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; ++ drv_data->state = MV64XXX_I2C_STATE_IDLE; ++ break; ++ } ++ /* FALLTHRU */ ++ case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */ ++ if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK) ++ drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; ++ else { ++ drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA; ++ drv_data->bytes_left--; ++ } ++ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA; ++ ++ if (drv_data->bytes_left == 1) ++ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK; ++ break; ++ ++ case MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */ ++ drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP; ++ drv_data->state = MV64XXX_I2C_STATE_IDLE; ++ break; ++ ++ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */ ++ case MV64XXX_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */ ++ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */ ++ /* Doesn't seem to be a device at other end */ ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; ++ drv_data->state = MV64XXX_I2C_STATE_IDLE; ++ drv_data->rc = -ENODEV; ++ break; ++ ++ default: ++ dev_err(&drv_data->adapter.dev, ++ "mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, " ++ "status: 0x%x, addr: 0x%x, flags: 0x%x\n", ++ drv_data->state, status, drv_data->msg->addr, ++ drv_data->msg->flags); ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; ++ drv_data->state = MV64XXX_I2C_STATE_IDLE; ++ drv_data->rc = -EIO; ++ } ++ ++ return; ++} ++ ++static void ++mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) ++{ ++ switch(drv_data->action) { ++ case MV64XXX_I2C_ACTION_CONTINUE: ++ writel(drv_data->cntl_bits, ++ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); ++ break; ++ ++ case MV64XXX_I2C_ACTION_SEND_START: ++ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, ++ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); ++ break; ++ ++ case MV64XXX_I2C_ACTION_SEND_ADDR_1: ++ writel(drv_data->addr1, ++ drv_data->reg_base + MV64XXX_I2C_REG_DATA); ++ writel(drv_data->cntl_bits, ++ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); ++ break; ++ ++ case MV64XXX_I2C_ACTION_SEND_ADDR_2: ++ writel(drv_data->addr2, ++ drv_data->reg_base + MV64XXX_I2C_REG_DATA); ++ writel(drv_data->cntl_bits, ++ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); ++ break; ++ ++ case MV64XXX_I2C_ACTION_SEND_DATA: ++ writel(drv_data->msg->buf[drv_data->byte_posn++], ++ drv_data->reg_base + MV64XXX_I2C_REG_DATA); ++ writel(drv_data->cntl_bits, ++ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); ++ break; ++ ++ case MV64XXX_I2C_ACTION_RCV_DATA: ++ drv_data->msg->buf[drv_data->byte_posn++] = ++ readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA); ++ writel(drv_data->cntl_bits, ++ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); ++ break; ++ ++ case MV64XXX_I2C_ACTION_RCV_DATA_STOP: ++ drv_data->msg->buf[drv_data->byte_posn++] = ++ readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA); ++ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; ++ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, ++ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); ++ drv_data->block = 0; ++ wake_up_interruptible(&drv_data->waitq); ++ break; ++ ++ case MV64XXX_I2C_ACTION_INVALID: ++ default: ++ dev_err(&drv_data->adapter.dev, ++ "mv64xxx_i2c_do_action: Invalid action: %d\n", ++ drv_data->action); ++ drv_data->rc = -EIO; ++ /* FALLTHRU */ ++ case MV64XXX_I2C_ACTION_SEND_STOP: ++ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; ++ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, ++ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); ++ drv_data->block = 0; ++ wake_up_interruptible(&drv_data->waitq); ++ break; ++ } ++ ++ return; ++} ++ ++static int ++mv64xxx_i2c_intr(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct mv64xxx_i2c_data *drv_data = dev_id; ++ u32 status; ++ long flags; ++ int rc = IRQ_NONE; ++ ++ spin_lock_irqsave(&drv_data->lock, flags); ++ while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) & ++ MV64XXX_I2C_REG_CONTROL_IFLG) { ++ status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS); ++ mv64xxx_i2c_fsm(drv_data, status); ++ mv64xxx_i2c_do_action(drv_data); ++ rc = IRQ_HANDLED; ++ } ++ spin_unlock_irqrestore(&drv_data->lock, flags); ++ ++ return rc; ++} ++ ++/* ++ ***************************************************************************** ++ * ++ * I2C Msg Execution Routines ++ * ++ ***************************************************************************** ++ */ ++static void ++mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, ++ struct i2c_msg *msg) ++{ ++ u32 dir = 0; ++ ++ drv_data->msg = msg; ++ drv_data->byte_posn = 0; ++ drv_data->bytes_left = msg->len; ++ drv_data->rc = 0; ++ drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK | ++ MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN; ++ ++ if (msg->flags & I2C_M_RD) ++ dir = 1; ++ ++ if (msg->flags & I2C_M_REV_DIR_ADDR) ++ dir ^= 1; ++ ++ if (msg->flags & I2C_M_TEN) { ++ drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir; ++ drv_data->addr2 = (u32)msg->addr & 0xff; ++ } else { ++ drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir; ++ drv_data->addr2 = 0; ++ } ++ ++ return; ++} ++ ++static void ++mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) ++{ ++ long flags, time_left; ++ char abort = 0; ++ ++ time_left = wait_event_interruptible_timeout(drv_data->waitq, ++ !drv_data->block, msecs_to_jiffies(drv_data->adapter.timeout)); ++ ++ spin_lock_irqsave(&drv_data->lock, flags); ++ if (!time_left) { /* Timed out */ ++ drv_data->rc = -ETIMEDOUT; ++ abort = 1; ++ } else if (time_left < 0) { /* Interrupted/Error */ ++ drv_data->rc = time_left; /* errno value */ ++ abort = 1; ++ } ++ ++ if (abort && drv_data->block) { ++ drv_data->state = MV64XXX_I2C_STATE_ABORTING; ++ spin_unlock_irqrestore(&drv_data->lock, flags); ++ ++ time_left = wait_event_timeout(drv_data->waitq, ++ !drv_data->block, ++ msecs_to_jiffies(drv_data->adapter.timeout)); ++ ++ if (time_left <= 0) { ++ drv_data->state = MV64XXX_I2C_STATE_IDLE; ++ dev_err(&drv_data->adapter.dev, ++ "mv64xxx: I2C bus locked\n"); ++ } ++ } else ++ spin_unlock_irqrestore(&drv_data->lock, flags); ++ ++ return; ++} ++ ++static int ++mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) ++{ ++ long flags; ++ ++ spin_lock_irqsave(&drv_data->lock, flags); ++ mv64xxx_i2c_prepare_for_io(drv_data, msg); ++ ++ if (unlikely(msg->flags & I2C_M_NOSTART)) { /* Skip start/addr phases */ ++ if (drv_data->msg->flags & I2C_M_RD) { ++ /* No action to do, wait for slave to send a byte */ ++ drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; ++ drv_data->state = ++ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA; ++ } else { ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; ++ drv_data->state = ++ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK; ++ drv_data->bytes_left--; ++ } ++ } else { ++ drv_data->action = MV64XXX_I2C_ACTION_SEND_START; ++ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; ++ } ++ ++ drv_data->block = 1; ++ mv64xxx_i2c_do_action(drv_data); ++ spin_unlock_irqrestore(&drv_data->lock, flags); ++ ++ mv64xxx_i2c_wait_for_completion(drv_data); ++ return drv_data->rc; ++} ++ ++/* ++ ***************************************************************************** ++ * ++ * I2C Core Support Routines (Interface to higher level I2C code) ++ * ++ ***************************************************************************** ++ */ ++static u32 ++mv64xxx_i2c_functionality(struct i2c_adapter *adap) ++{ ++ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; ++} ++ ++static int ++mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ++{ ++ struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); ++ int i, rc = 0; ++ ++ for (i=0; i<num; i++) ++ if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) != 0) ++ break; ++ ++ return rc; ++} ++ ++static struct i2c_algorithm mv64xxx_i2c_algo = { ++ .name = MV64XXX_I2C_CTLR_NAME " algorithm", ++ .id = I2C_ALGO_MV64XXX, ++ .master_xfer = mv64xxx_i2c_xfer, ++ .functionality = mv64xxx_i2c_functionality, ++}; ++ ++/* ++ ***************************************************************************** ++ * ++ * Driver Interface & Early Init Routines ++ * ++ ***************************************************************************** ++ */ ++static void __init ++mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data) ++{ ++ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET); ++ writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)), ++ drv_data->reg_base + MV64XXX_I2C_REG_BAUD); ++ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR); ++ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR); ++ writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP, ++ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); ++ drv_data->state = MV64XXX_I2C_STATE_IDLE; ++ return; ++} ++ ++static int __init ++mv64xxx_i2c_map_regs(struct platform_device *pd, ++ struct mv64xxx_i2c_data *drv_data) ++{ ++ struct resource *r; ++ ++ if ((r = platform_get_resource(pd, IORESOURCE_MEM, 0)) && ++ request_mem_region(r->start, MV64XXX_I2C_REG_BLOCK_SIZE, ++ drv_data->adapter.name)) { ++ ++ drv_data->reg_base = ioremap(r->start, ++ MV64XXX_I2C_REG_BLOCK_SIZE); ++ drv_data->reg_base_p = r->start; ++ } else ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void __exit ++mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data) ++{ ++ if (drv_data->reg_base) { ++ iounmap(drv_data->reg_base); ++ release_mem_region(drv_data->reg_base_p, ++ MV64XXX_I2C_REG_BLOCK_SIZE); ++ } ++ ++ drv_data->reg_base = NULL; ++ drv_data->reg_base_p = 0; ++ return; ++} ++ ++static int __init ++mv64xxx_i2c_probe(struct device *dev) ++{ ++ struct platform_device *pd = to_platform_device(dev); ++ struct mv64xxx_i2c_data *drv_data; ++ struct mv64xxx_i2c_pdata *pdata = dev->platform_data; ++ int rc; ++ ++ if ((pd->id != 0) || !pdata) ++ return -ENODEV; ++ ++ drv_data = kmalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); ++ ++ if (!drv_data) ++ return -ENOMEM; ++ ++ memset(drv_data, 0, sizeof(struct mv64xxx_i2c_data)); ++ ++ if (mv64xxx_i2c_map_regs(pd, drv_data)) { ++ rc = -ENODEV; ++ goto exit_kfree; ++ } ++ ++ strncpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", ++ I2C_NAME_SIZE); ++ ++ init_waitqueue_head(&drv_data->waitq); ++ spin_lock_init(&drv_data->lock); ++ ++ drv_data->freq_m = pdata->freq_m; ++ drv_data->freq_n = pdata->freq_n; ++ drv_data->irq = platform_get_irq(pd, 0); ++ drv_data->adapter.id = I2C_ALGO_MV64XXX | I2C_HW_MV64XXX; ++ drv_data->adapter.algo = &mv64xxx_i2c_algo; ++ drv_data->adapter.timeout = pdata->timeout; ++ drv_data->adapter.retries = pdata->retries; ++ dev_set_drvdata(dev, drv_data); ++ i2c_set_adapdata(&drv_data->adapter, drv_data); ++ ++ if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0, ++ MV64XXX_I2C_CTLR_NAME, drv_data)) { ++ ++ dev_err(dev, "mv64xxx: Can't register intr handler " ++ "irq: %d\n", drv_data->irq); ++ rc = -EINVAL; ++ goto exit_unmap_regs; ++ } else if ((rc = i2c_add_adapter(&drv_data->adapter)) != 0) { ++ dev_err(dev, "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); ++ goto exit_free_irq; ++ } ++ ++ mv64xxx_i2c_hw_init(drv_data); ++ ++ return 0; ++ ++ exit_free_irq: ++ free_irq(drv_data->irq, drv_data); ++ exit_unmap_regs: ++ mv64xxx_i2c_unmap_regs(drv_data); ++ exit_kfree: ++ kfree(drv_data); ++ return rc; ++} ++ ++static int __exit ++mv64xxx_i2c_remove(struct device *dev) ++{ ++ struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev); ++ int rc; ++ ++ rc = i2c_del_adapter(&drv_data->adapter); ++ free_irq(drv_data->irq, drv_data); ++ mv64xxx_i2c_unmap_regs(drv_data); ++ kfree(drv_data); ++ ++ return rc; ++} ++ ++static struct device_driver mv64xxx_i2c_driver = { ++ .name = MV64XXX_I2C_CTLR_NAME, ++ .bus = &platform_bus_type, ++ .probe = mv64xxx_i2c_probe, ++ .remove = mv64xxx_i2c_remove, ++}; ++ ++static int __init ++mv64xxx_i2c_init(void) ++{ ++ return driver_register(&mv64xxx_i2c_driver); ++} ++ ++static void __exit ++mv64xxx_i2c_exit(void) ++{ ++ driver_unregister(&mv64xxx_i2c_driver); ++ return; ++} ++ ++module_init(mv64xxx_i2c_init); ++module_exit(mv64xxx_i2c_exit); ++ ++MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>"); ++MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver"); ++MODULE_LICENSE("GPL"); +diff -Nru a/include/linux/i2c-id.h b/include/linux/i2c-id.h +--- a/include/linux/i2c-id.h 2005-02-08 17:28:52 -07:00 ++++ b/include/linux/i2c-id.h 2005-02-08 17:28:52 -07:00 +@@ -311,4 +311,7 @@ + /* --- MCP107 adapter */ + #define I2C_HW_MPC107 0x00 + ++/* --- Marvell mv64xxx i2c adapter */ ++#define I2C_HW_MV64XXX 0x00 ++ + #endif /* LINUX_I2C_ID_H */ +diff -Nru a/include/linux/mv643xx.h b/include/linux/mv643xx.h +--- a/include/linux/mv643xx.h 2005-02-08 17:28:52 -07:00 ++++ b/include/linux/mv643xx.h 2005-02-08 17:28:52 -07:00 +@@ -977,12 +977,9 @@ + /* I2C Registers */ + /****************************************/ + +-#define MV64340_I2C_SLAVE_ADDR 0xc000 +-#define MV64340_I2C_EXTENDED_SLAVE_ADDR 0xc010 +-#define MV64340_I2C_DATA 0xc004 +-#define MV64340_I2C_CONTROL 0xc008 +-#define MV64340_I2C_STATUS_BAUDE_RATE 0xc00C +-#define MV64340_I2C_SOFT_RESET 0xc01c ++#define MV64XXX_I2C_CTLR_NAME "mv64xxx i2c" ++#define MV64XXX_I2C_OFFSET 0xc000 ++#define MV64XXX_I2C_REG_BLOCK_SIZE 0x0020 + + /****************************************/ + /* GPP Interface Registers */ +@@ -1083,6 +1080,14 @@ + u8 brg_can_tune; + u8 brg_clk_src; + u32 brg_clk_freq; ++}; ++ ++/* i2c Platform Device, Driver Data */ ++struct mv64xxx_i2c_pdata { ++ u32 freq_m; ++ u32 freq_n; ++ u32 timeout; /* In milliseconds */ ++ u32 retries; + }; + + #endif /* __ASM_MV64340_H */ diff --git a/a/content_digest b/N1/content_digest index 9c8b107..d912bc8 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -1,13 +1,13 @@ "ref\042094ADB.9040403@mvista.com\0" "ref\058cb370e05020816017431b38@mail.gmail.com\0" - "From\0mgreer@mvista.com (Mark A. Greer)\0" - "Subject\0[PATCH][I2C] Marvell mv64xxx i2c driver\0" - "Date\0Thu, 19 May 2005 06:25:37 +0000\0" + "From\0Mark A. Greer <mgreer@mvista.com>\0" + "Subject\0Re: [PATCH][I2C] Marvell mv64xxx i2c driver\0" + "Date\0Tue, 08 Feb 2005 17:32:11 -0700\0" "To\0Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>\0" "Cc\0Greg KH <greg@kroah.com>" LM Sensors <sensors@stimpy.netroedge.com> " lkml <linux-kernel@vger.kernel.org>\0" - "\00:1\0" + "\01:1\0" "b\0" "Bartlomiej Zolnierkiewicz wrote:\n" "\n" @@ -58,8 +58,10 @@ "http://archives.andrew.net.au/lm-sensors/msg29405.html\n" "\n" "Signed-off-by: Mark A. Greer <mgreer@mvista.com>\n" - "--\n" - "-------------- next part --------------\n" + -- + "\01:2\0" + "fn\0i2c_8.patch\0" + "b\0" "diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig\n" "--- a/drivers/i2c/busses/Kconfig\t2005-02-08 17:28:52 -07:00\n" "+++ b/drivers/i2c/busses/Kconfig\t2005-02-08 17:28:52 -07:00\n" @@ -210,12 +212,12 @@ "+\t * operation that driver has given up on or the user has killed.\n" "+\t * If so, issue the stop condition and go to idle.\n" "+\t */\n" - "+\tif (drv_data->state = MV64XXX_I2C_STATE_IDLE) {\n" + "+\tif (drv_data->state == MV64XXX_I2C_STATE_IDLE) {\n" "+\t\tdrv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;\n" "+\t\treturn;\n" "+\t}\n" "+\n" - "+\tif (drv_data->state = MV64XXX_I2C_STATE_ABORTING) {\n" + "+\tif (drv_data->state == MV64XXX_I2C_STATE_ABORTING) {\n" "+\t\tdrv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;\n" "+\t\tdrv_data->state = MV64XXX_I2C_STATE_IDLE;\n" "+\t\treturn;\n" @@ -234,7 +236,8 @@ "+\tcase MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */\n" "+\t\tif (drv_data->msg->flags & I2C_M_TEN) {\n" "+\t\t\tdrv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;\n" - "+\t\t\tdrv_data->state +\t\t\t\tMV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;\n" + "+\t\t\tdrv_data->state =\n" + "+\t\t\t\tMV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;\n" "+\t\t\tbreak;\n" "+\t\t}\n" "+\t\t/* FALLTHRU */\n" @@ -242,7 +245,8 @@ "+\tcase MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */\n" "+\t\tif (drv_data->bytes_left > 0) {\n" "+\t\t\tdrv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;\n" - "+\t\t\tdrv_data->state +\t\t\t\tMV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;\n" + "+\t\t\tdrv_data->state =\n" + "+\t\t\t\tMV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;\n" "+\t\t\tdrv_data->bytes_left--;\n" "+\t\t} else {\n" "+\t\t\tdrv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;\n" @@ -254,12 +258,13 @@ "+\tcase MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */\n" "+\t\tif (drv_data->msg->flags & I2C_M_TEN) {\n" "+\t\t\tdrv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;\n" - "+\t\t\tdrv_data->state +\t\t\t\tMV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;\n" + "+\t\t\tdrv_data->state =\n" + "+\t\t\t\tMV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;\n" "+\t\t\tbreak;\n" "+\t\t}\n" "+\t\t/* FALLTHRU */\n" "+\tcase MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */\n" - "+\t\tif (drv_data->bytes_left = 0) {\n" + "+\t\tif (drv_data->bytes_left == 0) {\n" "+\t\t\tdrv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;\n" "+\t\t\tdrv_data->state = MV64XXX_I2C_STATE_IDLE;\n" "+\t\t\tbreak;\n" @@ -274,7 +279,7 @@ "+\t\t}\n" "+\t\tdrv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;\n" "+\n" - "+\t\tif (drv_data->bytes_left = 1)\n" + "+\t\tif (drv_data->bytes_left == 1)\n" "+\t\t\tdrv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK;\n" "+\t\tbreak;\n" "+\n" @@ -342,13 +347,15 @@ "+\t\tbreak;\n" "+\n" "+\tcase MV64XXX_I2C_ACTION_RCV_DATA:\n" - "+\t\tdrv_data->msg->buf[drv_data->byte_posn++] +\t\t\treadl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);\n" + "+\t\tdrv_data->msg->buf[drv_data->byte_posn++] =\n" + "+\t\t\treadl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);\n" "+\t\twritel(drv_data->cntl_bits,\n" "+\t\t\tdrv_data->reg_base + MV64XXX_I2C_REG_CONTROL);\n" "+\t\tbreak;\n" "+\n" "+\tcase MV64XXX_I2C_ACTION_RCV_DATA_STOP:\n" - "+\t\tdrv_data->msg->buf[drv_data->byte_posn++] +\t\t\treadl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);\n" + "+\t\tdrv_data->msg->buf[drv_data->byte_posn++] =\n" + "+\t\t\treadl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);\n" "+\t\tdrv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;\n" "+\t\twritel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,\n" "+\t\t\tdrv_data->reg_base + MV64XXX_I2C_REG_CONTROL);\n" @@ -482,10 +489,12 @@ "+\t\tif (drv_data->msg->flags & I2C_M_RD) {\n" "+\t\t\t/* No action to do, wait for slave to send a byte */\n" "+\t\t\tdrv_data->action = MV64XXX_I2C_ACTION_CONTINUE;\n" - "+\t\t\tdrv_data->state +\t\t\t\tMV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;\n" + "+\t\t\tdrv_data->state =\n" + "+\t\t\t\tMV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;\n" "+\t\t} else {\n" "+\t\t\tdrv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;\n" - "+\t\t\tdrv_data->state +\t\t\t\tMV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;\n" + "+\t\t\tdrv_data->state =\n" + "+\t\t\t\tMV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;\n" "+\t\t\tdrv_data->bytes_left--;\n" "+\t\t}\n" "+\t} else {\n" @@ -738,4 +747,4 @@ " \n" #endif /* __ASM_MV64340_H */ -b61e43c5aa77785be41cd49fadef1e1be7930bc17afb00c74423043f73a20a74 +c365a093fea3a9ab0de53442b72b95d9ff03105a61b9e3e7614b583a37267d37
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.