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

📄 i2c-imx.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************** *	Copyright (C) 2002 Motorola GSG-China * *	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. * *  File Name   : i2c-imx.c *  Description : Implementation of i2c Adapter/Algorithm Driver *  Author      : Motorola GSG-China *  History     : 2002/2/7 use msgs[] *                2004/3/3 port to linux kernel v2.6.x for IMX *                         adding  cpu- and bus-usage optimization *                         (by T.Koschorrek, http://www.synertronixx.de/) * *  Additional Description (T. Koschorrek) : *  - to enable debug messages just #define DEBUG *  - this module supports cpu- and bus-usage-optimization for ad-converter *    'ads1100' and for serial access timekeeper 'm41t00' *  - support for other chips is NOT yet implemented (you can implement other *    chips by adding two lines in the init-function (i2c_imx_init) *  - this module can be accessed via the i2c-dev interface from user-space *  - access from kernel-space is not supported (add this if you want) * ******************************************************************************//****************************************************************************** * global stuff ******************************************************************************//*----------------------------------------------------------------------------- * included header files *----------------------------------------------------------------------------*/#include <linux/i2c.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/spinlock.h>#include <asm/arch/irqs.h>#include <asm/arch/hardware.h>#include <asm/leds.h>/*----------------------------------------------------------------------------- * defines *----------------------------------------------------------------------------*/#define DEFAULT_FREQ 	   0x16#define I2C_IO_CHANGE_FREQ 0xaa#define I2C_IO_GET_STATUS  0xab#define I2C_IMX_TIMEOUT    5000000/* #define DEBUG *//*----------------------------------------------------------------------------- * function declarations *----------------------------------------------------------------------------*/static int i2c_imx_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[ ],			int num);static int i2c_imx_smbus(struct i2c_adapter * adapter, u16 addr,			 unsigned short flags, char read_write, u8 command,			 int size, union i2c_smbus_data * data);static int i2c_imx_ioctl(struct i2c_adapter * adapter, unsigned int cmd,			 unsigned long arg);/*----------------------------------------------------------------------------- * structs for i2c *----------------------------------------------------------------------------*//* algorithm structure for handling with i2c-bus */static struct i2c_algorithm i2c_imx_algorithm = {	/* name: */		"IMX I2C algorithm",	/* id: */		I2C_ALGO_BIT,	/* master_xfer: */	i2c_imx_xfer,	/* smbus_xfer: */	i2c_imx_smbus,	/* slave_send: */	NULL,	/* slave_recv: */	NULL,	/* algo_control: */	i2c_imx_ioctl,	/* functionality: */	NULL};/* adapter structure to the i2c-bus */static struct i2c_adapter i2c_imx_adapter = {	/* name: */           .name = "IMX I2C adapter",	/* i2c_algorithm: */  .algo = &i2c_imx_algorithm,	/* class: */          .class = I2C_ADAP_CLASS_SMBUS,	/* ID: */             .id = I2C_ALGO_BIT | I2C_HW_B_SER,};/* imx-registers for i2c */struct i2c_imx_i2creg {  	volatile u32 iadr;	volatile u32 ifdr;	volatile u32 i2cr;	volatile u32 i2sr;	volatile u32 i2dr;};struct i2c_imx_i2cslp {	unsigned long jif;	unsigned int slp_time;};/*----------------------------------------------------------------------------- * variables *----------------------------------------------------------------------------*/static struct i2c_imx_i2creg *i2c_imx_reg = (struct i2c_imx_i2creg *)IMX_I2C_BASE;static spinlock_t i2c_imx_irqlock = SPIN_LOCK_UNLOCKED;static int i2c_imx_irq_ok;static int i2c_imx_i2sr;static struct i2c_imx_i2cslp i2c_imx_slp[128];#ifdef DEBUGstatic int i2c_imx_errs_rxack = 0;static int i2c_imx_errs_txcomplete = 0;static int i2c_imx_errs_busbusy = 0;static int i2c_imx_errs_busgrab = 0;#endif/****************************************************************************** * functions (i2c-driver for IMX) ******************************************************************************//*----------------------------------------------------------------------------- * bus grab *----------------------------------------------------------------------------*/static int i2c_imx_bus_grab(void){	int i = 0;	/* wait for bus grab */	while(!((i2c_imx_reg->i2sr & (u32)0x30)) );	if (i == I2C_IMX_TIMEOUT) return 4;	return 0;}/*----------------------------------------------------------------------------- * bus busy *----------------------------------------------------------------------------*/static int i2c_imx_bus_busy(void){	int i = 0;	/* wait for bus not busy */	while((i2c_imx_reg->i2sr & (u32)0x20) && (i < I2C_IMX_TIMEOUT)) i++;	if (i == I2C_IMX_TIMEOUT) return 3;	return 0;}/*----------------------------------------------------------------------------- * received ack *----------------------------------------------------------------------------*/static int i2c_imx_received_acknowledge(void){	if(i2c_imx_i2sr & 0x01) return 1;	return 0;}/*----------------------------------------------------------------------------- * transfer complete *----------------------------------------------------------------------------*/static int i2c_imx_transfer_complete(void){	int i = 0;	unsigned long flags;	i2c_imx_i2sr = 0x00;	/* wait for transfer complete interrupt */	while ((!(i2c_imx_irq_ok)) && (i < I2C_IMX_TIMEOUT)){		spin_lock_irqsave(&i2c_imx_irqlock, flags);		i++;		spin_unlock_irqrestore(&i2c_imx_irqlock, flags);	}	i2c_imx_irq_ok = 0;	if (i == I2C_IMX_TIMEOUT) return 3;	return 0;}/*----------------------------------------------------------------------------- * bus release *----------------------------------------------------------------------------*/static int i2c_imx_bus_release(void){		int i=0, dummy;		/* if bus busy reset the module process suggested in reference manual	   (tahiti) */	if (i2c_imx_bus_busy() && (i < I2C_IMX_TIMEOUT)) {		i2c_imx_reg->i2cr  =   (u32)0x00;		i2c_imx_reg->i2cr |=   (u32)0x0a;		dummy = (u8)i2c_imx_reg->i2dr;		i2c_imx_reg->i2sr  =   (u32)0x00;		i2c_imx_reg->i2cr  =   (u32)0x00;		i2c_imx_reg->i2cr &= ~((u32)0x80);		i++;	}	return 0;}/*----------------------------------------------------------------------------- * start *----------------------------------------------------------------------------*/static int i2c_imx_start(void){	int i = 0;	/* Set Master Mode */	i2c_imx_reg->i2cr |= 0x20;	/* wait while bus grab */	while((i2c_imx_bus_grab()) && (i < I2C_IMX_TIMEOUT)) {		i2c_imx_reg->i2cr &= ~((u32)0x20);	  /* bus stop */		i2c_imx_bus_release();		if (i2c_imx_bus_busy()) return 3;		i2c_imx_reg->i2cr |=   (u32)0x80; /* [I2CR:IEN] (I2C Enable) */		i2c_imx_reg->i2cr |=   (u32)0x08; /* [I2CR:TXAK] dable txack */		i2c_imx_reg->i2cr |=   (u32)0x20;         /* Set Master Mode */		i++;	}	if (i == I2C_IMX_TIMEOUT) return 4;	return 0;}/*----------------------------------------------------------------------------- * write *----------------------------------------------------------------------------*/static int i2c_imx_write(int i, int *count, struct i2c_msg *msgs){	int err, j;	/* select slave */	i2c_imx_reg->i2dr = msgs->addr << 1;	if ((err = i2c_imx_transfer_complete())) return err;	if ((err = i2c_imx_received_acknowledge())) return err;	/* write data */	for ( j = 0; j < msgs->len; j ++ ) {		i2c_imx_reg->i2dr = msgs->buf[j];		if ((err = i2c_imx_transfer_complete())) return err;	}	count += msgs->len;	return 0;}/*----------------------------------------------------------------------------- * read *----------------------------------------------------------------------------*/static int i2c_imx_read(int i, int *count, struct i2c_msg *msgs){	int err, j, dummy;	/* select slave */	i2c_imx_reg->i2dr = ((u32)msgs->addr << 1) | (u32)0x01;	if ((err = i2c_imx_transfer_complete())) return err;	if ((err = i2c_imx_received_acknowledge())) return err;	/* setup bus to read data */	i2c_imx_reg->i2cr &= ~(u32)0x10;	if(msgs->len-1) i2c_imx_reg->i2cr &= ~(u32)0x08;	dummy = (u8)i2c_imx_reg->i2dr; /* trigger rec. of next byte */	if ((err = i2c_imx_transfer_complete())) return err;	/* read data */	for ( j = 0; j < msgs->len; j ++ ){		if(j== (msgs->len - 2)) i2c_imx_reg->i2cr |= 0x08;		msgs->buf[j] = (u8)i2c_imx_reg->i2dr;	              		if ((err = i2c_imx_transfer_complete())) return err;	}	count += msgs->len;	return 0;}/*----------------------------------------------------------------------------- * chip_sleep functions: gets timeout-values for supported chips * you have to add own functions to get optimal timeouts for your own chips  * now supported chips: m41t00 at 0x68, ads1100 at 0x48 *----------------------------------------------------------------------------*//* support for ads1100 at address 0x48 */void chip_slp_48(struct i2c_msg *msgs) {	switch(msgs->buf[0] & 0x0c) {	case 0x00:		i2c_imx_slp[0x48-1].slp_time = 1;		break;	case 0x04:		i2c_imx_slp[0x48-1].slp_time = 20;		break;	case 0x08:		i2c_imx_slp[0x48-1].slp_time = 40;		break;	case 0x0c:		i2c_imx_slp[0x48-1].slp_time = 70;		break;	}	return;}/* chip_slp */void chip_slp(struct i2c_msg *msgs) {	switch(msgs->addr) {	case 0x48:		chip_slp_48(msgs);		return;	}

⌨️ 快捷键说明

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