`

I2C bus glue for Cirrus EP93xx

 
阅读更多

转自 http://arm.cirrus.com/forum/viewtopic.php?t=51&highlight=i2c

 

The attached file should be placed in linux-2.4.21\drivers\i2c\ . 

In Config.in I have added: 

dep_tristate ' I2C bus glue for Cirrus EP93xx processors' CONFIG_I2C_EP93XX $CONFIG_I2C_ALGOBIT 

And in Makefile: 

obj-$(CONFIG_I2C_EP93XX) += i2c-ep93xx.o 

 

 

/* ------------------------------------------------------------------------ *
 * i2c-ep933xx.c I2C bus glue for Cirrus EP93xx                             *
 * ------------------------------------------------------------------------ *

   Copyright (C) 2004 Michael Burian
   
   Based on i2c-parport-light.c
   Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
  
   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.
 * ------------------------------------------------------------------------ */


#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <asm/io.h>

//1/(2*clockfrequency)
#define EE_DELAY_USEC       50
#define GPIOG_EECLK 1
#define GPIOG_EEDAT 2

/* ----- I2C algorithm call-back functions and structures ----------------- */

// TODO: optimize
static void ep93xx_setscl(void *data, int state)
{
	unsigned int val, dir;

	val = inl(GPIO_PGDR);
	dir = inl(GPIO_PGDDR);

	/* Configure the clock line as output. */
	dir |= GPIOG_EECLK;
	outl(dir, GPIO_PGDDR);

	/* Set clock line to state */
	if(state)
		val |= GPIOG_EECLK;
	else
		val &= ~GPIOG_EECLK;
	
	outl(val, GPIO_PGDR);
}

static void ep93xx_setsda(void *data, int state)
{
	unsigned int val, dir;
	val = inl(GPIO_PGDR);
	dir = inl(GPIO_PGDDR);

	/* Configure the data line as output. */
	dir |= GPIOG_EEDAT;
	outl(dir, GPIO_PGDDR);

	/* Set data line to state */
	if(state)
		val |= GPIOG_EEDAT;
	else
		val &= ~GPIOG_EEDAT;
	
	outl(val, GPIO_PGDR);
}

static int ep93xx_getscl(void *data)
{
	unsigned int val, dir;
	val = inl(GPIO_PGDR);
	dir = inl(GPIO_PGDDR);

	/* Configure the clock line as input */
	dir &= ~GPIOG_EECLK;
	outl(dir, GPIO_PGDDR);
	
	/* Return state of the clock line */
	return (inl(GPIO_PGDR) & GPIOG_EECLK) ? 1 : 0;
}

static int ep93xx_getsda(void *data)
{
	unsigned int val, dir;
	val = inl(GPIO_PGDR);
	dir = inl(GPIO_PGDDR);

	/* Configure the data line as input */
	dir &= ~GPIOG_EEDAT;
	outl(dir, GPIO_PGDDR);

	/* Return state of the data line */
	return (inl(GPIO_PGDR) & GPIOG_EEDAT) ? 1 : 0;
}

static int ep93xx_reg(struct i2c_client *client)
{
	return 0;
}

static int ep93xx_unreg(struct i2c_client *client)
{
	return 0;
}

static void ep93xx_inc_use(struct i2c_adapter *adap)
{
#ifdef MODULE
	MOD_INC_USE_COUNT;
#endif
}

static void ep93xx_dec_use(struct i2c_adapter *adap)
{
#ifdef MODULE
	MOD_DEC_USE_COUNT;
#endif
}
/* ------------------------------------------------------------------------
 * Encapsulate the above functions in the correct operations structure.
 * This is only done when more than one hardware adapter is supported.
 */

/* last line (us, ms, timout)
 * us dominates the bit rate: 10us  means: 100Kbit/sec(25 means 40kbps)
 *                            10ms  not known
 *                            100ms timeout
 */
static struct i2c_algo_bit_data ep93xx_data = {
	NULL,
	ep93xx_setsda,
	ep93xx_setscl,
	ep93xx_getsda,
	ep93xx_getscl,
//	EE_DELAY_USEC, EE_DELAY_USEC, 100,	/* orginal (non-guide) value 10, 10, 100  */
	10, 10, 100,	/* orginal (non-guide) value 10, 10, 100  */
};

/* ----- I2c structure ---------------------------------------------------- */
static struct i2c_adapter ep93xx_adapter = {
	"EP93XX I2C interface",
	I2C_HW_B_LP, //I2C_HW_B_GUIDE
	NULL,
	&ep93xx_data,
	ep93xx_inc_use,
	ep93xx_dec_use,
	ep93xx_reg,
	ep93xx_unreg,
};

/* ----- Module loading, unloading and information ------------------------ */

static int __init i2c_ep93xx_init(void)
{
	unsigned long uiVal, uiDDR;
	
	/* Read the current value of the GPIO data and data direction registers. */
	uiVal = inl(GPIO_PGDR);
	uiDDR = inl(GPIO_PGDDR);

	/* If the GPIO pins have not been configured since reset, the data 
	 * and clock lines will be set as inputs and with data value of 0.
	 * External pullup resisters are pulling them high.
	 * Set them both high before configuring them as outputs. */
	uiVal |= (GPIOG_EEDAT | GPIOG_EECLK);
	outl(uiVal, GPIO_PGDR);

	/* Delay to meet the EE Interface timing specification. */
	udelay(EE_DELAY_USEC);

	
	/* Configure the EE data and clock lines as outputs. */
	uiDDR |= (GPIOG_EEDAT | GPIOG_EECLK);
	outl(uiDDR, GPIO_PGDDR);

	/* Delay to meet the EE Interface timing specification. */
	udelay(EE_DELAY_USEC);

	/* Reset hardware to a sane state (SCL and SDA high) */
	ep93xx_setsda(NULL, 1);
	ep93xx_setscl(NULL, 1);

	if (i2c_bit_add_bus(&ep93xx_adapter) < 0) {
		printk(KERN_ERR "i2c-ep93xx: Unable to register with I2C\n");
		return -ENODEV;
	}
	
	return 0;
}

static void __exit i2c_ep93xx_exit(void)
{
	i2c_bit_del_bus(&ep93xx_adapter);
}

EXPORT_NO_SYMBOLS;

MODULE_AUTHOR("Michael Burian");
MODULE_DESCRIPTION("I2C bus glue for Cirrus EP93xx processors");
MODULE_LICENSE("GPL");

module_init(i2c_ep93xx_init);
module_exit(i2c_ep93xx_exit);
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics