Commit 201ca54a authored by Jesper Nilsson's avatar Jesper Nilsson
Browse files

CRIS v32: New version of I2C driver.

- Add i2c_write and i2c_read as functions.
- Use spinlocks for critical regions.
- Add config item to set I2C data and clock port.
- Put unneeded testcode inside #if 0.
- Remove CVS id tag.
parent 0f229504
Loading
Loading
Loading
Loading
+185 −14
Original line number Diff line number Diff line
@@ -19,10 +19,10 @@
*!
*! ---------------------------------------------------------------------------
*!
*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
*! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN
*!
*!***************************************************************************/
/* $Id: i2c.c,v 1.2 2005/05/09 15:29:49 starvik Exp $ */

/****************** INCLUDE FILES SECTION ***********************************/

#include <linux/module.h>
@@ -79,6 +79,8 @@ static const char i2c_name[] = "i2c";

#define i2c_delay(usecs) udelay(usecs)

static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */

/****************** VARIABLE SECTION ************************************/

static struct crisv32_iopin cris_i2c_clk;
@@ -252,6 +254,7 @@ i2c_getack(void)
	 * generate ACK clock pulse
	 */
	i2c_clk(I2C_CLOCK_HIGH);
#if 0
	/*
	 * Use PORT PB instead of I2C
	 * for input. (I2C not working)
@@ -264,6 +267,8 @@ i2c_getack(void)
	i2c_data(1);
	i2c_disable();
	i2c_dir_in();
#endif

	/*
	 * now wait for ack
	 */
@@ -275,7 +280,7 @@ i2c_getack(void)
		ack = 0;
	i2c_delay(CLOCK_HIGH_TIME/2);
	if (!ack) {
		if(!i2c_getbit()) /* receiver pulled SDA low */
		if (!i2c_getbit()) /* receiver pulld SDA low */
			ack = 1;
		i2c_delay(CLOCK_HIGH_TIME/2);
	}
@@ -285,6 +290,7 @@ i2c_getack(void)
    * before we enable our output. If we keep data high
    * and enable output, we would generate a stop condition.
    */
#if 0
   i2c_data(I2C_DATA_LOW);

	/*
@@ -292,6 +298,7 @@ i2c_getack(void)
	 */
	i2c_enable();
	i2c_dir_out();
#endif
	i2c_clk(I2C_CLOCK_LOW);
	i2c_delay(CLOCK_HIGH_TIME/4);
	/*
@@ -373,6 +380,137 @@ i2c_sendnack(void)
	i2c_dir_in();
}

/*#---------------------------------------------------------------------------
*#
*# FUNCTION NAME: i2c_write
*#
*# DESCRIPTION  : Writes a value to an I2C device
*#
*#--------------------------------------------------------------------------*/
int
i2c_write(unsigned char theSlave, void *data, size_t nbytes)
{
	int error, cntr = 3;
	unsigned char bytes_wrote = 0;
	unsigned char value;
	unsigned long flags;

	spin_lock(&i2c_lock);

	do {
		error = 0;
		/*
		 * we don't like to be interrupted
		 */
		local_irq_save(flags);

		i2c_start();
		/*
		 * send slave address
		 */
		i2c_outbyte((theSlave & 0xfe));
		/*
		 * wait for ack
		 */
		if (!i2c_getack())
			error = 1;
		/*
		 * send data
		 */
		for (bytes_wrote = 0; bytes_wrote < nbytes; bytes_wrote++) {
			memcpy(&value, data + bytes_wrote, sizeof value);
			i2c_outbyte(value);
			/*
			 * now it's time to wait for ack
			 */
			if (!i2c_getack())
				error |= 4;
		}
		/*
		 * end byte stream
		 */
		i2c_stop();
		/*
		 * enable interrupt again
		 */
		local_irq_restore(flags);

	} while (error && cntr--);

	i2c_delay(CLOCK_LOW_TIME);

	spin_unlock(&i2c_lock);

	return -error;
}

/*#---------------------------------------------------------------------------
*#
*# FUNCTION NAME: i2c_read
*#
*# DESCRIPTION  : Reads a value from an I2C device
*#
*#--------------------------------------------------------------------------*/
int
i2c_read(unsigned char theSlave, void *data, size_t nbytes)
{
	unsigned char b = 0;
	unsigned char bytes_read = 0;
	int error, cntr = 3;
	unsigned long flags;

	spin_lock(&i2c_lock);

	do {
		error = 0;
		memset(data, 0, nbytes);
		/*
		 * we don't like to be interrupted
		 */
		local_irq_save(flags);
		/*
		 * generate start condition
		 */
		i2c_start();
		/*
		 * send slave address
		 */
		i2c_outbyte((theSlave | 0x01));
		/*
		 * wait for ack
		 */
		if (!i2c_getack())
			error = 1;
		/*
		 * fetch data
		 */
		for (bytes_read = 0; bytes_read < nbytes; bytes_read++) {
			b = i2c_inbyte();
			memcpy(data + bytes_read, &b, sizeof b);

			if (bytes_read < (nbytes - 1))
				i2c_sendack();
		}
		/*
		 * last received byte needs to be nacked
		 * instead of acked
		 */
		i2c_sendnack();
		/*
		 * end sequence
		 */
		i2c_stop();
		/*
		 * enable interrupt again
		 */
		local_irq_restore(flags);
	} while (error && cntr--);

	spin_unlock(&i2c_lock);

	return -error;
}

/*#---------------------------------------------------------------------------
*#
*# FUNCTION NAME: i2c_writereg
@@ -387,6 +525,8 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg,
	int error, cntr = 3;
	unsigned long flags;

	spin_lock(&i2c_lock);

	do {
		error = 0;
		/*
@@ -431,11 +571,12 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg,
		 * enable interrupt again
		 */
		local_irq_restore(flags);

	} while(error && cntr--);

	i2c_delay(CLOCK_LOW_TIME);

	spin_unlock(&i2c_lock);

	return -error;
}

@@ -453,6 +594,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
	int error, cntr = 3;
	unsigned long flags;

	spin_lock(&i2c_lock);

	do {
		error = 0;
		/*
@@ -482,7 +625,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
		 * now it's time to wait for ack
		 */
		if(!i2c_getack())
			error = 1;
			error |= 2;
		/*
		 * repeat start condition
		 */
@@ -496,7 +639,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
		 * wait for ack
		 */
		if(!i2c_getack())
			error = 1;
			error |= 4;
		/*
		 * fetch register
		 */
@@ -517,6 +660,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)

	} while(error && cntr--);

	spin_unlock(&i2c_lock);

	return b;
}

@@ -583,12 +728,37 @@ static const struct file_operations i2c_fops = {
int __init
i2c_init(void)
{
	int res;
	static int res;
	static int first = 1;

	if (!first)
		return res;

	/* Setup and enable the Port B I2C interface */
	first = 0;

        crisv32_io_get_name(&cris_i2c_data, CONFIG_ETRAX_I2C_DATA_PORT);
        crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_I2C_CLK_PORT);
	/* Setup and enable the DATA and CLK pins */

	res = crisv32_io_get_name(&cris_i2c_data,
		CONFIG_ETRAX_V32_I2C_DATA_PORT);
	if (res < 0)
		return res;

	res = crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_V32_I2C_CLK_PORT);
	crisv32_io_set_dir(&cris_i2c_clk, crisv32_io_dir_out);

	return res;
}


int __init
i2c_register(void)
{

	int res;

	res = i2c_init();
	if (res < 0)
		return res;

	/* register char device */

@@ -598,13 +768,14 @@ i2c_init(void)
		return res;
	}

	printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n");
	printk(KERN_INFO
		"I2C driver v2.2, (c) 1999-2007 Axis Communications AB\n");

	return 0;
}

/* this makes sure that i2c_init is called during boot */

module_init(i2c_init);
module_init(i2c_register);

/****************** END OF FILE i2c.c ********************************/
+2 −0
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@

/* High level I2C actions */
int __init i2c_init(void);
int i2c_write(unsigned char theSlave, void *data, size_t nbytes);
int i2c_read(unsigned char theSlave, void *data, size_t nbytes);
int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue);
unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg);