📄 i2c-samsung.c
字号:
/*
* (C) Copyright 2002 Soft I2C Char Device Driver for
* my own SAMSUNGS3C4510B Board EDEN E-TECH4510
* but it is replanted from my MPC8250 Board Drivers
* Honeyandy Chen, EDEN E-TECH Co. ltd, honeyandy@thunis.com
* if there is any problem ,call EDEN E-TECH Co. ltd by
* +86-028-85184225-8005
* first edit date : 2002.7.2, author: Honeyandy Chen
* history : 2003.6.18, author: Honeyandy Chen
* history : 2003.7.1, author: Honeyandy Chen
* history : 2003.11.12, author: Honeyandy Chen for uClinux
* history : 2003.11.16, author: Honeyandy Chen for uClinux with Mutex
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/vfs.h>
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/signal.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/slab.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/semaphore.h> /* for MUTEX */
#include <asm/uaccess.h>
#include <asm/page.h>
#include "i2c-samsung.h"
/*
* * Deal with modules and CONFIG_MODVERSIONS
* */
#ifdef MODULE
# if CONFIG_MODVERSIONS==1
# include <linux/modversions.h>
# endif
MODULE_AUTHOR("Honeyandy Chen, honeyandy@thunis.com");
MODULE_DESCRIPTION("SAMSUNG4510B Hardware I2C Driver for uClinux 4510B Project");
# endif
/*
* * Debugging Options
* *
*/
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
#define DEVICE_NAME "i2c"
#define I2C_MAJOR 89 /* define major id */
#define USE_KMALLOC /* kmalloc is one way save memory */
#ifndef USE_KMALLOC
static volatile U8 priv_buf[128];
#endif
static struct semaphore i2c_samsung_sem;
//devfs_handle_t dev_handle; /* register handle to store device fs */
static struct file_operations i2c_ops ;
/* IIC paramters */
typedef struct
{
int i2c_speed;
U8 i2c_slave;
U8 i2c_addrlen;
U8 i2c_operate;
int i2c_pagesize;
spinlock_t lock;
U8 *buf;
} I2C_PRIVATE_T;
static I2C_PRIVATE_T iic_priv;
static IIC_DATA_TX_FORMAT iic_txmit;
static IIC_DATA_RX_FORMAT iic_recv;
#ifdef MODULE
int init_module(void);
void cleanup_module(void);
#endif
int __init i2c_samsung_init( void );
static ssize_t i2c_read (struct file * file ,char * buf, size_t count, loff_t * f_ops);
static ssize_t i2c_write (struct file * file ,const char * buf, size_t count, loff_t * f_ops);
static ssize_t i2c_ioctl (struct inode * inode ,struct file * file,
unsigned int cmd, U32 data);
static ssize_t i2c_open (struct inode * inode ,struct file * file);
static ssize_t i2c_release(struct inode * inode ,struct file * file);
/*=========== I2C Read =======================*/
static ssize_t i2c_read (struct file * file ,char * buf, size_t count, loff_t * f_ops)
{
DBG("s34510: i2c device file-read operation!\n");
return count;
}
/*=========== I2C Write =======================*/
static ssize_t i2c_write (struct file * file ,const char * buf, size_t count, loff_t * f_ops)
{
DBG("s34510: i2c device file-write operation!\n");
return count;
}
/*=========== I2C Ioctl =======================*/
static ssize_t i2c_ioctl (struct inode * inode ,struct file * file,
unsigned int cmd, U32 data)
{
I2C_CHAIN_T *chain = NULL;
down(&i2c_samsung_sem);
DBG("s34510: i2c device ioctl operation!\n");
switch( cmd )
{
case CMD_CHAIN_INIT:
DBG("s34510: CMD_CHAIN_INIT command!\n");
goto ioctl_exit;
case CMD_CHAIN_READ:
DBG("s34510: CMD_CHAIN_READ command!\n");
chain = (I2C_CHAIN_T *)data;
if( chain->mode.i2c_pagesize ==0 ){ /* at least one byte every write command*/
break;
}
iic_priv.i2c_speed = chain->mode.i2c_speed;
iic_priv.i2c_slave = chain->mode.i2c_slave;
iic_priv.i2c_addrlen = chain->mode.i2c_addrlen;
iic_priv.i2c_pagesize = chain->mode.i2c_pagesize;
#ifndef USE_KMALLOC
iic_priv.buf = priv_buf;
if( chain->len > 128 ){
break;
}
#else
iic_priv.buf = (volatile U8 *)kmalloc(chain->len +1, GFP_KERNEL);
if( iic_priv.buf == NULL ){
break;
}
#endif
i2c_chain_read( chain->addr, iic_priv.buf, chain->len);
copy_to_user( chain->buffer, iic_priv.buf, chain->len);
#ifdef USE_KMALLOC
kfree( iic_priv.buf);
#endif
goto ioctl_exit;
case CMD_CHAIN_WRITE:
DBG("s34510: CMD_CHAIN_WRITE command!\n");
chain = (I2C_CHAIN_T *)data;
if( chain->mode.i2c_pagesize ==0 ){ /* at least one byte every write command*/
break;
}
iic_priv.i2c_speed = chain->mode.i2c_speed;
iic_priv.i2c_slave = chain->mode.i2c_slave;
iic_priv.i2c_addrlen = chain->mode.i2c_addrlen;
iic_priv.i2c_pagesize = chain->mode.i2c_pagesize;
#ifndef USE_KMALLOC
if( chain->len > 128 ){
break;
}
iic_priv.buf = priv_buf;
#else
iic_priv.buf = (volatile U8 *)kmalloc(chain->len +1, GFP_KERNEL);
if( iic_priv.buf == NULL ){
break;
}
#endif
copy_from_user( iic_priv.buf , chain->buffer, chain->len );
i2c_chain_write( chain->addr, iic_priv.buf, chain->len);
#ifdef USE_KMALLOC
kfree( iic_priv.buf);
#endif
goto ioctl_exit;
default:
DBG("s34510: invaluable command :%08x\n !",(U32)cmd);
break;
}
up(&i2c_samsung_sem);
return -EINVAL;
ioctl_exit:
up(&i2c_samsung_sem);
return (0);
}
/*============ I2C device open ==============*/
static ssize_t i2c_open (struct inode * inode ,struct file * file)
{
DBG("s34510: i2c device open operation!\n");
MOD_INC_USE_COUNT;
return 0;
}
/*============ I2C device close =============*/
static ssize_t i2c_release (struct inode * inode ,struct file * file)
{
DBG("s34510: i2c device release operation!\n");
MOD_DEC_USE_COUNT;
return 0;
}
/*======= device function interface =========*/
static struct file_operations i2c_ops ={
open: i2c_open,
read: i2c_read,
write: i2c_write,
ioctl: i2c_ioctl,
release: i2c_release,
};
/*===========================================*/
/* i2C interrupt handle */
/*===========================================*/
static void s3c4510_i2c(int irq, void *dev_id, struct pt_regs *regs)
{
spin_lock(&iic_priv.lock);
DBG( "s34510: interrupt happen!\n");
if( iic_priv.i2c_operate == IICWRITE )
{
if(!(iic_txmit.FLAG & (U32)iic_byte_addr_msb)) {
/* Send byte address: MSB */
IICBUF = iic_txmit.BYTE_ADDR_MSB;
iic_txmit.FLAG |= (U32)iic_byte_addr_msb;
}
else if(!(iic_txmit.FLAG & (U32)iic_byte_addr_lsb)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -