#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/i2c.h"
#include "linux/init.h"
#include "linux/time.h"
#include "linux/interrupt.h"
#include "linux/delay.h"
#include "linux/errno.h"
#include "linux/err.h"
#include "linux/platform_device.h"
#include "linux/pm_runtime.h"
#include "linux/clk.h"
#include "linux/cpufreq.h"
#include "linux/slab.h"
#include "linux/io.h"
#include "linux/of_i2c.h"
#include "linux/of_gpio.h"
#include "plat/gpio-cfg.h"
#include "mach/regs-gpio.h"
#include "asm/irq.h"
#include "plat/regs-iic.h"
#include "plat/iic.h"
//#define PRINTK printk
#define PRINTK(...)
enum s3c24xx_i2c_state {
STATE_IDLE,
STATE_START,
STATE_READ,
STATE_WRITE,
STATE_STOP
};
struct s3c2440_i2c_regs {
unsigned int iiccon;
unsigned int iicstat;
unsigned int iicadd;
unsigned int iicds;
unsigned int iiclc;
};
struct s3c2440_i2c_xfer_data {
struct i2c_msg *msgs;
int msn_num;
int cur_msg;
int cur_ptr;
int state;
int err;
wait_queue_head_t wait;
};
static struct s3c2440_i2c_xfer_data s3c2440_i2c_xfer_data;
static struct s3c2440_i2c_regs *s3c2440_i2c_regs;
static void s3c2440_i2c_start(void)
{
s3c2440_i2c_xfer_data.state = STATE_START;
if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) // 读 //
{
s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->addr < 1;
s3c2440_i2c_regs->iicstat = 0xb0; // 主机接收,启动
}
else // 写 //
{
s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->addr < 1;
s3c2440_i2c_regs->iicstat = 0xf0; // 主机发送,启动
}
}
static void s3c2440_i2c_stop(int err)
{
s3c2440_i2c_xfer_data.state = STATE_STOP;
s3c2440_i2c_xfer_data.err = err;
PRINTK("STATE_STOP, err = %d\n", err);
if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) // 读 //
{
// 下面两行恢复I2C操作,发出P信号
s3c2440_i2c_regs->iicstat = 0x90;
s3c2440_i2c_regs->iiccon = 0xaf;
ndelay(50); // 等待一段时间以便P信号已经发出
}
else // 写 //
{
// 下面两行用来恢复I2C操作,发出P信号
s3c2440_i2c_regs->iicstat = 0xd0;
s3c2440_i2c_regs->iiccon = 0xaf;
ndelay(50); // 等待一段时间以便P信号已经发出
}
// 唤醒 //
wake_up(&s3c2440_i2c_xfer_data.wait);
}
static int s3c2440_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
unsigned long timeout;
// 把num个msg的I2C数据发送出去/读进来 //
s3c2440_i2c_xfer_data.msgs = msgs;
s3c2440_i2c_xfer_data.msn_num = num;
s3c2440_i2c_xfer_data.cur_msg = 0;
s3c2440_i2c_xfer_data.cur_ptr = 0;
s3c2440_i2c_xfer_data.err = -ENODEV;
s3c2440_i2c_start();
// 休眠 //
timeout = wait_event_timeout(s3c2440_i2c_xfer_data.wait, (s3c2440_i2c_xfer_data.state == STATE_STOP), HZ * 5);
if (0 == timeout)
{
printk("s3c2440_i2c_xfer time out\n");
return -ETIMEDOUT;
}
else
{
return s3c2440_i2c_xfer_data.err;
}
}
static u32 s3c2440_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
}
static const struct i2c_algorithm s3c2440_i2c_algo = {
// .smbus_xfer = ,
.master_xfer = s3c2440_i2c_xfer,
.functionality = s3c2440_i2c_func,
};
// 1. 分配/设置i2c_adapter
//
static struct i2c_adapter s3c2440_i2c_adapter = {
.name = "s3c2440_100ask",
.algo = &s3c2440_i2c_algo,
.owner = THIS_MODULE,
};
static int isLastMsg(void)
{
return (s3c2440_i2c_xfer_data.cur_msg == s3c2440_i2c_xfer_data.msn_num - 1);
}
static int isEndData(void)
{
return (s3c2440_i2c_xfer_data.cur_ptr >= s3c2440_i2c_xfer_data.msgs->len);
}
static int isLastData(void)
{
return (s3c2440_i2c_xfer_data.cur_ptr == s3c2440_i2c_xfer_data.msgs->len - 1);
}
static irqreturn_t s3c2440_i2c_xfer_irq(int irq, void *dev_id)
{
unsigned int iicSt;
iicSt = s3c2440_i2c_regs->iicstat;
if(iicSt & 0x8){ printk("Bus arbitration failed\