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

📄 i2c-algo-8xx.c

📁 I2C总线LINUX驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM * Copyright (c) 1999 Dan Malek (dmalek@jlc.net). *    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., 675 Mass Ave, Cambridge, MA 02139, USA. * * moved into proper i2c interface; separated out platform specific  * parts into i2c-rpx.c * Brad Parker (brad@heeltoe.com) */// XXX todo// timeout sleep?/* $Id: i2c-algo-8xx.c,v 1.15 2004/11/20 08:02:24 khali Exp $ */#include <linux/kernel.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/sched.h>#include "i2c.h"#include "i2c-algo-8xx.h"#include <asm/mpc8xx.h>#include <asm/commproc.h>#define CPM_MAX_READ	513/* #define I2C_CHIP_ERRATA */ /* Try uncomment this if you have an older CPU(earlier than rev D4) */static wait_queue_head_t iic_wait;static ushort r_tbase, r_rbase;int cpm_debug = 0;static  voidcpm_iic_interrupt(void *dev_id, struct pt_regs *regs){	volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;	if (cpm_debug > 1)		printk("cpm_iic_interrupt(dev_id=%p)\n", dev_id);#if 0	/* Chip errata, clear enable. This is not needed on rev D4 CPUs */        /* This should probably be removed and replaced by I2C_CHIP_ERRATA stuff */        /* Someone with a buggy CPU needs to confirm that */	i2c->i2c_i2mod &= ~1;#endif	/* Clear interrupt.	*/	i2c->i2c_i2cer = 0xff;	/* Get 'me going again.	*/	wake_up_interruptible(&iic_wait);}static voidcpm_iic_init(struct i2c_algo_8xx_data *cpm){	volatile iic_t		*iip = cpm->iip;	volatile i2c8xx_t	*i2c = cpm->i2c;	unsigned char brg;	bd_t *bd = (bd_t *)__res;	if (cpm_debug) printk(KERN_DEBUG "cpm_iic_init()\n");	/* Initialize the parameter ram.	 * We need to make sure many things are initialized to zero,	 * especially in the case of a microcode patch.	 */	iip->iic_rstate = 0;	iip->iic_rdp = 0;	iip->iic_rbptr = 0;	iip->iic_rbc = 0;	iip->iic_rxtmp = 0;	iip->iic_tstate = 0;	iip->iic_tdp = 0;	iip->iic_tbptr = 0;	iip->iic_tbc = 0;	iip->iic_txtmp = 0;	/* Set up the IIC parameters in the parameter ram.	*/	iip->iic_tbase = r_tbase = cpm->dp_addr;	iip->iic_rbase = r_rbase = cpm->dp_addr + sizeof(cbd_t)*2;	iip->iic_tfcr = SMC_EB;	iip->iic_rfcr = SMC_EB;	/* Set maximum receive size.	*/	iip->iic_mrblr = CPM_MAX_READ;	/* Initialize Tx/Rx parameters.	*/	if (cpm->reloc == 0) {		volatile cpm8xx_t *cp = cpm->cp;		cp->cp_cpcr =			mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;		while (cp->cp_cpcr & CPM_CR_FLG);	} else {		iip->iic_rbptr = iip->iic_rbase;		iip->iic_tbptr = iip->iic_tbase;		iip->iic_rstate	= 0;		iip->iic_tstate	= 0;	}	/* Select an arbitrary address.  Just make sure it is unique.	*/	i2c->i2c_i2add = 0xfe;	/* Make clock run at 60 KHz.	*/	brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3);	i2c->i2c_i2brg = brg;	i2c->i2c_i2mod = 0x00; 	i2c->i2c_i2com = 0x01; /* Master mode */	/* Disable interrupts.	*/	i2c->i2c_i2cmr = 0;	i2c->i2c_i2cer = 0xff;	init_waitqueue_head(&iic_wait);	/* Install interrupt handler.	*/	if (cpm_debug) {		printk ("%s[%d] Install ISR for IRQ %d\n",			__func__,__LINE__, CPMVEC_I2C);	}	(*cpm->setisr)(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c);}static intcpm_iic_shutdown(struct i2c_algo_8xx_data *cpm){	volatile i2c8xx_t *i2c = cpm->i2c;	/* Shut down IIC.	*/	i2c->i2c_i2mod &= ~1;	i2c->i2c_i2cmr = 0;	i2c->i2c_i2cer = 0xff;	return(0);}static void cpm_reset_iic_params(volatile iic_t *iip){	iip->iic_tbase = r_tbase;	iip->iic_rbase = r_rbase;	iip->iic_tfcr = SMC_EB;	iip->iic_rfcr = SMC_EB;	iip->iic_mrblr = CPM_MAX_READ;	iip->iic_rstate = 0;	iip->iic_rdp = 0;	iip->iic_rbptr = iip->iic_rbase;	iip->iic_rbc = 0;	iip->iic_rxtmp = 0;	iip->iic_tstate = 0;	iip->iic_tdp = 0;	iip->iic_tbptr = iip->iic_tbase;	iip->iic_tbc = 0;	iip->iic_txtmp = 0;}#define BD_SC_NAK		((ushort)0x0004) /* NAK - did not respond */#define BD_SC_OV		((ushort)0x0002) /* OV - receive overrun */#define CPM_CR_CLOSE_RXBD	((ushort)0x0007)static void force_close(struct i2c_algo_8xx_data *cpm){	volatile i2c8xx_t *i2c = cpm->i2c;	if (cpm->reloc == 0) { /* micro code disabled */		volatile cpm8xx_t *cp = cpm->cp;		if (cpm_debug) printk("force_close()\n");		cp->cp_cpcr =			mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) |			CPM_CR_FLG;		while (cp->cp_cpcr & CPM_CR_FLG);	}	i2c->i2c_i2cmr = 0x00;	/* Disable all interrupts */	i2c->i2c_i2cer = 0xff; }/* Read from IIC... * abyte = address byte, with r/w flag already set */static intcpm_iic_read(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf, int count){	volatile iic_t *iip = cpm->iip;	volatile i2c8xx_t *i2c = cpm->i2c;	volatile cpm8xx_t *cp = cpm->cp;	volatile cbd_t	*tbdf, *rbdf;	u_char *tb;	unsigned long flags, tmo;	if (count >= CPM_MAX_READ)		return -EINVAL;	/* check for and use a microcode relocation patch */	if (cpm->reloc) {		cpm_reset_iic_params(iip);	}	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];	/* To read, we need an empty buffer of the proper length.	 * All that is used is the first byte for address, the remainder	 * is just used for timing (and doesn't really have to exist).	 */	tb = cpm->temp;	tb = (u_char *)(((uint)tb + 15) & ~15);	tb[0] = abyte;		/* Device address byte w/rw flag */	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));	if (cpm_debug) printk("cpm_iic_read(abyte=0x%x)\n", abyte);	tbdf->cbd_bufaddr = __pa(tb);	tbdf->cbd_datlen = count + 1;	tbdf->cbd_sc =		BD_SC_READY | BD_SC_LAST |		BD_SC_WRAP | BD_IIC_START;	iip->iic_mrblr = count +1; /* prevent excessive read, +1				      is needed otherwise will the				      RXB interrupt come too early */	/* flush will invalidate too. */	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));	rbdf->cbd_datlen = 0;	rbdf->cbd_bufaddr = __pa(buf);	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT;	if(count > 16){		/* Chip bug, set enable here */		local_irq_save(flags);		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */		i2c->i2c_i2cer = 0xff;		i2c->i2c_i2mod |= 1;	/* Enable */		i2c->i2c_i2com |= 0x80;	/* Begin transmission */		/* Wait for IIC transfer */		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);		local_irq_restore(flags);	} else { /* busy wait for small transfers, its faster */		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */		i2c->i2c_i2cer = 0xff;		i2c->i2c_i2mod |= 1;	/* Enable */		i2c->i2c_i2com |= 0x80;	/* Begin transmission */		tmo = jiffies + 1*HZ; 		while(!(i2c->i2c_i2cer & 0x11 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */	}			if (signal_pending(current) || !tmo){		force_close(cpm);		if(cpm_debug) 			printk("IIC read: timeout!\n");		return -EIO;	}#ifdef I2C_CHIP_ERRATA	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.	 Disabling I2C too early may cause too short stop condition */	udelay(4);	i2c->i2c_i2mod &= ~1;#endif	if (cpm_debug) {		printk("tx sc %04x, rx sc %04x\n",		       tbdf->cbd_sc, rbdf->cbd_sc);	}	if (tbdf->cbd_sc & BD_SC_READY) {		printk("IIC read; complete but tbuf ready\n");		force_close(cpm);		printk("tx sc %04x, rx sc %04x\n",		       tbdf->cbd_sc, rbdf->cbd_sc);	}	if (tbdf->cbd_sc & BD_SC_NAK) {		if (cpm_debug)			printk("IIC read; no ack\n");

⌨️ 快捷键说明

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