diff for duplicates of <41FFC258.8010505@mvista.com> diff --git a/a/1.txt b/N1/1.txt index cf588b5..04a251f 100644 --- a/a/1.txt +++ b/N1/1.txt @@ -5,700 +5,3 @@ Greg KH wrote: > Oops, sorry. :) --------------- next part -------------- -diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig ---- a/drivers/i2c/busses/Kconfig 2005-02-01 10:45:00 -07:00 -+++ b/drivers/i2c/busses/Kconfig 2005-02-01 10:45:00 -07:00 -@@ -476,4 +476,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-01 10:45:00 -07:00 -+++ b/drivers/i2c/busses/Makefile 2005-02-01 10:45:00 -07:00 -@@ -20,6 +20,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-01 10:45:00 -07:00 -@@ -0,0 +1,614 @@ -+/* -+ * 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; -+ uint state; -+ uint action; -+ u32 cntl_bits; -+ void *reg_base; -+ ulong reg_base_p; -+ u32 addr1; -+ u32 addr2; -+ uint bytes_left; -+ uint byte_posn; -+ uint 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; -+ drv_data->state = MV64XXX_I2C_STATE_IDLE; -+ 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 __devinit -+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 __devinit -+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 __devexit -+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 = 0; -+ drv_data->reg_base_p = 0; -+ return; -+} -+ -+static int __devinit -+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) { -+ 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)) { -+ kfree(drv_data); -+ return -ENODEV; -+ } -+ -+ 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); -+ -+ mv64xxx_i2c_unmap_regs(drv_data); -+ kfree(drv_data); -+ return -EINVAL; -+ } -+ else if ((rc = i2c_add_adapter(&drv_data->adapter)) != 0) { -+ dev_err(dev, "mv64xxx: Can't add i2c adapter, rc: %d\n", -+ -rc); -+ free_irq(drv_data->irq, drv_data); -+ mv64xxx_i2c_unmap_regs(drv_data); -+ kfree(drv_data); -+ return rc; -+ } -+ -+ mv64xxx_i2c_hw_init(drv_data); -+ } -+ else -+ return -ENODEV; -+ -+ return 0; -+} -+ -+static int __devexit -+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 __devinit -+mv64xxx_i2c_init(void) -+{ -+ return driver_register(&mv64xxx_i2c_driver); -+} -+ -+static void __devexit -+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-01 10:45:00 -07:00 -+++ b/include/linux/i2c-id.h 2005-02-01 10:45:00 -07:00 -@@ -200,6 +200,9 @@ - - #define I2C_ALGO_SIBYTE 0x150000 /* Broadcom SiByte SOCs */ - #define I2C_ALGO_SGI 0x160000 /* SGI algorithm */ -+ /* 0x170000 - USB */ -+ /* 0x180000 - Virtual buses */ -+#define I2C_ALGO_MV64XXX 0x190000 /* Marvell mv64xxx i2c ctlr */ - - #define I2C_ALGO_EXP 0x800000 /* experimental */ - -@@ -305,5 +308,8 @@ - - /* --- 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-01 10:45:00 -07:00 -+++ b/include/linux/mv643xx.h 2005-02-01 10:45:00 -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..e9fded5 --- /dev/null +++ b/N1/2.hdr @@ -0,0 +1,5 @@ +Content-Type: text/plain; + name="i2c_4.patch" +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; + filename="i2c_4.patch" diff --git a/N1/2.txt b/N1/2.txt new file mode 100644 index 0000000..0a49b29 --- /dev/null +++ b/N1/2.txt @@ -0,0 +1,703 @@ +diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +--- a/drivers/i2c/busses/Kconfig 2005-02-01 10:45:00 -07:00 ++++ b/drivers/i2c/busses/Kconfig 2005-02-01 10:45:00 -07:00 +@@ -476,4 +476,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-01 10:45:00 -07:00 ++++ b/drivers/i2c/busses/Makefile 2005-02-01 10:45:00 -07:00 +@@ -20,6 +20,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-01 10:45:00 -07:00 +@@ -0,0 +1,614 @@ ++/* ++ * 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; ++ uint state; ++ uint action; ++ u32 cntl_bits; ++ void *reg_base; ++ ulong reg_base_p; ++ u32 addr1; ++ u32 addr2; ++ uint bytes_left; ++ uint byte_posn; ++ uint 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; ++ drv_data->state = MV64XXX_I2C_STATE_IDLE; ++ 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 __devinit ++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 __devinit ++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 __devexit ++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 = 0; ++ drv_data->reg_base_p = 0; ++ return; ++} ++ ++static int __devinit ++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) { ++ 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)) { ++ kfree(drv_data); ++ return -ENODEV; ++ } ++ ++ 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); ++ ++ mv64xxx_i2c_unmap_regs(drv_data); ++ kfree(drv_data); ++ return -EINVAL; ++ } ++ else if ((rc = i2c_add_adapter(&drv_data->adapter)) != 0) { ++ dev_err(dev, "mv64xxx: Can't add i2c adapter, rc: %d\n", ++ -rc); ++ free_irq(drv_data->irq, drv_data); ++ mv64xxx_i2c_unmap_regs(drv_data); ++ kfree(drv_data); ++ return rc; ++ } ++ ++ mv64xxx_i2c_hw_init(drv_data); ++ } ++ else ++ return -ENODEV; ++ ++ return 0; ++} ++ ++static int __devexit ++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 __devinit ++mv64xxx_i2c_init(void) ++{ ++ return driver_register(&mv64xxx_i2c_driver); ++} ++ ++static void __devexit ++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-01 10:45:00 -07:00 ++++ b/include/linux/i2c-id.h 2005-02-01 10:45:00 -07:00 +@@ -200,6 +200,9 @@ + + #define I2C_ALGO_SIBYTE 0x150000 /* Broadcom SiByte SOCs */ + #define I2C_ALGO_SGI 0x160000 /* SGI algorithm */ ++ /* 0x170000 - USB */ ++ /* 0x180000 - Virtual buses */ ++#define I2C_ALGO_MV64XXX 0x190000 /* Marvell mv64xxx i2c ctlr */ + + #define I2C_ALGO_EXP 0x800000 /* experimental */ + +@@ -305,5 +308,8 @@ + + /* --- 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-01 10:45:00 -07:00 ++++ b/include/linux/mv643xx.h 2005-02-01 10:45:00 -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 66459a0..22d8730 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -2,14 +2,14 @@ "ref\020050131182542.GB21438@kroah.com\0" "ref\041FE7BD8.9060103@mvista.com\0" "ref\020050201004637.GB8296@kroah.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:35 +0000\0" + "From\0Mark A. Greer <mgreer@mvista.com>\0" + "Subject\0Re: [PATCH][I2C] Marvell mv64xxx i2c driver\0" + "Date\0Tue, 01 Feb 2005 10:54:32 -0700\0" "To\0Greg KH <greg@kroah.com>\0" "Cc\0phil@netroedge.com" sensors@stimpy.netroedge.com " lkml <linux-kernel@vger.kernel.org>\0" - "\00:1\0" + "\01:1\0" "b\0" "Greg KH wrote:\n" "\n" @@ -17,8 +17,10 @@ "> \n" ">\n" "\n" - "Oops, sorry. :)\n" - "-------------- next part --------------\n" + Oops, sorry. :) + "\01:2\0" + "fn\0i2c_4.patch\0" + "b\0" "diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig\n" "--- a/drivers/i2c/busses/Kconfig\t2005-02-01 10:45:00 -07:00\n" "+++ b/drivers/i2c/busses/Kconfig\t2005-02-01 10:45:00 -07:00\n" @@ -169,13 +171,13 @@ "+\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\tdrv_data->state = MV64XXX_I2C_STATE_IDLE;\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" @@ -194,7 +196,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" @@ -202,7 +205,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}\n" "+\t\telse {\n" @@ -215,12 +219,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" @@ -235,7 +240,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" @@ -303,13 +308,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" @@ -446,11 +453,13 @@ "+\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}\n" "+\t\telse {\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}\n" @@ -563,7 +572,7 @@ "+\tstruct mv64xxx_i2c_pdata\t*pdata = dev->platform_data;\n" "+\tint\trc;\n" "+\n" - "+\tif ((pd->id = 0) && pdata) {\n" + "+\tif ((pd->id == 0) && pdata) {\n" "+\t\tdrv_data = kmalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL);\n" "+\n" "+\t\tif (!drv_data)\n" @@ -716,4 +725,4 @@ " \n" #endif /* __ASM_MV64340_H */ -e0354d918b42e0b9631e84c60c5af091450a7d6fa0ca578dd302fb7e184081a3 +eef23d36ba0c7674f9e27134aeaf0500d393aceac2a7bbc603f7af243c5926e1
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.