11b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
21b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Specific bus support for PMC-TWI compliant implementation on MSP71xx.
31b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *
41b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Copyright 2005-2007 PMC-Sierra, Inc.
51b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *
61b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  This program is free software; you can redistribute  it and/or modify it
71b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  under  the terms of  the GNU General  Public License as published by the
81b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  Free Software Foundation;  either version 2 of the  License, or (at your
91b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  option) any later version.
101b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *
111b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
121b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
131b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
141b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
151b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
161b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
171b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
181b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
191b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
201b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
211b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *
221b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  You should have received a copy of the  GNU General Public License along
231b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  with this program; if not, write  to the Free Software Foundation, Inc.,
241b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *  675 Mass Ave, Cambridge, MA 02139, USA.
251b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
261b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
271b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#include <linux/kernel.h>
281b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#include <linux/module.h>
291b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#include <linux/init.h>
301b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#include <linux/platform_device.h>
311b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#include <linux/i2c.h>
321b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#include <linux/interrupt.h>
331b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#include <linux/completion.h>
341b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#include <linux/mutex.h>
351b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#include <linux/delay.h>
362178218027e4da0608219fae1d02e5c88f4e560dH Hartley Sweeten#include <linux/io.h>
371b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
381b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define DRV_NAME	"pmcmsptwi"
391b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
401b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_SF_CLK_REG_OFFSET	0x00
411b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_HS_CLK_REG_OFFSET	0x04
421b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_CFG_REG_OFFSET		0x08
431b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_CMD_REG_OFFSET		0x0c
441b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_ADD_REG_OFFSET		0x10
451b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_DAT_0_REG_OFFSET	0x14
461b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_DAT_1_REG_OFFSET	0x18
471b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_INT_STS_REG_OFFSET	0x1c
481b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_INT_MSK_REG_OFFSET	0x20
491b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_BUSY_REG_OFFSET		0x24
501b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
511b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_INT_STS_DONE			(1 << 0)
521b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_INT_STS_LOST_ARBITRATION	(1 << 1)
531b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_INT_STS_NO_RESPONSE		(1 << 2)
541b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_INT_STS_DATA_COLLISION		(1 << 3)
551b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_INT_STS_BUSY			(1 << 4)
561b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_TWI_INT_STS_ALL			0x1f
571b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
581b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_MAX_BYTES_PER_RW		8
591b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_MAX_POLL			5
601b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_POLL_DELAY			10
611b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define MSP_IRQ_TIMEOUT			(MSP_MAX_POLL * MSP_POLL_DELAY)
621b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
631b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/* IO Operation macros */
641b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define pmcmsptwi_readl		__raw_readl
651b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean#define pmcmsptwi_writel	__raw_writel
661b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
671b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/* TWI command type */
681b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanenum pmcmsptwi_cmd_type {
691b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	MSP_TWI_CMD_WRITE	= 0,	/* Write only */
701b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	MSP_TWI_CMD_READ	= 1,	/* Read only */
711b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	MSP_TWI_CMD_WRITE_READ	= 2,	/* Write then Read */
721b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
731b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
741b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/* The possible results of the xferCmd */
751b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanenum pmcmsptwi_xfer_result {
761b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	MSP_TWI_XFER_OK	= 0,
771b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	MSP_TWI_XFER_TIMEOUT,
781b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	MSP_TWI_XFER_BUSY,
791b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	MSP_TWI_XFER_DATA_COLLISION,
801b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	MSP_TWI_XFER_NO_RESPONSE,
811b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	MSP_TWI_XFER_LOST_ARBITRATION,
821b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
831b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
841b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/* Corresponds to a PMCTWI clock configuration register */
851b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstruct pmcmsptwi_clock {
861b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u8 filter;	/* Bits 15:12,	default = 0x03 */
871b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u16 clock;	/* Bits 9:0,	default = 0x001f */
881b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
891b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
901b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstruct pmcmsptwi_clockcfg {
911b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	struct pmcmsptwi_clock standard;  /* The standard/fast clock config */
921b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	struct pmcmsptwi_clock highspeed; /* The highspeed clock config */
931b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
941b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
951b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/* Corresponds to the main TWI configuration register */
961b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstruct pmcmsptwi_cfg {
971b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u8 arbf;	/* Bits 15:12,	default=0x03 */
981b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u8 nak;		/* Bits 11:8,	default=0x03 */
991b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u8 add10;	/* Bit 7,	default=0x00 */
1001b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u8 mst_code;	/* Bits 6:4,	default=0x00 */
1011b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u8 arb;		/* Bit 1,	default=0x01 */
1021b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u8 highspeed;	/* Bit 0,	default=0x00 */
1031b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
1041b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
1051b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/* A single pmctwi command to issue */
1061b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstruct pmcmsptwi_cmd {
1071b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u16 addr;	/* The slave address (7 or 10 bits) */
1081b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	enum pmcmsptwi_cmd_type type;	/* The command type */
1091b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u8 write_len;	/* Number of bytes in the write buffer */
1101b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u8 read_len;	/* Number of bytes in the read buffer */
1111b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u8 *write_data;	/* Buffer of characters to send */
1121b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u8 *read_data;	/* Buffer to fill with incoming data */
1131b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
1141b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
1151b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/* The private data */
1161b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstruct pmcmsptwi_data {
1171b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	void __iomem *iobase;			/* iomapped base for IO */
1181b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	int irq;				/* IRQ to use (0 disables) */
1191b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	struct completion wait;			/* Completion for xfer */
1201b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	struct mutex lock;			/* Used for threadsafeness */
1211b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	enum pmcmsptwi_xfer_result last_result;	/* result of last xfer */
1221b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
1231b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
1241b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/* The default settings */
125305183fc3ec8aac55179ef0fcb65dab9b97a9145Tobias Klauserstatic const struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = {
1261b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.standard = {
1271b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		.filter	= 0x3,
1281b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		.clock	= 0x1f,
1291b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	},
1301b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.highspeed = {
1311b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		.filter	= 0x3,
1321b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		.clock	= 0x1f,
1331b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	},
1341b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
1351b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
136305183fc3ec8aac55179ef0fcb65dab9b97a9145Tobias Klauserstatic const struct pmcmsptwi_cfg pmcmsptwi_defcfg = {
1371b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.arbf		= 0x03,
1381b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.nak		= 0x03,
1391b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.add10		= 0x00,
1401b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.mst_code	= 0x00,
1411b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.arb		= 0x01,
1421b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.highspeed	= 0x00,
1431b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
1441b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
1451b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic struct pmcmsptwi_data pmcmsptwi_data;
1461b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
1471b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic struct i2c_adapter pmcmsptwi_adapter;
1481b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
1491b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/* inline helper functions */
1501b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic inline u32 pmcmsptwi_clock_to_reg(
1511b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			const struct pmcmsptwi_clock *clock)
1521b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
1531b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
1541b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
1551b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
1561b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic inline void pmcmsptwi_reg_to_clock(
1571b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			u32 reg, struct pmcmsptwi_clock *clock)
1581b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
1591b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	clock->filter = (reg >> 12) & 0xf;
1601b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	clock->clock = reg & 0x03ff;
1611b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
1621b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
1631b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
1641b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
1651b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return ((cfg->arbf & 0xf) << 12) |
1661b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		((cfg->nak & 0xf) << 8) |
1671b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		((cfg->add10 & 0x1) << 7) |
1681b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		((cfg->mst_code & 0x7) << 4) |
1691b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		((cfg->arb & 0x1) << 1) |
1701b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		(cfg->highspeed & 0x1);
1711b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
1721b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
1731b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic inline void pmcmsptwi_reg_to_cfg(u32 reg, struct pmcmsptwi_cfg *cfg)
1741b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
1751b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	cfg->arbf = (reg >> 12) & 0xf;
1761b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	cfg->nak = (reg >> 8) & 0xf;
1771b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	cfg->add10 = (reg >> 7) & 0x1;
1781b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	cfg->mst_code = (reg >> 4) & 0x7;
1791b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	cfg->arb = (reg >> 1) & 0x1;
1801b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	cfg->highspeed = reg & 0x1;
1811b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
1821b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
1831b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
1841b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Sets the current clock configuration
1851b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
1861b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic void pmcmsptwi_set_clock_config(const struct pmcmsptwi_clockcfg *cfg,
1871b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean					struct pmcmsptwi_data *data)
1881b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
1891b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	mutex_lock(&data->lock);
1901b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->standard),
1911b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				data->iobase + MSP_TWI_SF_CLK_REG_OFFSET);
1921b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->highspeed),
1931b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				data->iobase + MSP_TWI_HS_CLK_REG_OFFSET);
1941b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	mutex_unlock(&data->lock);
1951b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
1961b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
1971b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
1981b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Gets the current TWI bus configuration
1991b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
2001b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic void pmcmsptwi_get_twi_config(struct pmcmsptwi_cfg *cfg,
2011b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean					struct pmcmsptwi_data *data)
2021b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
2031b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	mutex_lock(&data->lock);
2041b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_reg_to_cfg(pmcmsptwi_readl(
2051b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				data->iobase + MSP_TWI_CFG_REG_OFFSET), cfg);
2061b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	mutex_unlock(&data->lock);
2071b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
2081b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2091b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
2101b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Sets the current TWI bus configuration
2111b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
2121b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic void pmcmsptwi_set_twi_config(const struct pmcmsptwi_cfg *cfg,
2131b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean					struct pmcmsptwi_data *data)
2141b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
2151b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	mutex_lock(&data->lock);
2161b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_writel(pmcmsptwi_cfg_to_reg(cfg),
2171b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				data->iobase + MSP_TWI_CFG_REG_OFFSET);
2181b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	mutex_unlock(&data->lock);
2191b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
2201b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2211b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
2221b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Parses the 'int_sts' register and returns a well-defined error code
2231b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
2241b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic enum pmcmsptwi_xfer_result pmcmsptwi_get_result(u32 reg)
2251b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
2261b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (reg & MSP_TWI_INT_STS_LOST_ARBITRATION) {
2271b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_dbg(&pmcmsptwi_adapter.dev,
2281b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			"Result: Lost arbitration\n");
2291b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		return MSP_TWI_XFER_LOST_ARBITRATION;
2301b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	} else if (reg & MSP_TWI_INT_STS_NO_RESPONSE) {
2311b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_dbg(&pmcmsptwi_adapter.dev,
2321b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			"Result: No response\n");
2331b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		return MSP_TWI_XFER_NO_RESPONSE;
2341b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	} else if (reg & MSP_TWI_INT_STS_DATA_COLLISION) {
2351b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_dbg(&pmcmsptwi_adapter.dev,
2361b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			"Result: Data collision\n");
2371b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		return MSP_TWI_XFER_DATA_COLLISION;
2381b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	} else if (reg & MSP_TWI_INT_STS_BUSY) {
2391b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_dbg(&pmcmsptwi_adapter.dev,
2401b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			"Result: Bus busy\n");
2411b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		return MSP_TWI_XFER_BUSY;
2421b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
2431b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2441b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	dev_dbg(&pmcmsptwi_adapter.dev, "Result: Operation succeeded\n");
2451b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return MSP_TWI_XFER_OK;
2461b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
2471b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2481b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
2491b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * In interrupt mode, handle the interrupt.
2501b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * NOTE: Assumes data->lock is held.
2511b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
2521b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic irqreturn_t pmcmsptwi_interrupt(int irq, void *ptr)
2531b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
2541b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	struct pmcmsptwi_data *data = ptr;
2551b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2561b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	u32 reason = pmcmsptwi_readl(data->iobase +
2571b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean					MSP_TWI_INT_STS_REG_OFFSET);
2581b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_writel(reason, data->iobase + MSP_TWI_INT_STS_REG_OFFSET);
2591b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2601b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	dev_dbg(&pmcmsptwi_adapter.dev, "Got interrupt 0x%08x\n", reason);
2611b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (!(reason & MSP_TWI_INT_STS_DONE))
2621b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		return IRQ_NONE;
2631b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2641b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	data->last_result = pmcmsptwi_get_result(reason);
2651b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	complete(&data->wait);
2661b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2671b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return IRQ_HANDLED;
2681b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
2691b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2701b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
2711b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Probe for and register the device and return 0 if there is one.
2721b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
2731b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic int __devinit pmcmsptwi_probe(struct platform_device *pldev)
2741b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
2751b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	struct resource *res;
2761b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	int rc = -ENODEV;
2771b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2781b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	/* get the static platform resources */
2791b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
2801b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (!res) {
2811b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_err(&pldev->dev, "IOMEM resource not found\n");
2821b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		goto ret_err;
2831b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
2841b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2851b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	/* reserve the memory region */
286c6ffddea36dd576b70dfbd10eb5d2b287b786dcaLinus Walleij	if (!request_mem_region(res->start, resource_size(res),
2871b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				pldev->name)) {
2881b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_err(&pldev->dev,
2891b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			"Unable to get memory/io address region 0x%08x\n",
2901b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			res->start);
2911b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		rc = -EBUSY;
2921b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		goto ret_err;
2931b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
2941b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
2951b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	/* remap the memory */
2961b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_data.iobase = ioremap_nocache(res->start,
297c6ffddea36dd576b70dfbd10eb5d2b287b786dcaLinus Walleij						resource_size(res));
2981b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (!pmcmsptwi_data.iobase) {
2991b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_err(&pldev->dev,
3001b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			"Unable to ioremap address 0x%08x\n", res->start);
3011b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		rc = -EIO;
3021b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		goto ret_unreserve;
3031b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
3041b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3051b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	/* request the irq */
3061b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
3071b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (pmcmsptwi_data.irq) {
3081b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
3094311051c358ad0e66b68934e7a33cf10ba533466Yong Zhang			IRQF_SHARED | IRQF_SAMPLE_RANDOM,
3101b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			pldev->name, &pmcmsptwi_data);
3111b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		if (rc == 0) {
3121b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			/*
3131b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			 * Enable 'DONE' interrupt only.
3141b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			 *
3151b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			 * If you enable all interrupts, you will get one on
3161b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			 * error and another when the operation completes.
3171b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			 * This way you only have to handle one interrupt,
3181b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			 * but you can still check all result flags.
3191b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			 */
3201b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			pmcmsptwi_writel(MSP_TWI_INT_STS_DONE,
3211b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean					pmcmsptwi_data.iobase +
3221b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean					MSP_TWI_INT_MSK_REG_OFFSET);
3231b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		} else {
3241b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			dev_warn(&pldev->dev,
3251b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				"Could not assign TWI IRQ handler "
3261b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				"to irq %d (continuing with poll)\n",
3271b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				pmcmsptwi_data.irq);
3281b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			pmcmsptwi_data.irq = 0;
3291b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		}
3301b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
3311b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3321b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	init_completion(&pmcmsptwi_data.wait);
3331b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	mutex_init(&pmcmsptwi_data.lock);
3341b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3351b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_set_clock_config(&pmcmsptwi_defclockcfg, &pmcmsptwi_data);
3361b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_set_twi_config(&pmcmsptwi_defcfg, &pmcmsptwi_data);
3371b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3381b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	printk(KERN_INFO DRV_NAME ": Registering MSP71xx I2C adapter\n");
3391b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3401b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_adapter.dev.parent = &pldev->dev;
3411b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	platform_set_drvdata(pldev, &pmcmsptwi_adapter);
3421b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data);
3431b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3441b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	rc = i2c_add_adapter(&pmcmsptwi_adapter);
3451b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (rc) {
3461b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_err(&pldev->dev, "Unable to register I2C adapter\n");
3471b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		goto ret_unmap;
3481b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
3491b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3501b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return 0;
3511b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3521b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanret_unmap:
3531b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	platform_set_drvdata(pldev, NULL);
3541b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (pmcmsptwi_data.irq) {
3551b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		pmcmsptwi_writel(0,
3561b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
3571b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
3581b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
3591b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3601b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	iounmap(pmcmsptwi_data.iobase);
3611b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3621b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanret_unreserve:
363c6ffddea36dd576b70dfbd10eb5d2b287b786dcaLinus Walleij	release_mem_region(res->start, resource_size(res));
3641b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3651b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanret_err:
3661b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return rc;
3671b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
3681b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3691b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
3701b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Release the device and return 0 if there is one.
3711b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
3721b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic int __devexit pmcmsptwi_remove(struct platform_device *pldev)
3731b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
3741b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	struct resource *res;
3751b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3761b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	i2c_del_adapter(&pmcmsptwi_adapter);
3771b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3781b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	platform_set_drvdata(pldev, NULL);
3791b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (pmcmsptwi_data.irq) {
3801b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		pmcmsptwi_writel(0,
3811b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
3821b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
3831b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
3841b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3851b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	iounmap(pmcmsptwi_data.iobase);
3861b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3871b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
388c6ffddea36dd576b70dfbd10eb5d2b287b786dcaLinus Walleij	release_mem_region(res->start, resource_size(res));
3891b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3901b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return 0;
3911b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
3921b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
3931b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
3941b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Polls the 'busy' register until the command is complete.
3951b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * NOTE: Assumes data->lock is held.
3961b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
3971b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic void pmcmsptwi_poll_complete(struct pmcmsptwi_data *data)
3981b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
3991b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	int i;
4001b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
4011b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	for (i = 0; i < MSP_MAX_POLL; i++) {
4021b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		u32 val = pmcmsptwi_readl(data->iobase +
4031b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean						MSP_TWI_BUSY_REG_OFFSET);
4041b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		if (val == 0) {
4051b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			u32 reason = pmcmsptwi_readl(data->iobase +
4061b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean						MSP_TWI_INT_STS_REG_OFFSET);
4071b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			pmcmsptwi_writel(reason, data->iobase +
4081b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean						MSP_TWI_INT_STS_REG_OFFSET);
4091b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			data->last_result = pmcmsptwi_get_result(reason);
4101b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			return;
4111b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		}
4121b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		udelay(MSP_POLL_DELAY);
4131b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
4141b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
4151b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	dev_dbg(&pmcmsptwi_adapter.dev, "Result: Poll timeout\n");
4161b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	data->last_result = MSP_TWI_XFER_TIMEOUT;
4171b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
4181b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
4191b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
4201b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Do the transfer (low level):
4211b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *   May use interrupt-driven or polling, depending on if an IRQ is
4221b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean *   presently registered.
4231b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * NOTE: Assumes data->lock is held.
4241b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
4251b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic enum pmcmsptwi_xfer_result pmcmsptwi_do_xfer(
4261b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			u32 reg, struct pmcmsptwi_data *data)
4271b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
4281b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	dev_dbg(&pmcmsptwi_adapter.dev, "Writing cmd reg 0x%08x\n", reg);
4291b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_writel(reg, data->iobase + MSP_TWI_CMD_REG_OFFSET);
4301b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (data->irq) {
4311b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		unsigned long timeleft = wait_for_completion_timeout(
4321b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean						&data->wait, MSP_IRQ_TIMEOUT);
4331b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		if (timeleft == 0) {
4341b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			dev_dbg(&pmcmsptwi_adapter.dev,
4351b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				"Result: IRQ timeout\n");
4361b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			complete(&data->wait);
4371b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			data->last_result = MSP_TWI_XFER_TIMEOUT;
4381b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		}
4391b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	} else
4401b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		pmcmsptwi_poll_complete(data);
4411b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
4421b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return data->last_result;
4431b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
4441b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
4451b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
4461b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Helper routine, converts 'pmctwi_cmd' struct to register format
4471b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
4481b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic inline u32 pmcmsptwi_cmd_to_reg(const struct pmcmsptwi_cmd *cmd)
4491b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
4501b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return ((cmd->type & 0x3) << 8) |
4511b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		(((cmd->write_len - 1) & 0x7) << 4) |
4521b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		((cmd->read_len - 1) & 0x7);
4531b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
4541b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
4551b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
4561b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Do the transfer (high level)
4571b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
4581b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
4591b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			struct pmcmsptwi_cmd *cmd,
4601b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			struct pmcmsptwi_data *data)
4611b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
4621b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	enum pmcmsptwi_xfer_result retval;
4631b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
4641b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if ((cmd->type == MSP_TWI_CMD_WRITE && cmd->write_len == 0) ||
4651b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	    (cmd->type == MSP_TWI_CMD_READ && cmd->read_len == 0) ||
4661b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	    (cmd->type == MSP_TWI_CMD_WRITE_READ &&
4671b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	    (cmd->read_len == 0 || cmd->write_len == 0))) {
4681b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_err(&pmcmsptwi_adapter.dev,
4691b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			"%s: Cannot transfer less than 1 byte\n",
47008882d20932224d5c4500a855a2f4b1216e5f836Harvey Harrison			__func__);
4711b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		return -EINVAL;
4721b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
4731b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
4741b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (cmd->read_len > MSP_MAX_BYTES_PER_RW ||
4751b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	    cmd->write_len > MSP_MAX_BYTES_PER_RW) {
4761b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_err(&pmcmsptwi_adapter.dev,
4771b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			"%s: Cannot transfer more than %d bytes\n",
47808882d20932224d5c4500a855a2f4b1216e5f836Harvey Harrison			__func__, MSP_MAX_BYTES_PER_RW);
4791b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		return -EINVAL;
4801b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
4811b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
4821b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	mutex_lock(&data->lock);
4831b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	dev_dbg(&pmcmsptwi_adapter.dev,
4841b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		"Setting address to 0x%04x\n", cmd->addr);
4851b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	pmcmsptwi_writel(cmd->addr, data->iobase + MSP_TWI_ADD_REG_OFFSET);
4861b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
4871b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (cmd->type == MSP_TWI_CMD_WRITE ||
4881b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	    cmd->type == MSP_TWI_CMD_WRITE_READ) {
489d9d38ca07d5187b3082074934e73f014f5d31409Harvey Harrison		u64 tmp = be64_to_cpup((__be64 *)cmd->write_data);
4901b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		tmp >>= (MSP_MAX_BYTES_PER_RW - cmd->write_len) * 8;
4911b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_dbg(&pmcmsptwi_adapter.dev, "Writing 0x%016llx\n", tmp);
4921b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		pmcmsptwi_writel(tmp & 0x00000000ffffffffLL,
4931b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				data->iobase + MSP_TWI_DAT_0_REG_OFFSET);
4941b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		if (cmd->write_len > 4)
4951b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			pmcmsptwi_writel(tmp >> 32,
4961b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				data->iobase + MSP_TWI_DAT_1_REG_OFFSET);
4971b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
4981b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
4991b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	retval = pmcmsptwi_do_xfer(pmcmsptwi_cmd_to_reg(cmd), data);
5001b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (retval != MSP_TWI_XFER_OK)
5011b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		goto xfer_err;
5021b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5031b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (cmd->type == MSP_TWI_CMD_READ ||
5041b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	    cmd->type == MSP_TWI_CMD_WRITE_READ) {
5051b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		int i;
5061b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		u64 rmsk = ~(0xffffffffffffffffLL << (cmd->read_len * 8));
5071b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		u64 tmp = (u64)pmcmsptwi_readl(data->iobase +
5081b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean					MSP_TWI_DAT_0_REG_OFFSET);
5091b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		if (cmd->read_len > 4)
5101b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			tmp |= (u64)pmcmsptwi_readl(data->iobase +
5111b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean					MSP_TWI_DAT_1_REG_OFFSET) << 32;
5121b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		tmp &= rmsk;
5131b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_dbg(&pmcmsptwi_adapter.dev, "Read 0x%016llx\n", tmp);
5141b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5151b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		for (i = 0; i < cmd->read_len; i++)
5161b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			cmd->read_data[i] = tmp >> i;
5171b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
5181b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5191b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanxfer_err:
5201b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	mutex_unlock(&data->lock);
5211b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5221b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return retval;
5231b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
5241b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5251b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/* -- Algorithm functions -- */
5261b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5271b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/*
5281b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean * Sends an i2c command out on the adapter
5291b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean */
5301b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
5311b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				struct i2c_msg *msg, int num)
5321b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
5331b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	struct pmcmsptwi_data *data = i2c_get_adapdata(adap);
5341b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	struct pmcmsptwi_cmd cmd;
5351b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	struct pmcmsptwi_cfg oldcfg, newcfg;
5361b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	int ret;
5371b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5381b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (num > 2) {
5391b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_dbg(&adap->dev, "%d messages unsupported\n", num);
5401b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		return -EINVAL;
5411b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	} else if (num == 2) {
5421b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		/* Check for a dual write-then-read command */
5431b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		struct i2c_msg *nextmsg = msg + 1;
5441b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		if (!(msg->flags & I2C_M_RD) &&
5451b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		    (nextmsg->flags & I2C_M_RD) &&
5461b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		    msg->addr == nextmsg->addr) {
5471b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			cmd.type = MSP_TWI_CMD_WRITE_READ;
5481b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			cmd.write_len = msg->len;
5491b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			cmd.write_data = msg->buf;
5501b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			cmd.read_len = nextmsg->len;
5511b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			cmd.read_data = nextmsg->buf;
5521b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		} else {
5531b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			dev_dbg(&adap->dev,
5541b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean				"Non write-read dual messages unsupported\n");
5551b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean			return -EINVAL;
5561b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		}
5571b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	} else if (msg->flags & I2C_M_RD) {
5581b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		cmd.type = MSP_TWI_CMD_READ;
5591b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		cmd.read_len = msg->len;
5601b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		cmd.read_data = msg->buf;
5611b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		cmd.write_len = 0;
5621b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		cmd.write_data = NULL;
5631b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	} else {
5641b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		cmd.type = MSP_TWI_CMD_WRITE;
5651b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		cmd.read_len = 0;
5661b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		cmd.read_data = NULL;
5671b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		cmd.write_len = msg->len;
5681b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		cmd.write_data = msg->buf;
5691b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
5701b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5711b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (msg->len == 0) {
5721b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		dev_err(&adap->dev, "Zero-byte messages unsupported\n");
5731b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		return -EINVAL;
5741b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
5751b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5761b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	cmd.addr = msg->addr;
5771b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5781b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (msg->flags & I2C_M_TEN) {
5791b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		pmcmsptwi_get_twi_config(&newcfg, data);
5801b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		memcpy(&oldcfg, &newcfg, sizeof(oldcfg));
5811b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5821b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		/* Set the special 10-bit address flag */
5831b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		newcfg.add10 = 1;
5841b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5851b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		pmcmsptwi_set_twi_config(&newcfg, data);
5861b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
5871b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5881b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	/* Execute the command */
5891b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	ret = pmcmsptwi_xfer_cmd(&cmd, data);
5901b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
5911b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (msg->flags & I2C_M_TEN)
5921b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		pmcmsptwi_set_twi_config(&oldcfg, data);
5931b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
594898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches	dev_dbg(&adap->dev, "I2C %s of %d bytes %s\n",
595898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches		(msg->flags & I2C_M_RD) ? "read" : "write", msg->len,
596898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches		(ret == MSP_TWI_XFER_OK) ? "succeeded" : "failed");
597898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches
5981b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	if (ret != MSP_TWI_XFER_OK) {
5991b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		/*
6001b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		 * TODO: We could potentially loop and retry in the case
6011b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		 * of MSP_TWI_XFER_TIMEOUT.
6021b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		 */
6031b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		return -1;
6041b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	}
6051b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
6061b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return 0;
6071b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
6081b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
6091b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
6101b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean{
6111b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
6121b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
6131b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
6141b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean}
6151b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
6161b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean/* -- Initialization -- */
6171b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
6181b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic struct i2c_algorithm pmcmsptwi_algo = {
6191b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.master_xfer	= pmcmsptwi_master_xfer,
6201b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.functionality	= pmcmsptwi_i2c_func,
6211b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
6221b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
6231b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic struct i2c_adapter pmcmsptwi_adapter = {
6241b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.owner		= THIS_MODULE,
6253401b2fff38fbb8b73ea6bcc69a8370ae5d2a7a0Jean Delvare	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
6261b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.algo		= &pmcmsptwi_algo,
6271b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.name		= DRV_NAME,
6281b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
6291b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
6301b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jeanstatic struct platform_driver pmcmsptwi_driver = {
6311b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.probe  = pmcmsptwi_probe,
6321b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	.remove	= __devexit_p(pmcmsptwi_remove),
6335ee403f584a67fb8725cca4d55218925b9295528Yoann Padioleau	.driver = {
6341b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		.name	= DRV_NAME,
6351b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean		.owner	= THIS_MODULE,
6361b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean	},
6371b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean};
6381b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
639a3664b51c783aaa0dde1c95334d1a670d6d54590Axel Linmodule_platform_driver(pmcmsptwi_driver);
6401b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-Jean
6411b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-JeanMODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver");
6421b144df1d7d69d6dd3394205933c8951dd8b6784Marc St-JeanMODULE_LICENSE("GPL");
643a3664b51c783aaa0dde1c95334d1a670d6d54590Axel LinMODULE_ALIAS("platform:" DRV_NAME);
644