⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c-mp200.c

📁 The attached file is the driver of I2C
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  File Name	    : linux/drivers/i2c/busses/i2c-mp200.c *  Function	    : i2c *  Release Version : Ver 1.01 *  Release Date    : 2006/03/21 * *  Copyright (C) NEC Electronics Corporation 2005-2006 * * *  This program is free software;you can redistribute it and/or modify it under the terms of *  the GNU General Public License as published by Free Softwere Foundation; either version 2 *  of License, or (at your option) any later version. * *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *  without even the implied warrnty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *  See the GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License along with this program; *  If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, *  MA 02111-1307, USA. * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/version.h>#include <linux/i2c.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/device.h>#include <linux/moduleparam.h>#include <linux/interrupt.h>#include <linux/ioctl.h>#include "i2c-mp200.h"/* ----- global defines ----------------------------------------------- */#define DEFAULT_CLOCK	    100000	/* default 100KHz */#define MAX_MESSAGES	    65536	/* max number of messages *//* ----- global variables --------------------------------------------- */static wait_queue_head_t i2c_wait;static volatile int i2c_pending;static spinlock_t i2c_lock = SPIN_LOCK_UNLOCKED;static spinlock_t i2c_irq_lock = SPIN_LOCK_UNLOCKED;static int i2c_arbls;/* ----- module parameters -------------------------------------------- */static int clock;static int irq = INT_IIC;	/* polling mode if irq = 0 */static int i2c_scan = 0;	/* have a look at what's hanging 'round *//* ----- Forward declarations ----------------------------------------- */static int mp200_i2c_xfer(struct i2c_adapter *, struct i2c_msg[], int);static int mp200_i2c_rxbytes(struct i2c_adapter *, struct i2c_msg *, int);static int mp200_i2c_suspend(struct device *dev, u32 state, u32 level);static int mp200_i2c_resume(struct device *dev, u32 level);/* ----- Utility functions -------------------------------------------- */static void mp200_setup_iiccl0_iicx0(struct i2c_adapter *adap){	u16 bit = 0x0;	i2c_ctrl_t *ctrl = (i2c_ctrl_t *) adap->algo_data;#ifdef I2C_DEBUG	printk(KERN_INFO	       "mp200_setup_iiccl0_iicx0(): IICCL0: %04x, IICX0: %04x\n",	       inw(I2C_REG_IICCL0), inw(I2C_REG_IICX0));#endif	/* mode */	if (ctrl->smc == I2C_SMC_HIGH_SPEED) {		/* High-speed mode(Maximum transfer rate 250kbit/s) */		bit |= I2C_BIT_SMC0;	}	/* else Nomal mode(Maximum transfer rate 70kbit/s)(default) */	/* digital filter */	if (ctrl->dfc == I2C_DFC_ON) {		/* digital filter ON */		bit |= I2C_BIT_DFC0;	}	/* else digital filter OFF */	/* clock speed */	switch (ctrl->clo) {	case I2C_CLO_4:		/* if standard mode,   6.4MHz support		   if high-speed mode, 6.4MHz support */		bit |= I2C_BIT_CLO1;		bit |= I2C_BIT_CLO0;		break;	case I2C_CLO_3:		/* if standard mode,   4.19MHz <= Fxx <= 8.38MHz		   if high-speed mode, 4.00MHz <= Fxx <= 8.38MHz */		bit |= I2C_BIT_CLO1;		break;	case I2C_CLO_2:		/* if standard mode,   4.19MHz <= Fxx <= 8.38MHz		   if high-speed mode, 4.00MHz <= Fxx <= 8.38MHz */		bit |= I2C_BIT_CLO0;		break;	case I2C_CLO_1:	default:		/* if standard mode,   2.00MHz <= Fxx <= 4.19MHz (default)		   if high-speed mode, 4.00MHz <= Fxx <= 8.38MHz */		break;	}	outw(bit, I2C_REG_IICCL0);	if (ctrl->clx == I2C_CLX_HIGH) {		outw(I2C_BIT_CLX0, I2C_REG_IICX0);	} else {		outw(0x0, I2C_REG_IICX0);	}#ifdef I2C_DEBUG	printk(KERN_INFO	       "mp200_setup_iiccl0_iicx0(): IICCL0: %04x, IICX0: %04x\n",	       inw(I2C_REG_IICCL0), inw(I2C_REG_IICX0));#endif}static void mp200_init(struct i2c_adapter *adap){	if (inw(I2C_REG_IICC0) & I2C_BIT_IICE0) {		spin_lock(&i2c_lock);		outw(0, I2C_REG_IICC0);		spin_unlock(&i2c_lock);		mdelay(10);	}	mp200_setup_iiccl0_iicx0(adap);	outw((I2C_BIT_STCEN | I2C_BIT_IICRSV), I2C_REG_IICF0);	spin_lock(&i2c_lock);	outw((I2C_BIT_IICE0 | I2C_BIT_WTIM0), I2C_REG_IICC0);	spin_unlock(&i2c_lock);#ifdef I2C_DEBUG	printk(KERN_INFO "mp200_init(): con: %04x, stat: %04x\n",	       inw(I2C_REG_IICC0), inw(I2C_REG_IICSE0));#endif}/* * Waiting on Bus Busy */static int mp200_i2c_wait_for_bb(struct i2c_adapter *adap){	int timeout = adap->timeout;	while ((inw(I2C_REG_IICF0) & I2C_BIT_IICBSY) && timeout--) {		/* If irq is setup properly, wait for interrupt.		 */		schedule_timeout(1);	}	if (timeout <= 0) {		printk(KERN_INFO		       "mp200_i2c_wait_for_bb(): Timeout, I2C bus is busy\n");	}	return (timeout <= 0);}/* * After we issue a transaction on the mp200 I2C bus, this function * is called. It puts this process to sleep until we get an interrupt from * the controller telling us that the transaction we requested is complete. * pin = Pending Interrupt Not */static int mp200_i2c_wait_for_pin(struct i2c_adapter *adap, u16 * status){	int retries = adap->retries;	int timeout;	int pending = 0;	DECLARE_WAITQUEUE(wait, current);	if (irq) {		add_wait_queue(&i2c_wait, &wait);	}	do {		/* Put the process to sleep. This process will be awakened		 * when either the the I2C peripheral interrupts or the		 * timeout expires. 		 */		if (irq) {			timeout = adap->timeout;			current->state = TASK_INTERRUPTIBLE;			spin_lock_irq(&i2c_irq_lock);			pending = i2c_pending;			i2c_pending = 0;			spin_unlock_irq(&i2c_irq_lock);			*status = inw(I2C_REG_IICSE0);#ifdef I2C_DEBUG			printk(KERN_INFO			       "mp200_i2c_wait_for_pin(): con: %04x, stat: %04x\n",			       inw(I2C_REG_IICC0), *status);#endif			if (pending) {				break;			}			schedule_timeout(timeout);		} else {			timeout = adap->timeout * 10000;			do {				udelay(100000 / clock);				if (MP200_I2C_INTC_MST_35 &				    inw(MP200_I2C_INTC_IT0_RAW1)) {					outw(MP200_I2C_INTC_MST_35,					     MP200_I2C_INTC_IT0_IIR1);					pending = 1;					break;				}			} while (--timeout);			*status = inw(I2C_REG_IICSE0);#ifdef I2C_DEBUG			printk(KERN_INFO			       "mp200_i2c_wait_for_pin(): con: %04x, stat: %04x\n",			       inw(I2C_REG_IICC0), *status);#endif			if (pending) {				break;			}		}	} while ((*status & I2C_BIT_MSTS0) && retries--);	if (irq) {		current->state = TASK_RUNNING;		remove_wait_queue(&i2c_wait, &wait);	}	if (retries <= 0) {		printk(KERN_INFO "mp200_i2c_wait_for_pin(): Timeout\n");	}	return (retries <= 0) ? -1 : 0;}/* * Sanity check for the adapter hardware - check the reaction of * the bus lines only if it seems to be idle. * * Scan the I2C bus for valid 7 bit addresses * (ie things that ACK on 1byte read) * if i2c_debug is off we print everything on one line. * if i2c_debug is on we do a newline per print so we don't * clash too much with printf's in the other functions. * TODO: check for 10-bit mode and never run as a slave. */static int mp200_i2c_scan_bus(struct i2c_adapter *adap){	int found = 0;	int i;	struct i2c_msg msg;	char data[1];	printk(KERN_INFO "mp200_i2c_scan_bus(): "	       "%s: scanning for active I2C devices on the bus.", adap->name);	for (i = 1; i < 0x7f; i++) {		if ((inw(I2C_REG_SVA0) >> 9) == i) {			continue;		}		msg.addr = i;		msg.buf = data;		msg.len = 0;		msg.flags = I2C_M_RD;		if (mp200_i2c_xfer(adap, &msg, 1) == 0) {			printk(" 0x%02x", i);			found++;		}	}	if (found) {		printk("\n");	} else {		printk(" Found nothing.\n");	}	return found;}/* * Prepare controller for a transaction and call mp200_i2c_rxbytes * to do the work. */static intmp200_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num){	int i;	int status = 0;#ifdef I2C_DEBUG	printk(KERN_INFO "mp200_i2c_xfer(): msgs: %d\n", num);#endif	if ((num < 1) || (num > MAX_MESSAGES)) {		return (status = -EINVAL);	}	/* Check for valid parameters in messages */	for (i = 0; i < num; i++) {		if (&msgs[i] == NULL) {			return (status = -EINVAL);		}		if (msgs[i].buf == NULL) {			return (status = -EINVAL);		}	}	if ((status = mp200_i2c_wait_for_bb(adap))) {		printk(KERN_INFO		       "mp200_i2c_xfer(): %s: Timeout waiting for busy bus.\n",		       adap->name);		if (!(inw(I2C_REG_IICSE0) & I2C_BIT_MSTS0)) {			/* We're not the master but the bus is busy. */			return (status = -EBUSY);		}		/* This shouldn't happen but we're already the master.		 * So try to park the bus before starting transaction.		 */		printk(KERN_INFO "mp200_i2c_xfer(): %s is already active. "		       "Attempting to Reset module...\n", adap->name);		/* stop condition trigger */		spin_lock(&i2c_lock);		outw((inw(I2C_REG_IICC0) | I2C_BIT_SPT0), I2C_REG_IICC0);		spin_unlock(&i2c_lock);		if ((status = mp200_i2c_wait_for_bb(adap))) {			/* Eew, still busy, try resetting to unwedge... */			mp200_init(adap);			if (mp200_i2c_wait_for_bb(adap)) {				printk(KERN_INFO "mp200_i2c_xfer(): "				       "%s reset failed - I2C bus is wedged.\n",				       adap->name);				/* Just give up... */				return (status = -EREMOTEIO);			}		}	}	for (i = 0; i < num; i++) {#ifdef I2C_DEBUG		printk(KERN_INFO		       "mp200_i2c_xfer(): msg: %d, addr: 0x%04x, len: %d, "		       "flags: 0x%x\n", i, msgs[i].addr, msgs[i].len,		       msgs[i].flags);#endif		status = mp200_i2c_rxbytes(adap, &msgs[i], (i == (num - 1)));#ifdef I2C_DEBUG		printk(KERN_INFO "mp200_i2c_xfer(): status loop: %d\n", status);#endif		if (status != msgs[i].len) {			break;		}	}	/* REVISIT: This is silly but fixup status to return expected results	 */	if ((status >= 0) && (num > 1)) {		status = num;	}#ifdef I2C_DEBUG	printk(KERN_INFO "mp200_i2c_xfer(): status: %d\n", status);#endif	return status;}/* * Low level master read/write transaction. */static intmp200_i2c_rxbytes(struct i2c_adapter *adap, struct i2c_msg *msg, int stop){	u16 status;	u8 data = 0;	int count = 0;	int recv_len = 0;	/* I2C_FUNC_SMBUS_READ_BLOCK_DATA coresponded */	if (msg->flags & I2C_M_RECV_LEN) {		recv_len = 1;	}#ifdef I2C_DEBUG	printk(KERN_INFO "mp200_i2c_rxbytes(): addr: 0x%04x, len: %d, "	       "flags: 0x%x, stop: %d\n", msg->addr, msg->len, msg->flags,	       stop);#endif	if (irq) {		spin_lock_irq(&i2c_irq_lock);		i2c_pending = 0;		spin_unlock_irq(&i2c_irq_lock);	}	spin_lock(&i2c_lock);	outw((inw(I2C_REG_IICC0) | I2C_BIT_STT0), I2C_REG_IICC0);	spin_unlock(&i2c_lock);	/* 6us wait */	udelay(MP200_I2C_WAIT);#ifdef I2C_DEBUG	printk(KERN_INFO "mp200_i2c_rxbytes(): con: %04x, flg: %04x\n",	       inw(I2C_REG_IICC0), inw(I2C_REG_IICF0));#endif	if ((inw(I2C_REG_IICF0) & I2C_BIT_STCF) ||	    !(inw(I2C_REG_IICSE0) & I2C_BIT_MSTS0)) {		return -EBUSY;	}#ifdef I2C_DEBUG	printk(KERN_INFO "mp200_i2c_rxbytes(): addr: %04x, flags: %04x\n",	       msg->addr, msg->flags);	printk(KERN_INFO "mp200_i2c_rxbytes(): addrdir: %04x\n",	       (msg->addr << I2C_DIR_SHIFT)	       | ((msg->flags & I2C_M_RD) ? 1 : 0));#endif	outw((msg->addr << I2C_DIR_SHIFT) | ((msg->flags & I2C_M_RD) ? 1 : 0),	     I2C_REG_IIC0);	if (mp200_i2c_wait_for_pin(adap, &status)) {		/* Timeout */		mp200_init(adap);		return -EREMOTEIO;	}	if (status & I2C_BIT_ALD0) {		i2c_arbls += 1;		/* need to reset for clear arbitration detect */		mp200_init(adap);		return -EREMOTEIO;	} else if (status & (I2C_BIT_EXC0 | I2C_BIT_COI0)		   || !(status & I2C_BIT_MSTS0)) {		/* unsupported slave mode and 10bit address mode */		mp200_init(adap);		return -EREMOTEIO;	} else if (!(status & I2C_BIT_TRC0)) {		if (!(msg->flags & I2C_M_RD)) {			printk(KERN_INFO			       "mp200_i2c_rxbytes(): %s r/w hardware fault.\n",			       adap->name);			mp200_init(adap);			return -EREMOTEIO;		}		if (!(status & I2C_BIT_ACKD0)) {			printk(KERN_INFO			       "mp200_i2c_rxbytes(): %s r/w hardware fault.\n",			       adap->name);			/* stop condition trigger */			spin_lock(&i2c_lock);			outw((inw(I2C_REG_IICC0) | I2C_BIT_SPT0),			     I2C_REG_IICC0);			spin_unlock(&i2c_lock);			return -EREMOTEIO;		}		spin_lock(&i2c_lock);		outw((inw(I2C_REG_IICC0) & ~I2C_BIT_WTIM0) | I2C_BIT_ACKE0 |		     I2C_BIT_WREL0, I2C_REG_IICC0);		spin_unlock(&i2c_lock);		if (mp200_i2c_wait_for_pin(adap, &status)) {			/* Timeout */			mp200_init(adap);			return -EREMOTEIO;		}	}	do {		if (status & I2C_BIT_ALD0) {			i2c_arbls += 1;			/* need to reset for clear arbitration detect */			mp200_init(adap);			return -EREMOTEIO;		} else if (status & (I2C_BIT_EXC0 | I2C_BIT_COI0)			   || !(status & I2C_BIT_MSTS0)) {			/* unsupported slave mode and 10bit address mode */			mp200_init(adap);			return -EREMOTEIO;		} else if (!(status & I2C_BIT_TRC0)) {			if (!(msg->flags & I2C_M_RD)) {				printk(KERN_INFO				       "mp200_i2c_rxbytes(): %s r/w hardware fault.\n",				       adap->name);				mp200_init(adap);				return -EREMOTEIO;			}			if (count == msg->len) {				break;			}			/* read data */			data = inw(I2C_REG_IIC0);#ifdef I2C_DEBUG			printk(KERN_INFO			       "mp200_i2c_rxbytes(): read: data: %04x\n", data);#endif			if (recv_len) {				recv_len = 0;				/* [Count] should be between 1 and 31 (I2C_SMBUS_BLOCK_MAX - 1). */				if (0 < data && data < I2C_SMBUS_BLOCK_MAX) {					/* plus one for [Count] itself */					msg->len = data + 1;				} else {					printk(KERN_INFO "mp200_i2c_rxbytes(): "					       "%s : bad block count (%d).\n",					       adap->name, data);					msg->len = 1;					recv_len = -1;				}			}			if (count < msg->len) {				msg->buf[count++] = data;			} else if (msg->len != 0) {				/* Er, h/w and/or s/w error? */				printk(KERN_INFO				       "mp200_i2c_rxbytes(): %s rcv count mismatch.\n",				       adap->name);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -