11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein * Driver for the i2c controller on the Marvell line of host bridges
3a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein * (e.g, gt642[46]0, mv643[46]0, mv644[46]0, and Orion SoC family).
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author: Mark A. Greer <mgreer@mvista.com>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2005 (c) MontaVista, Software, Inc.  This file is licensed under
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the terms of the GNU General Public License version 2.  This program
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is licensed "as is" without any warranty of any kind, whether express
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or implied.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
135a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2c.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
18a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein#include <linux/mv643xx_i2c.h>
19d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
202178218027e4da0608219fae1d02e5c88f4e560dH Hartley Sweeten#include <linux/io.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Register defines */
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_SLAVE_ADDR			0x00
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_DATA				0x04
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_CONTROL				0x08
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_STATUS				0x0c
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_BAUD				0x0c
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_EXT_SLAVE_ADDR			0x10
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_SOFT_RESET			0x1c
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_CONTROL_ACK			0x00000004
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_CONTROL_IFLG			0x00000008
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_CONTROL_STOP			0x00000010
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_CONTROL_START			0x00000020
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_CONTROL_TWSIEN			0x00000040
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_REG_CONTROL_INTEN			0x00000080
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Ctlr status values */
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_BUS_ERR			0x00
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_START			0x08
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_REPEAT_START		0x10
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK		0x18
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK		0x20
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_WR_ACK			0x28
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_WR_NO_ACK		0x30
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_LOST_ARB		0x38
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK		0x40
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK		0x48
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK		0x50
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK		0x58
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK		0xd0
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK	0xd8
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK		0xe0
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK	0xe8
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MV64XXX_I2C_STATUS_NO_STATUS			0xf8
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Driver states */
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_STATE_INVALID,
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_STATE_IDLE,
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_STATE_WAITING_FOR_START_COND,
62eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti	MV64XXX_I2C_STATE_WAITING_FOR_RESTART,
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK,
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK,
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK,
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA,
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Driver actions */
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_ACTION_INVALID,
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_ACTION_CONTINUE,
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_ACTION_SEND_START,
74eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti	MV64XXX_I2C_ACTION_SEND_RESTART,
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_ACTION_SEND_ADDR_1,
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_ACTION_SEND_ADDR_2,
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_ACTION_SEND_DATA,
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_ACTION_RCV_DATA,
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_ACTION_RCV_DATA_STOP,
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MV64XXX_I2C_ACTION_SEND_STOP,
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mv64xxx_i2c_data {
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			irq;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			state;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			action;
87e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer	u32			aborting;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			cntl_bits;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem		*reg_base;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			reg_base_p;
91a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein	u32			reg_size;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			addr1;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			addr2;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			bytes_left;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			byte_posn;
96eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti	u32			send_stop;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			block;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			rc;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			freq_m;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			freq_n;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t	waitq;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t		lock;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_msg		*msg;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_adapter	adapter;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Finite State Machine & Interrupt Routines
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
114a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth
115a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth/* Reset hardware and initialize FSM */
116a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworthstatic void
117a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworthmv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
118a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth{
119a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
120a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth	writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
121a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth		drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
122a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
123a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
124a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth	writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
125a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth		drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
126a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth	drv_data->state = MV64XXX_I2C_STATE_IDLE;
127a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth}
128a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If state is idle, then this is likely the remnants of an old
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * operation that driver has given up on or the user has killed.
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If so, issue the stop condition and go to idle.
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (drv_data->state == MV64XXX_I2C_STATE_IDLE) {
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The status from the ctlr [mostly] tells us what to do next */
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (status) {
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start condition interrupt */
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_START: /* 0x08 */
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Performing a write */
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (drv_data->msg->flags & I2C_M_TEN) {
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->state =
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FALLTHRU */
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */
162e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer		if ((drv_data->bytes_left == 0)
163e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer				|| (drv_data->aborting
164e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer					&& (drv_data->byte_posn != 0))) {
165eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti			if (drv_data->send_stop) {
166eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti				drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
167eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti				drv_data->state = MV64XXX_I2C_STATE_IDLE;
168eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti			} else {
169eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti				drv_data->action =
170eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti					MV64XXX_I2C_ACTION_SEND_RESTART;
171eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti				drv_data->state =
172eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti					MV64XXX_I2C_STATE_WAITING_FOR_RESTART;
173eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti			}
174e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer		} else {
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->state =
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->bytes_left--;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Performing a read */
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (drv_data->msg->flags & I2C_M_TEN) {
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->state =
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FALLTHRU */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (drv_data->bytes_left == 0) {
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->state = MV64XXX_I2C_STATE_IDLE;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FALLTHRU */
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->bytes_left--;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
207e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer		if ((drv_data->bytes_left == 1) || drv_data->aborting)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->state = MV64XXX_I2C_STATE_IDLE;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Doesn't seem to be a device at other end */
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->state = MV64XXX_I2C_STATE_IDLE;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->rc = -ENODEV;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&drv_data->adapter.dev,
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, "
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"status: 0x%x, addr: 0x%x, flags: 0x%x\n",
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 drv_data->state, status, drv_data->msg->addr,
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 drv_data->msg->flags);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
232a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth		mv64xxx_i2c_hw_init(drv_data);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->rc = -EIO;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch(drv_data->action) {
241eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti	case MV64XXX_I2C_ACTION_SEND_RESTART:
242eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti		drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
243eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti		drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
244eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti		writel(drv_data->cntl_bits,
245eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
246eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti		drv_data->block = 0;
247eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti		wake_up_interruptible(&drv_data->waitq);
248eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti		break;
249eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_ACTION_CONTINUE:
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(drv_data->cntl_bits,
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_ACTION_SEND_START:
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_ACTION_SEND_ADDR_1:
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(drv_data->addr1,
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->reg_base + MV64XXX_I2C_REG_DATA);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(drv_data->cntl_bits,
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_ACTION_SEND_ADDR_2:
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(drv_data->addr2,
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->reg_base + MV64XXX_I2C_REG_DATA);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(drv_data->cntl_bits,
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_ACTION_SEND_DATA:
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(drv_data->msg->buf[drv_data->byte_posn++],
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->reg_base + MV64XXX_I2C_REG_DATA);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(drv_data->cntl_bits,
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_ACTION_RCV_DATA:
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->msg->buf[drv_data->byte_posn++] =
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(drv_data->cntl_bits,
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_ACTION_RCV_DATA_STOP:
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->msg->buf[drv_data->byte_posn++] =
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->block = 0;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wake_up_interruptible(&drv_data->waitq);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_ACTION_INVALID:
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&drv_data->adapter.dev,
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"mv64xxx_i2c_do_action: Invalid action: %d\n",
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->action);
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->rc = -EIO;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FALLTHRU */
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MV64XXX_I2C_ACTION_SEND_STOP:
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->block = 0;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wake_up_interruptible(&drv_data->waitq);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
315b0999cc55bd49e315ec82d2fb770a0d9ef7cbed8Mikael Petterssonstatic irqreturn_t
3167d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsmv64xxx_i2c_intr(int irq, void *dev_id)
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mv64xxx_i2c_data	*drv_data = dev_id;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32		status;
321b0999cc55bd49e315ec82d2fb770a0d9ef7cbed8Mikael Pettersson	irqreturn_t	rc = IRQ_NONE;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&drv_data->lock, flags);
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) &
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						MV64XXX_I2C_REG_CONTROL_IFLG) {
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS);
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mv64xxx_i2c_fsm(drv_data, status);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mv64xxx_i2c_do_action(drv_data);
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = IRQ_HANDLED;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&drv_data->lock, flags);
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	I2C Msg Execution Routines
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_msg *msg)
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32	dir = 0;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->msg = msg;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->byte_posn = 0;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->bytes_left = msg->len;
352e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer	drv_data->aborting = 0;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->rc = 0;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (msg->flags & I2C_M_RD)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dir = 1;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (msg->flags & I2C_M_TEN) {
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->addr2 = (u32)msg->addr & 0xff;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->addr2 = 0;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long		time_left;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		abort = 0;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	time_left = wait_event_interruptible_timeout(drv_data->waitq,
3778a52c6b4d55b2960d93a90a7cf6afd252357fa54Jean Delvare		!drv_data->block, drv_data->adapter.timeout);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&drv_data->lock, flags);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!time_left) { /* Timed out */
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->rc = -ETIMEDOUT;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		abort = 1;
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (time_left < 0) { /* Interrupted/Error */
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drv_data->rc = time_left; /* errno value */
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		abort = 1;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (abort && drv_data->block) {
389e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer		drv_data->aborting = 1;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&drv_data->lock, flags);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		time_left = wait_event_timeout(drv_data->waitq,
3938a52c6b4d55b2960d93a90a7cf6afd252357fa54Jean Delvare			!drv_data->block, drv_data->adapter.timeout);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
395e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer		if ((time_left <= 0) && drv_data->block) {
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->state = MV64XXX_I2C_STATE_IDLE;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_err(&drv_data->adapter.dev,
398e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer				"mv64xxx: I2C bus locked, block: %d, "
399e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer				"time_left: %d\n", drv_data->block,
400e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer				(int)time_left);
401a07ad1cc0300931bfd76bfcd2da3ddad743f4a89Dale Farnsworth			mv64xxx_i2c_hw_init(drv_data);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&drv_data->lock, flags);
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
408eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giomettimv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
409eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti				int is_first, int is_last)
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&drv_data->lock, flags);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mv64xxx_i2c_prepare_for_io(drv_data, msg);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(msg->flags & I2C_M_NOSTART)) { /* Skip start/addr phases */
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (drv_data->msg->flags & I2C_M_RD) {
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* No action to do, wait for slave to send a byte */
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->state =
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->state =
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drv_data->bytes_left--;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
429eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti		if (is_first) {
430eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti			drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
431eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti			drv_data->state =
432eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti				MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
433eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti		} else {
434eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti			drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
435eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti			drv_data->state =
436eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti				MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
437eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti		}
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
440eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti	drv_data->send_stop = is_last;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->block = 1;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mv64xxx_i2c_do_action(drv_data);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&drv_data->lock, flags);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mv64xxx_i2c_wait_for_completion(drv_data);
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return drv_data->rc;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	I2C Core Support Routines (Interface to higher level I2C code)
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmv64xxx_i2c_functionality(struct i2c_adapter *adap)
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
466d1b2f0a9754d3087ee29b3e88b8f20f2d30090d3Jean Delvare	int	i, rc;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
468eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti	for (i = 0; i < num; i++) {
469eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti		rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i],
470eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti						i == 0, i + 1 == num);
471eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti		if (rc < 0)
472d1b2f0a9754d3087ee29b3e88b8f20f2d30090d3Jean Delvare			return rc;
473eda6bee6c7e67b5bd17bdbced0926f5687f686d5Rodolfo Giometti	}
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
475d1b2f0a9754d3087ee29b3e88b8f20f2d30090d3Jean Delvare	return num;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4788f9082c5ce0e2c2f7ad0211b0c089f680d2efc11Jean Delvarestatic const struct i2c_algorithm mv64xxx_i2c_algo = {
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.master_xfer = mv64xxx_i2c_xfer,
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.functionality = mv64xxx_i2c_functionality,
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Driver Interface & Early Init Routines
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmv64xxx_i2c_map_regs(struct platform_device *pd,
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mv64xxx_i2c_data *drv_data)
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
494a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein	int size;
495a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein	struct resource	*r = platform_get_resource(pd, IORESOURCE_MEM, 0);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
497a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein	if (!r)
498a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein		return -ENODEV;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
500c6ffddea36dd576b70dfbd10eb5d2b287b786dcaLinus Walleij	size = resource_size(r);
501a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein
502a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein	if (!request_mem_region(r->start, size, drv_data->adapter.name))
503a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein		return -EBUSY;
504a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein
505a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein	drv_data->reg_base = ioremap(r->start, size);
506a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein	drv_data->reg_base_p = r->start;
507a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein	drv_data->reg_size = size;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
512bdf602bd737eb07d63d6fa2da826b4751fdf9babRussell Kingstatic void
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (drv_data->reg_base) {
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iounmap(drv_data->reg_base);
517a0832798c05241f15e793805b6024919c07b8292Tzachi Perelstein		release_mem_region(drv_data->reg_base_p, drv_data->reg_size);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->reg_base = NULL;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->reg_base_p = 0;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit
5253ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingmv64xxx_i2c_probe(struct platform_device *pd)
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mv64xxx_i2c_data		*drv_data;
5283ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	struct mv64xxx_i2c_pdata	*pdata = pd->dev.platform_data;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	rc;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((pd->id != 0) || !pdata)
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5345263ebb51eb098b01caf229498c954999117e4a7Deepak Saxena	drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!drv_data)
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mv64xxx_i2c_map_regs(pd, drv_data)) {
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -ENODEV;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit_kfree;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
543e91c021c487110386a07facd0396e6c3b7cf9c1fMark A. Greer	strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter",
5442096b956d24c4b5950b808fc23b218425d79ebb1David Brownell		sizeof(drv_data->adapter.name));
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_waitqueue_head(&drv_data->waitq);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&drv_data->lock);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->freq_m = pdata->freq_m;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->freq_n = pdata->freq_n;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->irq = platform_get_irq(pd, 0);
552489447380a2921ec0e9154f773c44ab3167ede4bDavid Vrabel	if (drv_data->irq < 0) {
553489447380a2921ec0e9154f773c44ab3167ede4bDavid Vrabel		rc = -ENXIO;
554489447380a2921ec0e9154f773c44ab3167ede4bDavid Vrabel		goto exit_unmap_regs;
555489447380a2921ec0e9154f773c44ab3167ede4bDavid Vrabel	}
55612a917f69d1468c91d646dbad8408dd0d39d6207Jean Delvare	drv_data->adapter.dev.parent = &pd->dev;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->adapter.algo = &mv64xxx_i2c_algo;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv_data->adapter.owner = THIS_MODULE;
5593401b2fff38fbb8b73ea6bcc69a8370ae5d2a7a0Jean Delvare	drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
5608a52c6b4d55b2960d93a90a7cf6afd252357fa54Jean Delvare	drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
56165b22ad9508b609b0625eccb2680996a1e09ed16Dale Farnsworth	drv_data->adapter.nr = pd->id;
5623ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_set_drvdata(pd, drv_data);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2c_set_adapdata(&drv_data->adapter, drv_data);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5653269bb63eb076318ce4fb554851d047e1c9aa1a5Maxime Bizon	mv64xxx_i2c_hw_init(drv_data);
5663269bb63eb076318ce4fb554851d047e1c9aa1a5Maxime Bizon
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
568dfded4ae71080b53798c7bbf4628a9b22d1e3e8bMark A. Greer			MV64XXX_I2C_CTLR_NAME, drv_data)) {
569dfded4ae71080b53798c7bbf4628a9b22d1e3e8bMark A. Greer		dev_err(&drv_data->adapter.dev,
570dfded4ae71080b53798c7bbf4628a9b22d1e3e8bMark A. Greer			"mv64xxx: Can't register intr handler irq: %d\n",
571dfded4ae71080b53798c7bbf4628a9b22d1e3e8bMark A. Greer			drv_data->irq);
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -EINVAL;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit_unmap_regs;
57465b22ad9508b609b0625eccb2680996a1e09ed16Dale Farnsworth	} else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
575dfded4ae71080b53798c7bbf4628a9b22d1e3e8bMark A. Greer		dev_err(&drv_data->adapter.dev,
576dfded4ae71080b53798c7bbf4628a9b22d1e3e8bMark A. Greer			"mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit_free_irq;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	exit_free_irq:
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_irq(drv_data->irq, drv_data);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	exit_unmap_regs:
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mv64xxx_i2c_unmap_regs(drv_data);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	exit_kfree:
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(drv_data);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devexit
5923ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingmv64xxx_i2c_remove(struct platform_device *dev)
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5943ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	struct mv64xxx_i2c_data		*drv_data = platform_get_drvdata(dev);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	rc;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = i2c_del_adapter(&drv_data->adapter);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(drv_data->irq, drv_data);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mv64xxx_i2c_unmap_regs(drv_data);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(drv_data);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6053ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver mv64xxx_i2c_driver = {
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe	= mv64xxx_i2c_probe,
607bdf602bd737eb07d63d6fa2da826b4751fdf9babRussell King	.remove	= __devexit_p(mv64xxx_i2c_remove),
6083ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver	= {
6093ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
6103ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= MV64XXX_I2C_CTLR_NAME,
6113ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
614a3664b51c783aaa0dde1c95334d1a670d6d54590Axel Linmodule_platform_driver(mv64xxx_i2c_driver);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver");
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
619