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

📄 i2c-bfin-twi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * drivers/i2c/busses/i2c-bfin-twi.c * * Description: Driver for Blackfin Two Wire Interface * * Author:      sonicz  <sonic.zhang@analog.com> * * Copyright (c) 2005-2007 Analog Devices, Inc. * * 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 * the Free Software Foundation; either version 2 of the 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 warranty 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/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/i2c.h>#include <linux/mm.h>#include <linux/timer.h>#include <linux/spinlock.h>#include <linux/completion.h>#include <linux/interrupt.h>#include <linux/platform_device.h>#include <asm/blackfin.h>#include <asm/irq.h>#define POLL_TIMEOUT       (2 * HZ)/* SMBus mode*/#define TWI_I2C_MODE_STANDARD		0x01#define TWI_I2C_MODE_STANDARDSUB	0x02#define TWI_I2C_MODE_COMBINED		0x04struct bfin_twi_iface {	int			irq;	spinlock_t		lock;	char			read_write;	u8			command;	u8			*transPtr;	int			readNum;	int			writeNum;	int			cur_mode;	int			manual_stop;	int			result;	int			timeout_count;	struct timer_list	timeout_timer;	struct i2c_adapter	adap;	struct completion	complete;};static struct bfin_twi_iface twi_iface;static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface){	unsigned short twi_int_status = bfin_read_TWI_INT_STAT();	unsigned short mast_stat = bfin_read_TWI_MASTER_STAT();	if (twi_int_status & XMTSERV) {		/* Transmit next data */		if (iface->writeNum > 0) {			bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));			iface->writeNum--;		}		/* start receive immediately after complete sending in		 * combine mode.		 */		else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()				| MDIR | RSTART);		} else if (iface->manual_stop)			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()				| STOP);		SSYNC();		/* Clear status */		bfin_write_TWI_INT_STAT(XMTSERV);		SSYNC();	}	if (twi_int_status & RCVSERV) {		if (iface->readNum > 0) {			/* Receive next data */			*(iface->transPtr) = bfin_read_TWI_RCV_DATA8();			if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {				/* Change combine mode into sub mode after				 * read first data.				 */				iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;				/* Get read number from first byte in block				 * combine mode.				 */				if (iface->readNum == 1 && iface->manual_stop)					iface->readNum = *iface->transPtr + 1;			}			iface->transPtr++;			iface->readNum--;		} else if (iface->manual_stop) {			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()				| STOP);			SSYNC();		}		/* Clear interrupt source */		bfin_write_TWI_INT_STAT(RCVSERV);		SSYNC();	}	if (twi_int_status & MERR) {		bfin_write_TWI_INT_STAT(MERR);		bfin_write_TWI_INT_MASK(0);		bfin_write_TWI_MASTER_STAT(0x3e);		bfin_write_TWI_MASTER_CTL(0);		SSYNC();		iface->result = -1;		/* if both err and complete int stats are set, return proper		 * results.		 */		if (twi_int_status & MCOMP) {			bfin_write_TWI_INT_STAT(MCOMP);			bfin_write_TWI_INT_MASK(0);			bfin_write_TWI_MASTER_CTL(0);			SSYNC();			/* If it is a quick transfer, only address bug no data,			 * not an err, return 1.			 */			if (iface->writeNum == 0 && (mast_stat & BUFRDERR))				iface->result = 1;			/* If address not acknowledged return -1,			 * else return 0.			 */			else if (!(mast_stat & ANAK))				iface->result = 0;		}		complete(&iface->complete);		return;	}	if (twi_int_status & MCOMP) {		bfin_write_TWI_INT_STAT(MCOMP);		SSYNC();		if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {			if (iface->readNum == 0) {				/* set the read number to 1 and ask for manual				 * stop in block combine mode				 */				iface->readNum = 1;				iface->manual_stop = 1;				bfin_write_TWI_MASTER_CTL(					bfin_read_TWI_MASTER_CTL()					| (0xff << 6));			} else {				/* set the readd number in other				 * combine mode.				 */				bfin_write_TWI_MASTER_CTL(					(bfin_read_TWI_MASTER_CTL() &					(~(0xff << 6))) |					( iface->readNum << 6));			}			/* remove restart bit and enable master receive */			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() &				~RSTART);			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |				MEN | MDIR);			SSYNC();		} else {			iface->result = 1;			bfin_write_TWI_INT_MASK(0);			bfin_write_TWI_MASTER_CTL(0);			SSYNC();			complete(&iface->complete);		}	}}/* Interrupt handler */static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id){	struct bfin_twi_iface *iface = dev_id;	unsigned long flags;	spin_lock_irqsave(&iface->lock, flags);	del_timer(&iface->timeout_timer);	bfin_twi_handle_interrupt(iface);	spin_unlock_irqrestore(&iface->lock, flags);	return IRQ_HANDLED;}static void bfin_twi_timeout(unsigned long data){	struct bfin_twi_iface *iface = (struct bfin_twi_iface *)data;	unsigned long flags;	spin_lock_irqsave(&iface->lock, flags);	bfin_twi_handle_interrupt(iface);	if (iface->result == 0) {		iface->timeout_count--;		if (iface->timeout_count > 0) {			iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;			add_timer(&iface->timeout_timer);		} else {			iface->result = -1;			complete(&iface->complete);		}	}	spin_unlock_irqrestore(&iface->lock, flags);}/* * Generic i2c master transfer entrypoint */static int bfin_twi_master_xfer(struct i2c_adapter *adap,				struct i2c_msg *msgs, int num){	struct bfin_twi_iface *iface = adap->algo_data;	struct i2c_msg *pmsg;	int i, ret;	int rc = 0;	if (!(bfin_read_TWI_CONTROL() & TWI_ENA))		return -ENXIO;	while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {		yield();	}	ret = 0;	for (i = 0; rc >= 0 && i < num; i++) {		pmsg = &msgs[i];		if (pmsg->flags & I2C_M_TEN) {			dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr "				"not supported !\n");			rc = -EINVAL;			break;		}		iface->cur_mode = TWI_I2C_MODE_STANDARD;		iface->manual_stop = 0;		iface->transPtr = pmsg->buf;		iface->writeNum = iface->readNum = pmsg->len;		iface->result = 0;		iface->timeout_count = 10;		/* Set Transmit device address */		bfin_write_TWI_MASTER_ADDR(pmsg->addr);		/* FIFO Initiation. Data in FIFO should be		 *  discarded before start a new operation.		 */		bfin_write_TWI_FIFO_CTL(0x3);		SSYNC();		bfin_write_TWI_FIFO_CTL(0);		SSYNC();		if (pmsg->flags & I2C_M_RD)			iface->read_write = I2C_SMBUS_READ;		else {			iface->read_write = I2C_SMBUS_WRITE;			/* Transmit first data */			if (iface->writeNum > 0) {				bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));				iface->writeNum--;				SSYNC();			}		}		/* clear int stat */		bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);		/* Interrupt mask . Enable XMT, RCV interrupt */		bfin_write_TWI_INT_MASK(MCOMP | MERR |			((iface->read_write == I2C_SMBUS_READ)?			RCVSERV : XMTSERV));		SSYNC();		if (pmsg->len > 0 && pmsg->len <= 255)			bfin_write_TWI_MASTER_CTL(pmsg->len << 6);		else if (pmsg->len > 255) {			bfin_write_TWI_MASTER_CTL(0xff << 6);			iface->manual_stop = 1;		} else			break;		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;		add_timer(&iface->timeout_timer);		/* Master enable */		bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |			((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |			((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));		SSYNC();		wait_for_completion(&iface->complete);		rc = iface->result;		if (rc == 1)			ret++;		else if (rc == -1)			break;	}	return ret;}/* * SMBus type transfer entrypoint */int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,

⌨️ 快捷键说明

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