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