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