i2c: remove unused rk drivers

Change-Id: I7e198d811ec2163c28ac095d60e95f4e9ac702e3
Signed-off-by: Tao Huang <huangtao@rock-chips.com>
This commit is contained in:
Tao Huang 2018-01-25 10:28:00 +08:00
parent 8f9e364c9c
commit 052b8beaa3
9 changed files with 0 additions and 4410 deletions

View File

@ -1,398 +0,0 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/jiffies.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/rwsem.h>
#include <asm/uaccess.h>
#include "i2c-dev-rk29.h"
#include "../i2c-core.h"
#define I2C_DEV_SCL_RATE 100 * 1000
struct completion i2c_dev_complete = {
.done = -1,
};
struct i2c_dump_info g_dump;
static void i2c_dev_get_list(struct i2c_list_info *list)
{
struct i2c_devinfo *devinfo;
struct i2c_adapter *adap = NULL;
int index;
memset(list, 0, sizeof(struct i2c_list_info));
down_read(&__i2c_board_lock);
list_for_each_entry(devinfo, &__i2c_board_list, list) {
if(devinfo->busnum >= MAX_I2C_BUS) {
list->adap_nr = -1;
up_read(&__i2c_board_lock);
return;
}
adap = i2c_get_adapter(devinfo->busnum);
if(adap != NULL) {
list->adap[devinfo->busnum].id = adap->nr;
strcpy(list->adap[devinfo->busnum].name, adap->name);
index = list->adap[devinfo->busnum].client_nr++;
if(index >= MAX_CLIENT_NUM || index == -1)
list->adap[devinfo->busnum].client_nr = -1;
else {
list->adap[devinfo->busnum].client[index].addr = devinfo->board_info.addr;
strcpy(list->adap[devinfo->busnum].client[index].name,
devinfo->board_info.type);
}
}
}
list->adap_nr = MAX_I2C_BUS;
up_read(&__i2c_board_lock);
return;
}
void i2c_dev_dump_start(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
int i, j;
memset(&g_dump, 0, sizeof(struct i2c_dump_info));
g_dump.id = adap->nr;
g_dump.addr = msgs[0].addr;
for(i = 0; i < num; i++) {
if(msgs[i].flags & I2C_M_RD) {
if(msgs[i].len >= MAX_VALUE_NUM)
g_dump.get_num = -1;
else
g_dump.get_num = msgs[i].len;
}
else {
if(msgs[i].len >= MAX_VALUE_NUM)
g_dump.set_num = -1;
else {
g_dump.set_num = msgs[i].len;
for(j = 0; j < msgs[i].len; j++)
g_dump.set_value[j] = msgs[i].buf[j];
}
}
}
return;
}
EXPORT_SYMBOL(i2c_dev_dump_start);
void i2c_dev_dump_stop(struct i2c_adapter *adap, struct i2c_msg *msgs, int num, int ret)
{
int i, j;
if(ret < 0) {
g_dump.get_num = 0;
g_dump.set_num = 0;
}
for(i = 0; i < num; i++) {
if((msgs[i].flags & I2C_M_RD) && (g_dump.get_num > 0)) {
for(j = 0; j < msgs[i].len; j++)
g_dump.get_value[j] = msgs[i].buf[j];
}
}
if(i2c_dev_complete.done == 0)
complete(&i2c_dev_complete);
return;
}
EXPORT_SYMBOL(i2c_dev_dump_stop);
static void i2c_dev_get_dump(struct i2c_dump_info *dump)
{
init_completion(&i2c_dev_complete);
wait_for_completion_killable(&i2c_dev_complete);
*dump = g_dump;
return;
}
static int i2c_dev_get_normal(struct i2c_adapter *adap, struct i2c_get_info *get)
{
struct i2c_msg msg;
char buf[MAX_VALUE_NUM];
int ret, i;
msg.addr = (__u16)get->addr;
msg.flags = I2C_M_RD;
msg.len = get->num;
msg.buf = buf;
msg.scl_rate = I2C_DEV_SCL_RATE;
ret = i2c_transfer(adap, &msg, 1);
if(ret == 1) {
for(i = 0; i < get->num; i++)
get->value[i] = buf[i];
return 0;
}
else
return -1;
}
static int i2c_dev_set_normal(struct i2c_adapter *adap, struct i2c_set_info *set)
{
struct i2c_msg msg;
char buf[MAX_VALUE_NUM];
int ret;
msg.addr = (__u16)set->addr;
msg.flags = 0;
msg.len = set->num;
msg.buf = buf;
msg.scl_rate = I2C_DEV_SCL_RATE;
ret = i2c_transfer(adap, &msg, 1);
return(ret == 1)? 0: -1;
}
static int i2c_dev_get_reg8(struct i2c_adapter *adap, struct i2c_get_info *get)
{
int ret, i;
struct i2c_msg msgs[2];
char reg = get->reg;
char buf[MAX_VALUE_NUM];
msgs[0].addr = (__u16)get->addr;
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = &reg;
msgs[0].scl_rate = I2C_DEV_SCL_RATE;
msgs[1].addr = get->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = get->num;
msgs[1].buf = buf;
msgs[1].scl_rate = I2C_DEV_SCL_RATE;
ret = i2c_transfer(adap, msgs, 2);
if(ret == 2) {
for(i = 0; i < get->num; i++)
get->value[i] = buf[i];
return 0;
}
else
return -1;
}
static int i2c_dev_set_reg8(struct i2c_adapter *adap, struct i2c_set_info *set)
{
int ret, i;
struct i2c_msg msg;
char buf[MAX_VALUE_NUM + 1];
buf[0] = (char)set->reg;
for(i = 0; i < set->num; i++)
buf[i+1] = (char)set->value[i];
msg.addr = (__u16)set->addr;
msg.flags = 0;
msg.len = set->num + 1;
msg.buf = buf;
msg.scl_rate = I2C_DEV_SCL_RATE;
ret = i2c_transfer(adap, &msg, 1);
return (ret == 1)? 0: -1;
}
static int i2c_dev_get_reg16(struct i2c_adapter *adap, struct i2c_get_info *get)
{
int ret, i;
struct i2c_msg msgs[2];
char reg[2];
char buf[MAX_VALUE_NUM * 2];
reg[0] = (char)(get->reg & 0xff);
reg[1] = (char)((get->reg >>8) & 0xff);
msgs[0].addr = (__u16)get->addr;
msgs[0].flags = 0;
msgs[0].len = 2;
msgs[0].buf = reg;
msgs[0].scl_rate = I2C_DEV_SCL_RATE;
msgs[1].addr = get->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = get->num * 2;
msgs[1].buf = buf;
msgs[1].scl_rate = I2C_DEV_SCL_RATE;
ret = i2c_transfer(adap, msgs, 2);
if(ret == 2) {
for(i = 0; i < get->num; i++)
get->value[i] = buf[2*i] & (buf[2*i+1]<<8);
return 0;
}
else
return -1;
}
static int i2c_dev_set_reg16(struct i2c_adapter *adap, struct i2c_set_info *set)
{
struct i2c_msg msg;
int ret, i;
char buf[2 * (MAX_VALUE_NUM + 1)];
buf[0] = (char)(set->reg & 0xff);
buf[1] = (char)((set->reg >>8) & 0xff);
for(i = 0; i < set->num; i++) {
buf[2 * (i + 1)] = (char)(set->value[i] & 0xff);
buf[2 * (i + 1) + 1] = (char)((set->value[i]>>8) & 0xff);
}
msg.addr = set->addr;
msg.flags = 0;
msg.len = 2 * (set->num + 1);
msg.buf = buf;
msg.scl_rate = I2C_DEV_SCL_RATE;
ret = i2c_transfer(adap, &msg, 1);
return (ret == 1)? 0: -1;
}
static int i2c_dev_get_value(struct i2c_get_info *get)
{
int ret = 0;
struct i2c_adapter *adap = NULL;
if(get->num > MAX_VALUE_NUM)
return -1;
adap = i2c_get_adapter(get->id);
if(adap == NULL)
return -1;
switch(get->mode) {
case 'b':
ret = i2c_dev_get_reg8(adap, get);
break;
case 's':
ret = i2c_dev_get_reg16(adap, get);
break;
case 'o':
ret = -1;
break;
default:
ret = i2c_dev_get_normal(adap, get);
break;
}
return ret;
}
static int i2c_dev_set_value(struct i2c_set_info *set)
{
int ret = 0;
struct i2c_adapter *adap = NULL;
printk("id=%d, addr=0x%x, mode = %c, num = %d, reg = 0x%x, value[0] = %d,",set->id, set->addr, set->mode, set->num, set->reg, set->value[0]);
if(set->num > MAX_VALUE_NUM)
return -1;
adap = i2c_get_adapter(set->id);
if(adap == NULL)
return -1;
switch(set->mode) {
case 'b':
ret = i2c_dev_set_reg8(adap, set);
break;
case 's':
ret = i2c_dev_set_reg16(adap, set);
break;
case 'o':
ret = -1;
break;
default:
ret = i2c_dev_set_normal(adap, set);
break;
}
return ret;
}
static int i2c_dev_open(struct inode *inode, struct file *file)
{
return 0;
}
static long i2c_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret = 0;
struct i2c_list_info *list = NULL;
struct i2c_dump_info dump;
struct i2c_get_info get;
struct i2c_set_info set;
switch(cmd) {
case I2C_LIST:
list = kzalloc(sizeof(struct i2c_list_info), GFP_KERNEL);
if(list == NULL) {
ret = -ENOMEM;
break;
}
i2c_dev_get_list(list);
if(copy_to_user((void __user *)arg, (void *)list, sizeof(struct i2c_list_info)))
ret = -EFAULT;
kfree(list);
break;
case I2C_DUMP:
i2c_dev_get_dump(&dump);
if(copy_to_user((void __user *)arg, (void *)&dump, sizeof(struct i2c_dump_info)))
ret = -EFAULT;
break;
case I2C_GET:
if(copy_from_user((void *)&get, (void __user *)arg, sizeof(struct i2c_get_info))) {
ret = -EFAULT;
break;
}
if(i2c_dev_get_value(&get) < 0) {
ret = -EFAULT;
break;
}
if(copy_to_user((void __user *)arg, (void *)&get, sizeof(struct i2c_get_info)))
ret = -EFAULT;
break;
case I2C_SET:
if(copy_from_user((void *)&set, (void __user *)arg, sizeof(struct i2c_set_info))) {
ret = -EFAULT;
break;
}
ret = i2c_dev_set_value(&set);
break;
default:
break;
}
return ret;
}
static int i2c_dev_release(struct inode *inode, struct file *file)
{
return 0;
}
static struct file_operations i2c_dev_fops = {
.owner = THIS_MODULE,
.open = i2c_dev_open,
.unlocked_ioctl = i2c_dev_ioctl,
.release = i2c_dev_release,
};
static struct miscdevice i2c_misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = I2C_DEV_NAME,
.fops = &i2c_dev_fops,
};
static int __init i2c_dev_init(void)
{
return misc_register(&i2c_misc_dev);
}
static void __exit i2c_dev_exit(void)
{
misc_deregister(&i2c_misc_dev);
}
module_init(i2c_dev_init);
module_exit(i2c_dev_exit);
MODULE_DESCRIPTION("Driver for RK29 I2C Device");
MODULE_AUTHOR("kfx, kfx@rock-chips.com");
MODULE_LICENSE("GPL");

View File

@ -1,62 +0,0 @@
#ifndef _I2C_DEV_H
#define _I2C_DEV_H
#define I2C_DEV_NAME "i2c-dev"
#define I2C_DEV_PATH "/dev/"I2C_DEV_NAME
#define MAX_ADAP_LENG 48
#define MAX_CLIENT_LENG 20
#define MAX_VALUE_NUM 16
#define MAX_I2C_BUS 4
#define MAX_CLIENT_NUM 32
#define I2C_LIST 0X7000
#define I2C_DUMP 0x7010
#define I2C_GET 0x7020
#define I2C_SET 0x7030
struct i2c_client_info {
int addr;
char name[MAX_CLIENT_LENG];
};
struct i2c_adap_info {
int id;
char name[MAX_ADAP_LENG];
int client_nr;
struct i2c_client_info client[MAX_CLIENT_NUM];
};
struct i2c_list_info {
int adap_nr;
struct i2c_adap_info adap[MAX_I2C_BUS];
};
struct i2c_dump_info {
int id;
int addr;
int get_num;
int get_value[MAX_VALUE_NUM];
int set_num;
int set_value[MAX_VALUE_NUM];
};
struct i2c_get_info {
char mode;
int id;
int addr;
int reg;
int num;
int value[MAX_VALUE_NUM];
};
struct i2c_set_info {
char mode;
int id;
int addr;
int reg;
int num;
int value[MAX_VALUE_NUM];
};
#endif /* _I2CDEV_H */

View File

@ -1,598 +0,0 @@
/* drivers/i2c/busses/i2c-rk29-adapter.c
*
* Copyright (C) 2012 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include "i2c-rk30.h"
/* master transmit */
#define I2C_MTXR (0x0000)
/* master receive */
#define I2C_MRXR (0x0004)
/* slave address */
#define I2C_SADDR (0x0010)
/* interrupt enable control */
#define I2C_IER (0x0014)
#define I2C_IER_ARBITR_LOSE (1<<7)
#define I2C_IER_MRX_NEED_ACK (1<<1)
#define I2C_IER_MTX_RCVD_ACK (1<<0)
#define IRQ_MST_ENABLE (I2C_IER_ARBITR_LOSE | \
I2C_IER_MRX_NEED_ACK | \
I2C_IER_MTX_RCVD_ACK)
#define IRQ_ALL_DISABLE (0x00)
/* interrupt status, write 0 to clear */
#define I2C_ISR (0x0018)
#define I2C_ISR_ARBITR_LOSE (1<<7)
#define I2C_ISR_MRX_NEED_ACK (1<<1)
#define I2C_ISR_MTX_RCVD_ACK (1<<0)
/* stop/start/resume command, write 1 to set */
#define I2C_LCMR (0x001c)
#define I2C_LCMR_RESUME (1<<2)
#define I2C_LCMR_STOP (1<<1)
#define I2C_LCMR_START (1<<0)
/* i2c core status */
#define I2C_LSR (0x0020)
#define I2C_LSR_RCV_NAK (1<<1)
#define I2C_LSR_RCV_ACK (~(1<<1))
#define I2C_LSR_BUSY (1<<0)
/* i2c config */
#define I2C_CONR (0x0024)
#define I2C_CONR_NAK (1<<4)
#define I2C_CONR_ACK (~(1<<4))
#define I2C_CONR_MTX_MODE (1<<3)
#define I2C_CONR_MRX_MODE (~(1<<3))
#define I2C_CONR_MPORT_ENABLE (1<<2)
#define I2C_CONR_MPORT_DISABLE (~(1<<2))
/* i2c core config */
#define I2C_OPR (0x0028)
#define I2C_OPR_RESET_STATUS (1<<7)
#define I2C_OPR_CORE_ENABLE (1<<6)
#define I2CCDVR_REM_BITS (0x03)
#define I2CCDVR_REM_MAX (1<<(I2CCDVR_REM_BITS))
#define I2CCDVR_EXP_BITS (0x03)
#define I2CCDVR_EXP_MAX (1<<(I2CCDVR_EXP_BITS))
#define RK29_I2C_START_TMO_COUNT 100 // msleep 1 * 100
int i2c_suspended(struct i2c_adapter *adap)
{
return 1;
}
EXPORT_SYMBOL(i2c_suspended);
static inline void rk29_i2c_disable_ack(struct rk30_i2c *i2c)
{
unsigned long conr = readl(i2c->regs + I2C_CONR);
conr |= I2C_CONR_NAK;
writel(conr,i2c->regs + I2C_CONR);
}
static inline void rk29_i2c_enable_ack(struct rk30_i2c *i2c)
{
unsigned long conr = readl(i2c->regs + I2C_CONR);
conr &= I2C_CONR_ACK;
writel(conr,i2c->regs + I2C_CONR);
}
static inline void rk29_i2c_disable_mport(struct rk30_i2c *i2c)
{
unsigned long conr = readl(i2c->regs + I2C_CONR);
conr &= I2C_CONR_MPORT_DISABLE;
writel(conr,i2c->regs + I2C_CONR);
}
static inline void rk29_i2c_enable_mport(struct rk30_i2c *i2c)
{
unsigned long conr = readl(i2c->regs + I2C_CONR);
conr |= I2C_CONR_MPORT_ENABLE;
writel(conr,i2c->regs + I2C_CONR);
}
static inline void rk29_i2c_disable_irq(struct rk30_i2c *i2c)
{
writel(IRQ_ALL_DISABLE, i2c->regs + I2C_IER);
}
static inline void rk29_i2c_enable_irq(struct rk30_i2c *i2c)
{
writel(IRQ_MST_ENABLE, i2c->regs + I2C_IER);
}
/* scl = pclk/(5 *(rem+1) * 2^(exp+1)) */
static void rk29_i2c_calcdivisor(unsigned long pclk,
unsigned long scl_rate,
unsigned long *real_rate,
unsigned int *rem, unsigned int *exp)
{
unsigned int calc_rem = 0;
unsigned int calc_exp = 0;
for(calc_exp = 0; calc_exp < I2CCDVR_EXP_MAX; calc_exp++)
{
calc_rem = pclk / (5 * scl_rate * (1 <<(calc_exp +1)));
if(calc_rem < I2CCDVR_REM_MAX)
break;
}
if(calc_rem >= I2CCDVR_REM_MAX || calc_exp >= I2CCDVR_EXP_MAX)
{
calc_rem = I2CCDVR_REM_MAX - 1;
calc_exp = I2CCDVR_EXP_MAX - 1;
}
*rem = calc_rem;
*exp = calc_exp;
*real_rate = pclk/(5 * (calc_rem + 1) * (1 <<(calc_exp +1)));
return;
}
static void rk29_i2c_set_clk(struct rk30_i2c *i2c, unsigned long scl_rate)
{
unsigned int rem = 0, exp = 0;
unsigned long real_rate = 0, tmp;
unsigned long i2c_rate = clk_get_rate(i2c->clk);
if((scl_rate == i2c->scl_rate) && (i2c_rate == i2c->i2c_rate))
return;
i2c->i2c_rate = i2c_rate;
i2c->scl_rate = scl_rate;
rk29_i2c_calcdivisor(i2c->i2c_rate, i2c->scl_rate, &real_rate, &rem, &exp);
tmp = readl(i2c->regs + I2C_OPR);
tmp &= ~0x3f;
tmp |= exp;
tmp |= rem<<I2CCDVR_EXP_BITS;
writel(tmp, i2c->regs + I2C_OPR);
return;
}
static void rk29_i2c_init_hw(struct rk30_i2c *i2c, unsigned long scl_rate)
{
unsigned long opr = readl(i2c->regs + I2C_OPR);
opr |= I2C_OPR_RESET_STATUS;
writel(opr, i2c->regs + I2C_OPR);
udelay(10);
opr = readl(i2c->regs + I2C_OPR);
opr &= ~I2C_OPR_RESET_STATUS;
writel(opr, i2c->regs + I2C_OPR);
rk29_i2c_set_clk(i2c, scl_rate);
rk29_i2c_disable_irq(i2c);
writel(0, i2c->regs + I2C_LCMR);
writel(0, i2c->regs + I2C_LCMR);
opr = readl(i2c->regs + I2C_OPR);
opr |= I2C_OPR_CORE_ENABLE;
writel(opr, i2c->regs + I2C_OPR);
udelay(i2c->tx_setup);
return;
}
static inline void rk29_i2c_master_complete(struct rk30_i2c *i2c, int ret)
{
i2c_dbg(i2c->dev, "master_complete %d\n", ret);
i2c->msg_ptr = 0;
i2c->msg = NULL;
i2c->msg_idx++;
i2c->msg_num = 0;
if (ret)
i2c->msg_idx = ret;
wake_up(&i2c->wait);
}
static void rk29_i2c_message_start(struct rk30_i2c *i2c,
struct i2c_msg *msg)
{
unsigned int addr = (msg->addr & 0x7f) << 1;
unsigned long stat, conr;
stat = 0;
i2c->addr = msg->addr & 0x7f;
if (msg->flags & I2C_M_RD)
addr |= 1;
if (msg->flags & I2C_M_REV_DIR_ADDR)
addr ^= 1;
rk29_i2c_enable_ack(i2c);
i2c_dbg(i2c->dev, "START: set addr 0x%02x to DS\n", addr);
conr = readl(i2c->regs + I2C_CONR);
conr |= I2C_CONR_MTX_MODE;
writel(conr, i2c->regs + I2C_CONR);
writel(addr, i2c->regs + I2C_MTXR);
udelay(i2c->tx_setup);
writel(I2C_LCMR_START|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
}
static inline void rk29_i2c_stop(struct rk30_i2c *i2c, int ret)
{
i2c_dbg(i2c->dev, "STOP\n");
udelay(i2c->tx_setup);
writel(I2C_LCMR_STOP|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
i2c->state = STATE_STOP;
rk29_i2c_master_complete(i2c, ret);
rk29_i2c_disable_irq(i2c);
}
/* returns TRUE if the current message is the last in the set */
static inline int is_lastmsg(struct rk30_i2c *i2c)
{
return i2c->msg_idx >= (i2c->msg_num - 1);
}
/* returns TRUE if we this is the last byte in the current message */
static inline int is_msglast(struct rk30_i2c *i2c)
{
return i2c->msg_ptr == i2c->msg->len-1;
}
/* returns TRUE if we reached the end of the current message */
static inline int is_msgend(struct rk30_i2c *i2c)
{
return i2c->msg_ptr >= i2c->msg->len;
}
static int rk29_i2c_irq_nextbyte(struct rk30_i2c *i2c, unsigned long isr)
{
unsigned long lsr, conr;
unsigned char byte;
int ret = 0;
lsr = readl(i2c->regs + I2C_LSR);
switch (i2c->state) {
case STATE_IDLE:
dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
goto out;
case STATE_STOP:
dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
rk29_i2c_disable_irq(i2c);
goto out;
case STATE_START:
if(!(isr & I2C_ISR_MTX_RCVD_ACK)){
writel(isr & ~I2C_ISR_MTX_RCVD_ACK, i2c->regs + I2C_ISR);
rk29_i2c_stop(i2c, -ENXIO);
dev_err(i2c->dev, "START: addr[0x%02x] ack was not received(isr)\n", i2c->addr);
goto out;
}
if ((lsr & I2C_LSR_RCV_NAK) &&
!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
writel(isr & ~I2C_ISR_MTX_RCVD_ACK, i2c->regs + I2C_ISR);
rk29_i2c_stop(i2c, -EAGAIN);
dev_err(i2c->dev, "START: addr[0x%02x] ack was not received(lsr)\n", i2c->addr);
goto out;
}
if (i2c->msg->flags & I2C_M_RD)
i2c->state = STATE_READ;
else
i2c->state = STATE_WRITE;
/* terminate the transfer if there is nothing to do
* as this is used by the i2c probe to find devices. */
if (is_lastmsg(i2c) && i2c->msg->len == 0) {
writel(isr & ~I2C_ISR_MTX_RCVD_ACK, i2c->regs + I2C_ISR);
rk29_i2c_stop(i2c, 0);
goto out;
}
if (i2c->state == STATE_READ){
writel(isr & ~I2C_ISR_MTX_RCVD_ACK, i2c->regs + I2C_ISR);
goto prepare_read;
}
case STATE_WRITE:
if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
if (!(isr & I2C_ISR_MTX_RCVD_ACK)){
rk29_i2c_stop(i2c, -ECONNREFUSED);
dev_err(i2c->dev, "WRITE: addr[0x%02x] No Ack\n", i2c->addr);
goto out;
}
}
writel(isr & ~I2C_ISR_MTX_RCVD_ACK, i2c->regs + I2C_ISR);
retry_write:
if (!is_msgend(i2c)) {
byte = i2c->msg->buf[i2c->msg_ptr++];
conr = readl(i2c->regs + I2C_CONR);
conr |= I2C_CONR_MTX_MODE;
writel(conr, i2c->regs + I2C_CONR);
writel(byte, i2c->regs + I2C_MTXR);
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
} else if (!is_lastmsg(i2c)) {
/* we need to go to the next i2c message */
i2c_dbg(i2c->dev, "WRITE: Next Message\n");
i2c->msg_ptr = 0;
i2c->msg_idx++;
i2c->msg++;
/* check to see if we need to do another message */
if (i2c->msg->flags & I2C_M_NOSTART) {
if (i2c->msg->flags & I2C_M_RD) {
/* cannot do this, the controller
* forces us to send a new START
* when we change direction */
rk29_i2c_stop(i2c, -EINVAL);
}
goto retry_write;
} else {
/* send the new start */
rk29_i2c_message_start(i2c, i2c->msg);
i2c->state = STATE_START;
}
} else {
/* send stop */
rk29_i2c_stop(i2c, 0);
}
break;
case STATE_READ:
if(!(isr & I2C_ISR_MRX_NEED_ACK)){
rk29_i2c_stop(i2c, -ENXIO);
dev_err(i2c->dev, "READ: addr[0x%02x] not recv need ack interrupt\n", i2c->addr);
goto out;
}
writel(isr & ~I2C_ISR_MRX_NEED_ACK, i2c->regs + I2C_ISR);
byte = readl(i2c->regs + I2C_MRXR);
i2c_dbg(i2c->dev, "READ: byte = %d\n", byte);
i2c->msg->buf[i2c->msg_ptr++] = byte;
prepare_read:
if (is_msgend(i2c)) {
if (is_lastmsg(i2c)) {
/* last message, send stop and complete */
rk29_i2c_disable_ack(i2c);
i2c_dbg(i2c->dev, "READ: Send Stop\n");
rk29_i2c_stop(i2c, 0);
} else {
/* go to the next transfer */
i2c_dbg(i2c->dev, "READ: Next Transfer\n");
i2c->msg_ptr = 0;
i2c->msg_idx++;
i2c->msg++;
rk29_i2c_message_start(i2c, i2c->msg);
i2c->state = STATE_START;
}
}else{
conr = readl(i2c->regs + I2C_CONR);
conr &= I2C_CONR_MRX_MODE;
writel(conr, i2c->regs + I2C_CONR);
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
}
break;
}
out:
return ret;
}
static irqreturn_t rk29_i2c_irq(int irqno, void *dev_id)
{
struct rk30_i2c *i2c = dev_id;
unsigned long isr;
spin_lock(&i2c->lock);
udelay(i2c->tx_setup);
isr = readl(i2c->regs + I2C_ISR);
if (isr & I2C_ISR_ARBITR_LOSE) {
writel(isr & ~I2C_ISR_ARBITR_LOSE, i2c->regs + I2C_ISR);
dev_err(i2c->dev, "deal with arbitration loss\n");
}
if (i2c->state == STATE_IDLE) {
i2c_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
goto out;
}
rk29_i2c_irq_nextbyte(i2c, isr);
out:
spin_unlock(&i2c->lock);
return IRQ_HANDLED;
}
/* rk29_i2c_set_master
*
* get the i2c bus for a master transaction
*/
static int rk29_i2c_set_master(struct rk30_i2c *i2c)
{
int tmo = RK29_I2C_START_TMO_COUNT;
unsigned long lsr;
while (tmo-- > 0) {
lsr = readl(i2c->regs + I2C_LSR);
if (!(lsr & I2C_LSR_BUSY))
return 0;
writel(I2C_LCMR_STOP|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
msleep(1);
}
return -ETIMEDOUT;
}
/* rk29_i2c_doxfer
*
* this starts an i2c transfer
*/
static int rk29_i2c_doxfer(struct rk30_i2c *i2c,
struct i2c_msg *msgs, int num)
{
unsigned long timeout;
int ret;
if (i2c->suspended)
return -EIO;
ret = rk29_i2c_set_master(i2c);
if (ret != 0) {
dev_err(i2c->dev, "addr[0x%02x] cannot get bus (error %d)\n", msgs[0].addr, ret);
ret = -EAGAIN;
goto out;
}
spin_lock_irq(&i2c->lock);
i2c->msg = msgs;
i2c->msg_num = num;
i2c->msg_ptr = 0;
i2c->msg_idx = 0;
i2c->state = STATE_START;
rk29_i2c_enable_irq(i2c);
rk29_i2c_message_start(i2c, msgs);
spin_unlock_irq(&i2c->lock);
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, msecs_to_jiffies(I2C_WAIT_TIMEOUT));
ret = i2c->msg_idx;
if (timeout == 0)
i2c_dbg(i2c->dev, "addr[0x%02x] wait event timeout\n", msgs[0].addr);
else if (ret != num)
i2c_dbg(i2c->dev, "addr[0x%02x ]incomplete xfer (%d)\n", msgs[0].addr, ret);
if((readl(i2c->regs + I2C_LSR) & I2C_LSR_BUSY) ||
readl(i2c->regs + I2C_LCMR) & I2C_LCMR_STOP ){
msleep(1);
writel(I2C_LCMR_STOP|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
if((readl(i2c->regs + I2C_LSR) & I2C_LSR_BUSY) ||
readl(i2c->regs + I2C_LCMR) & I2C_LCMR_STOP ){
dev_warn(i2c->dev, "WARNING: STOP abnormal, addr[0x%02x] isr = 0x%x, lsr = 0x%x, lcmr = 0x%x\n",
msgs[0].addr,
readl(i2c->regs + I2C_ISR),
readl(i2c->regs + I2C_LSR),
readl(i2c->regs + I2C_LCMR)
);
}
}
out:
return ret;
}
/* rk29_i2c_xfer
*
* first port of call from the i2c bus code when an message needs
* transferring across the i2c bus.
*/
static int rk29_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct rk30_i2c *i2c = (struct rk30_i2c *)adap->algo_data;
int ret = 0;
unsigned long scl_rate;
clk_enable(i2c->clk);
if(msgs[0].scl_rate <= 400000 && msgs[0].scl_rate >= 10000)
scl_rate = msgs[0].scl_rate;
else if(msgs[0].scl_rate > 400000){
dev_warn(i2c->dev, "Warning: addr[0x%x] msg[0].scl_rate( = %dKhz) is too high!",
msgs[0].addr, msgs[0].scl_rate/1000);
scl_rate = 400000;
}
else{
dev_warn(i2c->dev, "Warning: addr[0x%x] msg[0].scl_rate( = %dKhz) is too low!",
msgs[0].addr, msgs[0].scl_rate/1000);
scl_rate = 10000;
}
if(i2c->is_div_from_arm[i2c->adap.nr])
wake_lock(&i2c->idlelock[i2c->adap.nr]);
rk29_i2c_set_clk(i2c, scl_rate);
rk29_i2c_enable_mport(i2c);
udelay(i2c->tx_setup);
ret = rk29_i2c_doxfer(i2c, msgs, num);
rk29_i2c_disable_mport(i2c);
if(i2c->is_div_from_arm[i2c->adap.nr])
wake_unlock(&i2c->idlelock[i2c->adap.nr]);
clk_disable(i2c->clk);
return ret;
}
/* declare our i2c functionality */
static u32 rk29_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
}
/* i2c bus registration info */
static const struct i2c_algorithm rk29_i2c_algorithm = {
.master_xfer = rk29_i2c_xfer,
.functionality = rk29_i2c_func,
};
int i2c_add_rk29_adapter(struct i2c_adapter *adap)
{
int ret = 0;
struct rk30_i2c *i2c = (struct rk30_i2c *)adap->algo_data;
adap->algo = &rk29_i2c_algorithm;
i2c->i2c_init_hw = &rk29_i2c_init_hw;
i2c->i2c_set_clk = &rk29_i2c_set_clk;
i2c->i2c_irq = &rk29_i2c_irq;
ret = i2c_add_numbered_adapter(adap);
return ret;
}

View File

@ -1,912 +0,0 @@
/* drivers/i2c/busses/i2c_rk29.c
*
* Copyright (C) 2010 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/completion.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/cpufreq.h>
#include <linux/device.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/wakelock.h>
#include <linux/slab.h>
#include <mach/board.h>
#include <asm/io.h>
#include "i2c-rk29.h"
#define DRV_NAME "rk29_i2c"
#define RETRY_NUM 1
#define RK29_UDELAY_TIME(scl_rate) ((400*1000)/(scl_rate))
/*max ACK delay time = RK29_I2C_ACK_TIMEOUT_COUNT * RK29_UDELAY_TIME(scl_rate) us */
#define RK29_I2C_ACK_TIMEOUT_COUNT (100 * 1000)
/*max STOP delay time = RK29_I2C_STOP_TIMEOUT_COUNT * RK29_UDELAY_TIME(scl_rate) us */
#define RK29_I2C_STOP_TIMEOUT_COUNT 70//1000
/*max START delay time = RK29_I2C_START_TIMEOUT_COUNT * RK29_UDELAY_TIME(scl_rate) us */
#define RK29_I2C_START_TIMEOUT_COUNT 1000
#if 0
#define i2c_dbg(dev, format, arg...) \
dev_printk(KERN_INFO , dev , format , ## arg)
#define i2c_err(dev, format, arg...) \
dev_printk(KERN_ERR , dev , format , ## arg)
#else
#define i2c_dbg(dev, format, arg...)
#define i2c_err(dev, format, arg...)
#endif
enum rk29_error {
RK29_ERROR_NONE = 0,
RK29_ERROR_ARBITR_LOSE,
RK29_ERROR_UNKNOWN
};
enum rk29_event {
RK29_EVENT_NONE = 0,
/* master has received ack(MTX mode)
means that data has been sent to slave.
*/
RK29_EVENT_MTX_RCVD_ACK,
/* master needs to send ack to slave(MRX mode)
means that data has been received from slave.
*/
RK29_EVENT_MRX_NEED_ACK,
RK29_EVENT_MAX
};
struct rk29_i2c_data {
struct device *dev;
struct i2c_adapter adap;
void __iomem *regs;
struct resource *ioarea;
unsigned int ack_timeout; //unit: us
unsigned int udelay_time; //unit: us
unsigned int suspended:1;
unsigned long scl_rate;
unsigned long i2c_rate;
struct clk *clk;
unsigned int mode;
int retry;
int poll_status;
unsigned int irq;
spinlock_t cmd_lock;
struct completion cmd_complete;
enum rk29_event cmd_event;
enum rk29_error cmd_err;
unsigned int msg_idx;
unsigned int msg_num;
int udelay;
int (*io_init)(void);
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
};
#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK30)
static struct wake_lock idlelock; /* only for i2c0 */
#endif
static void rk29_set_ack(struct rk29_i2c_data *i2c)
{
unsigned long conr = readl(i2c->regs + I2C_CONR);
conr &= I2C_CONR_ACK;
writel(conr,i2c->regs + I2C_CONR);
return;
}
static void rk29_set_nak(struct rk29_i2c_data *i2c)
{
unsigned long conr = readl(i2c->regs + I2C_CONR);
conr |= I2C_CONR_NAK;
writel(conr,i2c->regs + I2C_CONR);
return;
}
static inline void rk29_i2c_disable_irqs(struct rk29_i2c_data *i2c)
{
unsigned long tmp;
tmp = readl(i2c->regs + I2C_IER);
writel(tmp & IRQ_ALL_DISABLE, i2c->regs + I2C_IER);
}
static inline void rk29_i2c_enable_irqs(struct rk29_i2c_data *i2c)
{
unsigned long tmp;
tmp = readl(i2c->regs + I2C_IER);
writel(tmp | IRQ_MST_ENABLE, i2c->regs + I2C_IER);
}
/* scl = pclk/(5 *(rem+1) * 2^(exp+1)) */
static void rk29_i2c_calcdivisor(unsigned long pclk,
unsigned long scl_rate,
unsigned long *real_rate,
unsigned int *rem, unsigned int *exp)
{
unsigned int calc_rem = 0;
unsigned int calc_exp = 0;
for(calc_exp = 0; calc_exp < I2CCDVR_EXP_MAX; calc_exp++)
{
calc_rem = pclk / (5 * scl_rate * (1 <<(calc_exp +1)));
if(calc_rem < I2CCDVR_REM_MAX)
break;
}
if(calc_rem >= I2CCDVR_REM_MAX || calc_exp >= I2CCDVR_EXP_MAX)
{
calc_rem = I2CCDVR_REM_MAX - 1;
calc_exp = I2CCDVR_EXP_MAX - 1;
}
*rem = calc_rem;
*exp = calc_exp;
*real_rate = pclk/(5 * (calc_rem + 1) * (1 <<(calc_exp +1)));
return;
}
/* set i2c bus scl rate */
static void rk29_i2c_clockrate(struct rk29_i2c_data *i2c)
{
struct rk29_i2c_platform_data *pdata = i2c->dev->platform_data;
unsigned int rem = 0, exp = 0;
unsigned long scl_rate, real_rate = 0, tmp;
i2c->i2c_rate = clk_get_rate(i2c->clk);
scl_rate = (i2c->scl_rate) ? i2c->scl_rate : ((pdata->scl_rate)? pdata->scl_rate:100000);
rk29_i2c_calcdivisor(i2c->i2c_rate, scl_rate, &real_rate, &rem, &exp);
tmp = readl(i2c->regs + I2C_OPR);
tmp &= ~0x3f;
tmp |= exp;
tmp |= rem<<I2CCDVR_EXP_BITS;
writel(tmp, i2c->regs + I2C_OPR);
if(real_rate > 400000)
dev_warn(i2c->dev, "i2c_rate[%luKhz], scl_rate[%luKhz], real_rate[%luKhz] > 400Khz\n",
i2c->i2c_rate/1000, scl_rate/1000, real_rate/1000);
else
i2c_dbg(i2c->dev, "i2c_rate[%luKhz], scl_rate[%luKhz], real_rate[%luKhz]\n",
i2c->i2c_rate/1000, scl_rate/1000, real_rate/1000);
return;
}
static int rk29_event_occurred(struct rk29_i2c_data *i2c)
{
unsigned long isr, lsr;
isr = readl(i2c->regs + I2C_ISR);
lsr = readl(i2c->regs + I2C_LSR);
i2c_dbg(i2c->dev,"event occurred, isr = %lx, lsr = %lx\n", isr, lsr);
if(isr & I2C_ISR_ARBITR_LOSE)
{
writel(0, i2c->regs + I2C_ISR);
i2c->cmd_err = RK29_ERROR_ARBITR_LOSE;
i2c_err(i2c->dev, "<error>arbitration loss\n");
return 0;
}
switch(i2c->cmd_event)
{
case RK29_EVENT_MTX_RCVD_ACK:
if(isr & I2C_ISR_MTX_RCVD_ACK)
{
isr &= ~I2C_ISR_MTX_RCVD_ACK;
writel(isr, i2c->regs + I2C_ISR);
return 1;
}
break;
case RK29_EVENT_MRX_NEED_ACK:
if(isr & I2C_ISR_MRX_NEED_ACK)
{
isr &= ~I2C_ISR_MRX_NEED_ACK;
writel(isr, i2c->regs + I2C_ISR);
return 1;
}
break;
default:
break;
}
writel(0, i2c->regs + I2C_ISR);
i2c->cmd_err = RK29_ERROR_UNKNOWN;
return 0;
}
static irqreturn_t rk29_i2c_irq(int irq, void *data)
{
struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)data;
int res;
rk29_i2c_disable_irqs(i2c);
spin_lock(&i2c->cmd_lock);
res = rk29_event_occurred(i2c);
if(res)
{
if(i2c->mode == I2C_MODE_IRQ)
complete(&i2c->cmd_complete);
else
i2c->poll_status = 1;
}
spin_unlock(&i2c->cmd_lock);
return IRQ_HANDLED;
}
static int wait_for_completion_poll_timeout(struct rk29_i2c_data *i2c)
{
int tmo = RK29_I2C_ACK_TIMEOUT_COUNT;
while(--tmo)
{
if(i2c->poll_status == 1)
return 1;
udelay(i2c->udelay_time);
}
return 0;
}
static int rk29_wait_event(struct rk29_i2c_data *i2c,
enum rk29_event mr_event)
{
int ret = 0;
if(unlikely(irqs_disabled()))
{
i2c_err(i2c->dev, "irqs are disabled on this system!\n");
return -EIO;
}
i2c->cmd_err = RK29_ERROR_NONE;
i2c->cmd_event = mr_event;
rk29_i2c_enable_irqs(i2c);
if(i2c->mode == I2C_MODE_IRQ)
{
ret = wait_for_completion_interruptible_timeout(&i2c->cmd_complete,
usecs_to_jiffies(i2c->ack_timeout));
}
else
{
i2c->poll_status = 0;
ret = wait_for_completion_poll_timeout(i2c);
}
if(ret < 0)
{
i2c_err(i2c->dev, "i2c wait for event %04x, retrun %d \n", mr_event, ret);
return ret;
}
if(ret == 0)
{
i2c_err(i2c->dev, "i2c wait for envent timeout, but not return -ETIMEDOUT\n");
return 0;
//return -ETIMEDOUT;
}
return 0;
}
static void rk29_i2c_stop(struct rk29_i2c_data *i2c)
{
int tmo = RK29_I2C_STOP_TIMEOUT_COUNT;
writel(I2C_LCMR_STOP|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
while(--tmo && !(readl(i2c->regs + I2C_LCMR) & I2C_LCMR_STOP))
{
udelay(i2c->udelay_time);
}
writel(0, i2c->regs + I2C_ISR);
rk29_i2c_disable_irqs(i2c);
udelay(tmo);
return;
}
static void rk29_wait_while_busy(struct rk29_i2c_data *i2c)
{
int tmo = RK29_I2C_START_TIMEOUT_COUNT;
while(--tmo && (readl(i2c->regs + I2C_LSR) & I2C_LSR_BUSY))
{
udelay(i2c->udelay_time);
}
return;
}
static int rk29_send_2nd_addr(struct rk29_i2c_data *i2c,
struct i2c_msg *msg, int start)
{
int ret = 0;
unsigned long lsr;
unsigned long addr_2nd = msg->addr & 0xff;
i2c_dbg(i2c->dev, "i2c send addr_2nd: %lx\n", addr_2nd);
writel(addr_2nd, i2c->regs + I2C_MTXR);
if(i2c->mode == I2C_MODE_IRQ)
INIT_COMPLETION(i2c->cmd_complete);
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
rk29_set_ack(i2c);
if((ret = rk29_wait_event(i2c, RK29_EVENT_MTX_RCVD_ACK)) != 0)
{
i2c_err(i2c->dev, "after sent addr_2nd, i2c wait for ACK timeout\n");
return ret;
}
lsr = readl(i2c->regs + I2C_LSR);
if((lsr & I2C_LSR_RCV_NAK) && !(msg->flags & I2C_M_IGNORE_NAK))
return -EINVAL;
return ret;
}
static int rk29_send_address(struct rk29_i2c_data *i2c,
struct i2c_msg *msg, int start)
{
unsigned long addr_1st;
unsigned long conr,lsr;
int ret = 0;
if(msg->flags & I2C_M_TEN)
addr_1st = (0xf0 | (((unsigned long) msg->addr & 0x300) >> 7)) & 0xff;
else
addr_1st = ((msg->addr << 1) & 0xff);
if (msg->flags & I2C_M_RD)
addr_1st |= 0x01;
else
addr_1st &= (~0x01);
if(start)
rk29_wait_while_busy(i2c);
writel(0, i2c->regs + I2C_ISR);
conr = readl(i2c->regs + I2C_CONR);
conr |= I2C_CONR_MTX_MODE;
conr |= I2C_CONR_MPORT_ENABLE;
writel(conr, i2c->regs + I2C_CONR);
i2c_dbg(i2c->dev, "i2c send addr_1st: %lx\n", addr_1st);
writel(addr_1st, i2c->regs + I2C_MTXR);
rk29_set_ack(i2c);
if(i2c->mode == I2C_MODE_IRQ)
INIT_COMPLETION(i2c->cmd_complete);
writel(I2C_LCMR_START|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
if((ret = rk29_wait_event(i2c, RK29_EVENT_MTX_RCVD_ACK)) != 0)
{
i2c_err(i2c->dev, "after sent addr_1st, i2c wait for ACK timeout\n");
return ret;
}
lsr = readl(i2c->regs + I2C_LSR);
if((lsr & I2C_LSR_RCV_NAK) && !(msg->flags & I2C_M_IGNORE_NAK))
{
dev_info(i2c->dev, "addr: 0x%x receive no ack\n", msg->addr);
return -EAGAIN;
}
if(start && (msg->flags & I2C_M_TEN))
ret = rk29_send_2nd_addr(i2c, msg, start);
return ret;
}
static int rk29_i2c_send_msg(struct rk29_i2c_data *i2c, struct i2c_msg *msg)
{
int i, ret = 0;
unsigned long conr, lsr;
conr = readl(i2c->regs + I2C_CONR);
conr |= I2C_CONR_MTX_MODE;
//conr |= I2C_CONR_MPORT_ENABLE;
writel(conr, i2c->regs + I2C_CONR);
for(i = 0; i < msg->len; i++)
{
i2c_dbg(i2c->dev, "i2c send buf[%d]: %x\n", i, msg->buf[i]);
writel(msg->buf[i], i2c->regs + I2C_MTXR);
rk29_set_ack(i2c);
if(i2c->mode == I2C_MODE_IRQ)
INIT_COMPLETION(i2c->cmd_complete);
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
if((ret = rk29_wait_event(i2c, RK29_EVENT_MTX_RCVD_ACK)) != 0)
return ret;
lsr = readl(i2c->regs + I2C_LSR);
if((lsr & I2C_LSR_RCV_NAK) && (i != msg->len -1) && !(msg->flags & I2C_M_IGNORE_NAK))
return -EINVAL;
udelay(i2c->udelay);
}
return ret;
}
static int rk29_i2c_recv_msg(struct rk29_i2c_data *i2c, struct i2c_msg *msg)
{
int i, ret = 0;
unsigned long conr;
conr = readl(i2c->regs + I2C_CONR);
conr &= I2C_CONR_MRX_MODE;
//conr |= I2C_CONR_MPORT_ENABLE;
writel(conr, i2c->regs + I2C_CONR);
for(i = 0; i < msg->len; i++)
{
if(i2c->mode == I2C_MODE_IRQ)
INIT_COMPLETION(i2c->cmd_complete);
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
if((ret = rk29_wait_event(i2c, RK29_EVENT_MRX_NEED_ACK)) != 0)
return ret;
msg->buf[i] = (uint8_t)readl(i2c->regs + I2C_MRXR);
if( i == msg->len -1)
rk29_set_nak(i2c);
else
rk29_set_ack(i2c);
udelay(i2c->udelay);
i2c_dbg(i2c->dev, "i2c recv >>>>>>>>>>>> buf[%d]: %x\n", i, msg->buf[i]);
}
return ret;
}
static int rk29_xfer_msg(struct i2c_adapter *adap,
struct i2c_msg *msg, int start, int stop)
{
struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)adap->algo_data;
int ret = 0;
if(msg->len == 0)
{
ret = -EINVAL;
i2c_err(i2c->dev, "<error>msg->len = %d\n", msg->len);
goto exit;
}
if(msg->flags & I2C_M_NEED_DELAY)
i2c->udelay = msg->udelay;
else
i2c->udelay = 0;
if((ret = rk29_send_address(i2c, msg, start))!= 0)
{
rk29_set_nak(i2c);
i2c_err(i2c->dev, "<error>rk29_send_address timeout\n");
goto exit;
}
if(msg->flags & I2C_M_RD)
{
if(msg->flags & I2C_M_REG8_DIRECT)
{
struct i2c_msg msg1 = *msg;
struct i2c_msg msg2 = *msg;
msg1.len = 1;
msg2.len = msg->len - 1;
msg2.buf = msg->buf + 1;
if((ret = rk29_i2c_send_msg(i2c, &msg1)) != 0)
i2c_err(i2c->dev, "<error>rk29_i2c_send_msg timeout\n");
if((ret = rk29_i2c_recv_msg(i2c, &msg2)) != 0)
{
i2c_err(i2c->dev, "<error>rk29_i2c_recv_msg timeout\n");
goto exit;
}
}
else if((ret = rk29_i2c_recv_msg(i2c, msg)) != 0)
{
i2c_err(i2c->dev, "<error>rk29_i2c_recv_msg timeout\n");
goto exit;
}
}
else
{
if((ret = rk29_i2c_send_msg(i2c, msg)) != 0)
{
rk29_set_nak(i2c);
i2c_err(i2c->dev, "<error>rk29_i2c_send_msg timeout\n");
goto exit;
}
}
exit:
if(stop || ret < 0)
{
rk29_i2c_stop(i2c);
}
return ret;
}
static int rk29_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
int ret = -1;
int i;
struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)adap->algo_data;
//int retry = i2c->retry;
/*
if(i2c->suspended ==1)
return -EIO;
*/
// 400k > scl_rate > 10k
if(msgs[0].scl_rate <= 400000 && msgs[0].scl_rate >= 10000)
i2c->scl_rate = msgs[0].scl_rate;
else if(msgs[0].scl_rate > 400000){
dev_info(i2c->dev, "Warning: msg[0].scl_rate( = %dKhz) is too high!",
msgs[0].scl_rate/1000);
i2c->scl_rate = 400000;
}
else{
dev_info(i2c->dev, "Warning: msg[0].scl_rate( = %dKhz) is too low!",
msgs[0].scl_rate/1000);
i2c->scl_rate = 10000;
}
rk29_i2c_clockrate(i2c);
i2c->udelay_time = RK29_UDELAY_TIME(i2c->scl_rate);
i2c->ack_timeout = RK29_I2C_ACK_TIMEOUT_COUNT * i2c->udelay_time;
#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK30)
if (adap->nr == 0)
wake_lock(&idlelock);
#endif
for (i = 0; i < num; i++)
{
ret = rk29_xfer_msg(adap, &msgs[i], (i == 0), (i == (num - 1)));
if (ret != 0)
{
num = ret;
i2c_err(i2c->dev, "rk29_xfer_msg error, ret = %d\n", ret);
break;
}
}
#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK30)
if (adap->nr == 0)
wake_unlock(&idlelock);
#endif
/*
if( --retry && num < 0)
{
udelay(10000 * 1000/i2c->scl_rate);
goto retry;
}
*/
if(num < 0)
dev_err(i2c->dev, "i2c transfer err, client address is 0x%x [20110106]\n", msgs[0].addr);
return num;
}
static u32 rk29_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
}
static const struct i2c_algorithm rk29_i2c_algorithm = {
.master_xfer = rk29_i2c_xfer,
.functionality = rk29_i2c_func,
};
int i2c_suspended(struct i2c_adapter *adap)
{
struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)adap->algo_data;
if(adap->nr > 1)
return 1;
if(i2c == NULL)
return 1;
return i2c->suspended;
}
EXPORT_SYMBOL(i2c_suspended);
static void rk29_i2c_deinit_hw(struct rk29_i2c_data *i2c)
{
unsigned long opr = readl(i2c->regs + I2C_OPR);
opr &= ~I2C_OPR_RESET_STATUS;
writel(opr, i2c->regs);
return;
}
static void rk29_i2c_init_hw(struct rk29_i2c_data *i2c)
{
unsigned long opr = readl(i2c->regs + I2C_OPR);
opr |= I2C_OPR_RESET_STATUS;
writel(opr, i2c->regs + I2C_OPR);
udelay(10);
opr = readl(i2c->regs + I2C_OPR);
opr &= ~I2C_OPR_RESET_STATUS;
writel(opr, i2c->regs + I2C_OPR);
rk29_i2c_clockrate(i2c);
rk29_i2c_disable_irqs(i2c);
writel(0, i2c->regs + I2C_LCMR);
writel(0, i2c->regs + I2C_LCMR);
opr = readl(i2c->regs + I2C_OPR);
opr |= I2C_OPR_CORE_ENABLE;
writel(opr, i2c->regs + I2C_OPR);
return;
}
#ifdef CONFIG_CPU_FREQ
#define freq_to_i2c(_n) container_of(_n, struct rk29_i2c_data, freq_transition)
static int rk29_i2c_cpufreq_transition(struct notifier_block *nb,
unsigned long val, void *data)
{
struct rk29_i2c_data *i2c = freq_to_i2c(nb);
unsigned long flags;
int delta_f;
delta_f = clk_get_rate(i2c->clk) - i2c->i2c_rate;
if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||
(val == CPUFREQ_PRECHANGE && delta_f > 0))
{
spin_lock_irqsave(&i2c->cmd_lock, flags);
rk29_i2c_clockrate(i2c);
spin_unlock_irqrestore(&i2c->cmd_lock, flags);
}
return 0;
}
static inline int rk29_i2c_register_cpufreq(struct rk29_i2c_data *i2c)
{
if (i2c->adap.nr != 0)
return 0;
i2c->freq_transition.notifier_call = rk29_i2c_cpufreq_transition;
return cpufreq_register_notifier(&i2c->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
}
static inline void rk29_i2c_unregister_cpufreq(struct rk29_i2c_data *i2c)
{
if (i2c->adap.nr != 0)
return;
cpufreq_unregister_notifier(&i2c->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
}
#else
static inline int rk29_i2c_register_cpufreq(struct rk29_i2c_data *i2c)
{
return 0;
}
static inline void rk29_i2c_unregister_cpufreq(struct rk29_i2c_data *i2c)
{
return;
}
#endif
static int rk29_i2c_probe(struct platform_device *pdev)
{
struct rk29_i2c_data *i2c;
struct rk29_i2c_platform_data *pdata = NULL;
struct resource *res;
int ret;
pdata = pdev->dev.platform_data;
if (!pdata)
{
i2c_err(&pdev->dev, "<error>no platform data\n");
return -EINVAL;
}
i2c = kzalloc(sizeof(struct rk29_i2c_data), GFP_KERNEL);
if (!i2c)
{
i2c_err(&pdev->dev, "<error>no memory for state\n");
return -ENOMEM;
}
init_completion(&i2c->cmd_complete);
i2c->retry = RETRY_NUM;
i2c->mode = pdata->mode;
i2c->scl_rate = (pdata->scl_rate) ? pdata->scl_rate : 100000;
strlcpy(i2c->adap.name, DRV_NAME, sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &rk29_i2c_algorithm;
i2c->adap.class = I2C_CLASS_HWMON;
i2c->adap.nr = pdata->bus_num;
i2c->adap.retries = 3;
i2c->adap.timeout = msecs_to_jiffies(500);
spin_lock_init(&i2c->cmd_lock);
i2c->dev = &pdev->dev;
i2c->clk = clk_get(&pdev->dev, "i2c");
if (IS_ERR(i2c->clk)) {
i2c_err(&pdev->dev, "<error>cannot get clock\n");
ret = -ENOENT;
goto err_noclk;
}
clk_enable(i2c->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
i2c_err(&pdev->dev, "<error>cannot find IO resource\n");
ret = -ENOENT;
goto err_clk;
}
i2c->ioarea = request_mem_region(res->start, res->end - res->start + 1,
pdev->name);
if (i2c->ioarea == NULL) {
i2c_err(&pdev->dev, "<error>cannot request IO\n");
ret = -ENXIO;
goto err_clk;
}
i2c->regs = ioremap(res->start, res->end - res->start + 1);
if (i2c->regs == NULL) {
i2c_err(&pdev->dev, "<error>annot map IO\n");
ret = -ENXIO;
goto err_ioarea;
}
i2c->adap.algo_data = i2c;
i2c->adap.dev.parent = &pdev->dev;
if(pdata->io_init)
{
i2c->io_init = pdata->io_init;
pdata->io_init();
}
i2c->irq = ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
i2c_err(&pdev->dev, "cannot find IRQ\n");
goto err_iomap;
}
ret = request_irq(i2c->irq, rk29_i2c_irq, IRQF_DISABLED,
dev_name(&pdev->dev), i2c);
if (ret != 0) {
i2c_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
goto err_iomap;
}
ret = rk29_i2c_register_cpufreq(i2c);
if (ret < 0) {
i2c_err(&pdev->dev, "failed to register cpufreq notifier\n");
goto err_irq;
}
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0) {
i2c_err(&pdev->dev, "failed to add bus to i2c core\n");
goto err_cpufreq;
}
platform_set_drvdata(pdev, i2c);
rk29_i2c_init_hw(i2c);
dev_info(&pdev->dev, "%s: RK29 I2C adapter\n", dev_name(&i2c->adap.dev));
return 0;
err_cpufreq:
rk29_i2c_unregister_cpufreq(i2c);
err_irq:
free_irq(i2c->irq, i2c);
err_iomap:
iounmap(i2c->regs);
err_ioarea:
release_resource(i2c->ioarea);
kfree(i2c->ioarea);
err_clk:
clk_disable(i2c->clk);
clk_put(i2c->clk);
err_noclk:
kfree(i2c);
return ret;
}
static int rk29_i2c_remove(struct platform_device *pdev)
{
struct rk29_i2c_data *i2c = platform_get_drvdata(pdev);
rk29_i2c_deinit_hw(i2c);
rk29_i2c_unregister_cpufreq(i2c);
i2c_del_adapter(&i2c->adap);
free_irq(i2c->irq, i2c);
clk_disable(i2c->clk);
clk_put(i2c->clk);
iounmap(i2c->regs);
release_resource(i2c->ioarea);
kfree(i2c->ioarea);
kfree(i2c);
return 0;
}
#ifdef CONFIG_PM
static int rk29_i2c_suspend_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rk29_i2c_data *i2c = platform_get_drvdata(pdev);
i2c->suspended = 1;
return 0;
}
static int rk29_i2c_resume_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rk29_i2c_data *i2c = platform_get_drvdata(pdev);
i2c->suspended = 0;
rk29_i2c_init_hw(i2c);
return 0;
}
static struct dev_pm_ops rk29_i2c_pm_ops = {
.suspend_noirq = rk29_i2c_suspend_noirq,
.resume_noirq = rk29_i2c_resume_noirq,
};
#endif
static struct platform_driver rk29_i2c_driver = {
.probe = rk29_i2c_probe,
.remove = rk29_i2c_remove,
.driver = {
.owner = THIS_MODULE,
.name = DRV_NAME,
#ifdef CONFIG_PM
.pm = &rk29_i2c_pm_ops,
#endif
},
};
static int __init rk29_i2c_adap_init(void)
{
#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK30)
wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "i2c0");
#endif
return platform_driver_register(&rk29_i2c_driver);
}
static void __exit rk29_i2c_adap_exit(void)
{
platform_driver_unregister(&rk29_i2c_driver);
}
subsys_initcall(rk29_i2c_adap_init);
module_exit(rk29_i2c_adap_exit);
MODULE_DESCRIPTION("Driver for RK29 I2C Bus");
MODULE_AUTHOR("kfx, kfx@rock-chips.com");
MODULE_LICENSE("GPL");

View File

@ -1,73 +0,0 @@
/* drivers/i2c/busses/i2c_rk2818.h
*
* Copyright (C) 2010 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#ifndef __RK2818_I2C_H
#define __RK2818_I2C_H
/* master transmit */
#define I2C_MTXR (0x0000)
/* master receive */
#define I2C_MRXR (0x0004)
/* slave address */
#define I2C_SADDR (0x0010)
/* interrupt enable control */
#define I2C_IER (0x0014)
#define I2C_IER_ARBITR_LOSE (1<<7)
#define I2C_IER_MRX_NEED_ACK (1<<1)
#define I2C_IER_MTX_RCVD_ACK (1<<0)
#define IRQ_MST_ENABLE (I2C_IER_ARBITR_LOSE | \
I2C_IER_MRX_NEED_ACK | \
I2C_IER_MTX_RCVD_ACK)
#define IRQ_ALL_DISABLE (0x00)
/* interrupt status, write 0 to clear */
#define I2C_ISR (0x0018)
#define I2C_ISR_ARBITR_LOSE (1<<7)
#define I2C_ISR_MRX_NEED_ACK (1<<1)
#define I2C_ISR_MTX_RCVD_ACK (1<<0)
/* stop/start/resume command, write 1 to set */
#define I2C_LCMR (0x001c)
#define I2C_LCMR_RESUME (1<<2)
#define I2C_LCMR_STOP (1<<1)
#define I2C_LCMR_START (1<<0)
/* i2c core status */
#define I2C_LSR (0x0020)
#define I2C_LSR_RCV_NAK (1<<1)
#define I2C_LSR_RCV_ACK (~(1<<1))
#define I2C_LSR_BUSY (1<<0)
/* i2c config */
#define I2C_CONR (0x0024)
#define I2C_CONR_NAK (1<<4)
#define I2C_CONR_ACK (~(1<<4))
#define I2C_CONR_MTX_MODE (1<<3)
#define I2C_CONR_MRX_MODE (~(1<<3))
#define I2C_CONR_MPORT_ENABLE (1<<2)
#define I2C_CONR_MPORT_DISABLE (~(1<<2))
/* i2c core config */
#define I2C_OPR (0x0028)
#define I2C_OPR_RESET_STATUS (1<<7)
#define I2C_OPR_CORE_ENABLE (1<<6)
#define I2CCDVR_REM_BITS (0x03)
#define I2CCDVR_REM_MAX (1<<(I2CCDVR_REM_BITS))
#define I2CCDVR_EXP_BITS (0x03)
#define I2CCDVR_EXP_MAX (1<<(I2CCDVR_EXP_BITS))
#endif

View File

@ -1,708 +0,0 @@
/* drivers/i2c/busses/i2c-rk30-adapter.c
*
* Copyright (C) 2012 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include "i2c-rk30.h"
#define COMPLETE_READ (1<<STATE_START|1<<STATE_READ|1<<STATE_STOP)
#define COMPLETE_WRITE (1<<STATE_START|1<<STATE_WRITE|1<<STATE_STOP)
/* Control register */
#define I2C_CON 0x000
#define I2C_CON_EN (1 << 0)
#define I2C_CON_MOD(mod) ((mod) << 1)
#define I2C_CON_MASK (3 << 1)
enum{
I2C_CON_MOD_TX = 0,
I2C_CON_MOD_TRX,
I2C_CON_MOD_RX,
I2C_CON_MOD_RRX,
};
#define I2C_CON_START (1 << 3)
#define I2C_CON_STOP (1 << 4)
#define I2C_CON_LASTACK (1 << 5)
#define I2C_CON_ACTACK (1 << 6)
/* Clock dividor register */
#define I2C_CLKDIV 0x004
#define I2C_CLKDIV_VAL(divl, divh) (((divl) & 0xffff) | (((divh) << 16) & 0xffff0000))
/* the slave address accessed for master rx mode */
#define I2C_MRXADDR 0x008
#define I2C_MRXADDR_LOW (1 << 24)
#define I2C_MRXADDR_MID (1 << 25)
#define I2C_MRXADDR_HIGH (1 << 26)
/* the slave register address accessed for master rx mode */
#define I2C_MRXRADDR 0x00c
#define I2C_MRXRADDR_LOW (1 << 24)
#define I2C_MRXRADDR_MID (1 << 25)
#define I2C_MRXRADDR_HIGH (1 << 26)
/* master tx count */
#define I2C_MTXCNT 0x010
/* master rx count */
#define I2C_MRXCNT 0x014
/* interrupt enable register */
#define I2C_IEN 0x018
#define I2C_BTFIEN (1 << 0)
#define I2C_BRFIEN (1 << 1)
#define I2C_MBTFIEN (1 << 2)
#define I2C_MBRFIEN (1 << 3)
#define I2C_STARTIEN (1 << 4)
#define I2C_STOPIEN (1 << 5)
#define I2C_NAKRCVIEN (1 << 6)
#define IRQ_MST_ENABLE (I2C_MBTFIEN | I2C_MBRFIEN | I2C_NAKRCVIEN | I2C_STARTIEN | I2C_STOPIEN)
#define IRQ_ALL_DISABLE 0
/* interrupt pending register */
#define I2C_IPD 0x01c
#define I2C_BTFIPD (1 << 0)
#define I2C_BRFIPD (1 << 1)
#define I2C_MBTFIPD (1 << 2)
#define I2C_MBRFIPD (1 << 3)
#define I2C_STARTIPD (1 << 4)
#define I2C_STOPIPD (1 << 5)
#define I2C_NAKRCVIPD (1 << 6)
#define I2C_HOLD_SCL (1 << 7)
#define I2C_IPD_ALL_CLEAN 0x7f
/* finished count */
#define I2C_FCNT 0x020
/* I2C tx data register */
#define I2C_TXDATA_BASE 0X100
/* I2C rx data register */
#define I2C_RXDATA_BASE 0x200
static void rk30_show_regs(struct rk30_i2c *i2c)
{
int i;
dev_info(i2c->dev, "i2c->clk = %lu\n", clk_get_rate(i2c->clk));
dev_info(i2c->dev, "i2c->start = %d\n", i2c->state);
dev_info(i2c->dev, "I2C_CON: 0x%08x\n", i2c_readl(i2c->regs + I2C_CON));
dev_info(i2c->dev, "I2C_CLKDIV: 0x%08x\n", i2c_readl(i2c->regs + I2C_CLKDIV));
dev_info(i2c->dev, "I2C_MRXADDR: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXADDR));
dev_info(i2c->dev, "I2C_MRXRADDR: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXRADDR));
dev_info(i2c->dev, "I2C_MTXCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_MTXCNT));
dev_info(i2c->dev, "I2C_MRXCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_MRXCNT));
dev_info(i2c->dev, "I2C_IEN: 0x%08x\n", i2c_readl(i2c->regs + I2C_IEN));
dev_info(i2c->dev, "I2C_IPD: 0x%08x\n", i2c_readl(i2c->regs + I2C_IPD));
dev_info(i2c->dev, "I2C_FCNT: 0x%08x\n", i2c_readl(i2c->regs + I2C_FCNT));
for( i = 0; i < 8; i ++)
dev_info(i2c->dev, "I2C_TXDATA%d: 0x%08x\n", i, i2c_readl(i2c->regs + I2C_TXDATA_BASE + i * 4));
for( i = 0; i < 8; i ++)
dev_info(i2c->dev, "I2C_RXDATA%d: 0x%08x\n", i, i2c_readl(i2c->regs + I2C_RXDATA_BASE + i * 4));
}
static int rk30_i2c_check_idle(struct rk30_i2c *i2c)
{
int ret = 0;
int sda_io, scl_io;
int sda_lev, scl_lev;
sda_io = iomux_mode_to_gpio(i2c->sda_mode);
scl_io = iomux_mode_to_gpio(i2c->scl_mode);
ret = gpio_request(sda_io, NULL);
if(unlikely(ret < 0)){
dev_err(i2c->dev, "Failed to request gpio: SDA_GPIO\n");
return ret;
}
ret = gpio_request(scl_io, NULL);
if(unlikely(ret < 0)){
dev_err(i2c->dev, "Failed to request gpio: SCL_GPIO\n");
gpio_free(sda_io);
return ret;
}
gpio_direction_input(sda_io);
gpio_direction_input(scl_io);
sda_lev = gpio_get_value(sda_io);
scl_lev = gpio_get_value(scl_io);
gpio_free(sda_io);
gpio_free(scl_io);
iomux_set(i2c->sda_mode);
iomux_set(i2c->scl_mode);
if(sda_lev == 1 && scl_lev == 1)
return I2C_IDLE;
else if(sda_lev == 0 && scl_lev == 1)
return I2C_SDA_LOW;
else if(sda_lev == 1 && scl_lev == 0)
return I2C_SCL_LOW;
else
return BOTH_LOW;
}
static inline void rk30_i2c_enable(struct rk30_i2c *i2c, unsigned int lastnak)
{
unsigned int con = 0;
con |= I2C_CON_EN;
con |= I2C_CON_MOD(i2c->mode);
if(lastnak)
con |= I2C_CON_LASTACK;
con |= I2C_CON_START;
i2c_writel(con, i2c->regs + I2C_CON);
}
static inline void rk30_i2c_disable(struct rk30_i2c *i2c)
{
i2c_writel( 0, i2c->regs + I2C_CON);
}
static inline void rk30_i2c_clean_start(struct rk30_i2c *i2c)
{
unsigned int con = i2c_readl(i2c->regs + I2C_CON);
con &= ~I2C_CON_START;
i2c_writel(con, i2c->regs + I2C_CON);
}
static inline void rk30_i2c_send_start(struct rk30_i2c *i2c)
{
unsigned int con = i2c_readl(i2c->regs + I2C_CON);
con |= I2C_CON_START;
if(con & I2C_CON_STOP)
dev_warn(i2c->dev, "I2C_CON: stop bit is set\n");
i2c_writel(con, i2c->regs + I2C_CON);
}
static inline void rk30_i2c_send_stop(struct rk30_i2c *i2c)
{
unsigned int con = i2c_readl(i2c->regs + I2C_CON);
con |= I2C_CON_STOP;
if(con & I2C_CON_START)
dev_warn(i2c->dev, "I2C_CON: start bit is set\n");
i2c_writel(con, i2c->regs + I2C_CON);
}
static inline void rk30_i2c_clean_stop(struct rk30_i2c *i2c)
{
unsigned int con = i2c_readl(i2c->regs + I2C_CON);
con &= ~I2C_CON_STOP;
i2c_writel(con, i2c->regs + I2C_CON);
}
static inline void rk30_i2c_disable_irq(struct rk30_i2c *i2c)
{
i2c_writel(IRQ_ALL_DISABLE, i2c->regs + I2C_IEN);
}
static inline void rk30_i2c_enable_irq(struct rk30_i2c *i2c)
{
i2c_writel(IRQ_MST_ENABLE, i2c->regs + I2C_IEN);
}
static void rk30_get_div(int div, int *divh, int *divl)
{
if(div % 2 == 0){
*divh = div/2;
*divl = div/2;
}else{
*divh = rk30_ceil(div, 2);
*divl = div/2;
}
}
/* SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1)
* SCL = i2c_rate/ SCLK Divisor
*/
static void rk30_i2c_set_clk(struct rk30_i2c *i2c, unsigned long scl_rate)
{
unsigned long i2c_rate = clk_get_rate(i2c->clk);
int div, divl, divh;
if((scl_rate == i2c->scl_rate) && (i2c_rate == i2c->i2c_rate))
return;
i2c->i2c_rate = i2c_rate;
i2c->scl_rate = scl_rate;
div = rk30_ceil(i2c_rate, (scl_rate * 8)) - 2;
if(unlikely(div < 0)){
dev_warn(i2c->dev, "Divisor(%d) is negative, set divl = divh = 0\n", div);
divh =divl = 0;
}else{
rk30_get_div(div, &divh, &divl);
}
i2c_writel(I2C_CLKDIV_VAL(divl, divh), i2c->regs + I2C_CLKDIV);
i2c_dbg(i2c->dev, "set clk(I2C_CLKDIV: 0x%08x)\n", i2c_readl(i2c->regs + I2C_CLKDIV));
return;
}
static void rk30_i2c_init_hw(struct rk30_i2c *i2c, unsigned long scl_rate)
{
i2c->scl_rate = 0;
rk30_i2c_set_clk(i2c, scl_rate);
return;
}
/* returns TRUE if we this is the last byte in the current message */
static inline int is_msglast(struct rk30_i2c *i2c)
{
return i2c->msg_ptr == i2c->msg->len-1;
}
/* returns TRUE if we reached the end of the current message */
static inline int is_msgend(struct rk30_i2c *i2c)
{
return i2c->msg_ptr >= i2c->msg->len;
}
static void rk30_i2c_stop(struct rk30_i2c *i2c, int ret)
{
i2c->msg_ptr = 0;
i2c->msg = NULL;
if(ret == -EAGAIN){
i2c->state = STATE_IDLE;
i2c->is_busy = 0;
wake_up(&i2c->wait);
return;
}
i2c->error = ret;
i2c_writel(I2C_STOPIEN, i2c->regs + I2C_IEN);
i2c->state = STATE_STOP;
rk30_i2c_send_stop(i2c);
return;
}
static inline void rk30_set_rx_mode(struct rk30_i2c *i2c, unsigned int lastnak)
{
unsigned long con = i2c_readl(i2c->regs + I2C_CON);
con &= (~I2C_CON_MASK);
con |= (I2C_CON_MOD_RX << 1);
if(lastnak)
con |= I2C_CON_LASTACK;
i2c_writel(con, i2c->regs + I2C_CON);
}
static void rk30_irq_read_prepare(struct rk30_i2c *i2c)
{
unsigned int cnt, len = i2c->msg->len - i2c->msg_ptr;
if(len <= 32 && i2c->msg_ptr != 0)
rk30_set_rx_mode(i2c, 1);
else if(i2c->msg_ptr != 0)
rk30_set_rx_mode(i2c, 0);
if(is_msgend(i2c)) {
rk30_i2c_stop(i2c, i2c->error);
return;
}
if(len > 32)
cnt = 32;
else
cnt = len;
i2c_writel(cnt, i2c->regs + I2C_MRXCNT);
}
static void rk30_irq_read_get_data(struct rk30_i2c *i2c)
{
unsigned int i, len = i2c->msg->len - i2c->msg_ptr;
unsigned int p = 0;
len = (len >= 32)?32:len;
for(i = 0; i < len; i++){
if(i%4 == 0)
p = i2c_readl(i2c->regs + I2C_RXDATA_BASE + (i/4) * 4);
i2c->msg->buf[i2c->msg_ptr++] = (p >>((i%4) * 8)) & 0xff;
}
return;
}
static void rk30_irq_write_prepare(struct rk30_i2c *i2c)
{
unsigned int data = 0, cnt = 0, i, j;
unsigned char byte;
if(is_msgend(i2c)) {
rk30_i2c_stop(i2c, i2c->error);
return;
}
for(i = 0; i < 8; i++){
data = 0;
for(j = 0; j < 4; j++) {
if(is_msgend(i2c))
break;
if((i2c->msg_ptr == 0) && (cnt == 0))
byte = (i2c->addr_1st & 0x7f) << 1;
else if((i2c->msg_ptr == 0) && (cnt == 1) && (i2c->msg->flags & I2C_M_TEN))
byte = i2c->addr_2nd;
else
byte = i2c->msg->buf[i2c->msg_ptr++];
cnt++;
data |= (byte << (j * 8));
}
i2c_writel(data, i2c->regs + I2C_TXDATA_BASE + 4 * i);
if(is_msgend(i2c))
break;
}
i2c_writel(cnt, i2c->regs + I2C_MTXCNT);
}
static void rk30_i2c_irq_nextblock(struct rk30_i2c *i2c, unsigned int ipd)
{
switch (i2c->state) {
case STATE_START:
if(!(ipd & I2C_STARTIPD)){
rk30_i2c_stop(i2c, -ENXIO);
dev_err(i2c->dev, "Addr[0x%04x] no start irq in STATE_START\n", i2c->addr);
rk30_show_regs(i2c);
i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD);
goto out;
}
i2c->complete_what |= 1<<i2c->state;
i2c_writel(I2C_STARTIPD, i2c->regs + I2C_IPD);
rk30_i2c_clean_start(i2c);
if(i2c->mode == I2C_CON_MOD_TX){
i2c_writel(I2C_MBTFIEN | I2C_NAKRCVIEN, i2c->regs + I2C_IEN);
i2c->state = STATE_WRITE;
goto prepare_write;
} else {
i2c_writel(I2C_MBRFIEN | I2C_NAKRCVIEN, i2c->regs + I2C_IEN);
i2c->state = STATE_READ;
goto prepare_read;
}
case STATE_WRITE:
if(!(ipd & I2C_MBTFIPD)){
rk30_i2c_stop(i2c, -ENXIO);
dev_err(i2c->dev, "Addr[0x%04x] no mbtf irq in STATE_WRITE\n", i2c->addr);
rk30_show_regs(i2c);
i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD);
goto out;
}
i2c->complete_what |= 1<<i2c->state;
i2c_writel(I2C_MBTFIPD, i2c->regs + I2C_IPD);
prepare_write:
rk30_irq_write_prepare(i2c);
break;
case STATE_READ:
if(!(ipd & I2C_MBRFIPD)){
rk30_i2c_stop(i2c, -ENXIO);
dev_err(i2c->dev, "Addr[0x%04x] no mbrf irq in STATE_READ, ipd = 0x%x\n", i2c->addr, ipd);
rk30_show_regs(i2c);
i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD);
goto out;
}
i2c->complete_what |= 1<<i2c->state;
i2c_writel(I2C_MBRFIPD, i2c->regs + I2C_IPD);
rk30_irq_read_get_data(i2c);
prepare_read:
rk30_irq_read_prepare(i2c);
break;
case STATE_STOP:
if(!(ipd & I2C_STOPIPD)){
rk30_i2c_stop(i2c, -ENXIO);
dev_err(i2c->dev, "Addr[0x%04x] no stop irq in STATE_STOP\n", i2c->addr);
rk30_show_regs(i2c);
i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD);
goto out;
}
rk30_i2c_clean_stop(i2c);
i2c_writel(I2C_STOPIPD, i2c->regs + I2C_IPD);
i2c->is_busy = 0;
i2c->complete_what |= 1<<i2c->state;
i2c->state = STATE_IDLE;
wake_up(&i2c->wait);
break;
default:
break;
}
out:
return;
}
static irqreturn_t rk30_i2c_irq(int irq, void *dev_id)
{
struct rk30_i2c *i2c = dev_id;
unsigned int ipd;
spin_lock(&i2c->lock);
ipd = i2c_readl(i2c->regs + I2C_IPD);
if(i2c->state == STATE_IDLE){
dev_info(i2c->dev, "Addr[0x%04x] irq in STATE_IDLE, ipd = 0x%x\n", i2c->addr, ipd);
i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD);
goto out;
}
if(ipd & I2C_NAKRCVIPD){
i2c_writel(I2C_NAKRCVIPD, i2c->regs + I2C_IPD);
i2c->error = -EAGAIN;
goto out;
}
rk30_i2c_irq_nextblock(i2c, ipd);
out:
spin_unlock(&i2c->lock);
return IRQ_HANDLED;
}
static int rk30_i2c_set_master(struct rk30_i2c *i2c, struct i2c_msg *msgs, int num)
{
unsigned int reg_valid_bits = 0;
unsigned int reg_addr = 0;
unsigned int addr = (i2c->addr_1st << 1) | 1;
if(num == 1) {
i2c->count = msgs[0].len;
if(!(msgs[0].flags & I2C_M_RD)){
i2c->msg = &msgs[0];
i2c->mode = I2C_CON_MOD_TX;
}
else {
i2c->msg = &msgs[0];
i2c_writel(addr | I2C_MRXADDR_LOW, i2c->regs + I2C_MRXADDR);
i2c_writel(0, i2c->regs + I2C_MRXRADDR);
i2c->mode = I2C_CON_MOD_TRX;
//i2c->mode = I2C_CON_MOD_RX;
}
}
else if(num == 2) {
i2c->count = msgs[1].len;
if(msgs[0].flags & I2C_M_TEN){
switch(msgs[0].len){
case 1:
reg_addr = i2c->addr_2nd | (msgs[0].buf[0] << 8);
reg_valid_bits |= I2C_MRXADDR_LOW | I2C_MRXADDR_MID;
break;
case 2:
reg_addr = i2c->addr_2nd | (msgs[0].buf[0] << 8) | (msgs[0].buf[1] << 16);
reg_valid_bits |= I2C_MRXADDR_LOW | I2C_MRXADDR_MID | I2C_MRXADDR_HIGH;
break;
default:
return -EIO;
}
}else{
switch(msgs[0].len){
case 1:
reg_addr = msgs[0].buf[0];
reg_valid_bits |= I2C_MRXADDR_LOW;
break;
case 2:
reg_addr = msgs[0].buf[0] | (msgs[0].buf[1] << 8);
reg_valid_bits |= I2C_MRXADDR_LOW | I2C_MRXADDR_MID;
break;
case 3:
reg_addr = msgs[0].buf[0] | (msgs[0].buf[1] << 8) | (msgs[0].buf[2] << 16);
reg_valid_bits |= I2C_MRXADDR_LOW | I2C_MRXADDR_MID | I2C_MRXADDR_HIGH;
break;
default:
return -EIO;
}
}
if((msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) {
i2c->msg = &msgs[1];
i2c_writel(addr | I2C_MRXADDR_LOW, i2c->regs + I2C_MRXADDR);
i2c_writel(reg_addr | reg_valid_bits, i2c->regs + I2C_MRXRADDR);
i2c->mode = I2C_CON_MOD_RRX;
}
else if(!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) {
i2c->msg = &msgs[1];
i2c_writel(addr | I2C_MRXADDR_LOW, i2c->regs + I2C_MRXADDR);
i2c_writel(reg_addr | reg_valid_bits, i2c->regs + I2C_MRXRADDR);
i2c->mode = I2C_CON_MOD_TRX;
}
else
return -EIO;
}
else {
dev_err(i2c->dev, "This case(num > 2) has not been support now\n");
return -EIO;
}
return 0;
}
/* rk30_i2c_doxfer
*
* this starts an i2c transfer
*/
static int rk30_i2c_doxfer(struct rk30_i2c *i2c,
struct i2c_msg *msgs, int num)
{
unsigned long timeout, flags;
int error = 0;
/* 32 -- max transfer bytes
* 2 -- addr bytes * 2
* 3 -- max reg addr bytes
* 9 -- cycles per bytes
* max cycles: (32 + 2 + 3) * 9 --> 400 cycles
*/
int msleep_time = 400 * 1000/ i2c->scl_rate; // ms
if (i2c->suspended){
dev_err(i2c->dev, "i2c is suspended\n");
return -EIO;
}
spin_lock_irqsave(&i2c->lock, flags);
i2c->addr = msgs[0].addr;
if(msgs[0].flags & I2C_M_TEN){
i2c->addr_1st = ((i2c->addr & 0x0300)>>8) | 0x78;
i2c->addr_2nd = i2c->addr & 0x00ff;
}else{
i2c->addr_1st = i2c->addr & 0x007f;
i2c->addr_2nd = 0;
}
i2c_dbg(i2c->dev, "addr: 0x%04x, addr_1st: 0x%02x, addr_2nd: 0x%02x\n",
i2c->addr, i2c->addr_1st, i2c->addr_2nd);
if(rk30_i2c_set_master(i2c, msgs, num) < 0){
spin_unlock_irqrestore(&i2c->lock, flags);
dev_err(i2c->dev, "addr[0x%04x] set master error\n", msgs[0].addr);
return -EIO;
}
i2c->msg_ptr = 0;
i2c->error = 0;
i2c->is_busy = 1;
i2c->state = STATE_START;
i2c->complete_what = 0;
i2c_writel(I2C_STARTIEN, i2c->regs + I2C_IEN);
spin_unlock_irqrestore(&i2c->lock, flags);
rk30_i2c_enable(i2c, (i2c->count > 32)?0:1); //if count > 32, byte(32) send ack
if (in_atomic()){
int tmo = I2C_WAIT_TIMEOUT * USEC_PER_MSEC;
while(tmo-- && i2c->is_busy != 0)
udelay(1);
timeout = (tmo <= 0)?0:1;
}else
timeout = wait_event_timeout(i2c->wait, (i2c->is_busy == 0), msecs_to_jiffies(I2C_WAIT_TIMEOUT));
spin_lock_irqsave(&i2c->lock, flags);
i2c->state = STATE_IDLE;
error = i2c->error;
spin_unlock_irqrestore(&i2c->lock, flags);
if (timeout == 0){
unsigned int ipd = i2c_readl(i2c->regs + I2C_IPD);
if(error < 0)
i2c_dbg(i2c->dev, "error = %d\n", error);
else if((i2c->complete_what !=COMPLETE_READ && i2c->complete_what != COMPLETE_WRITE)){
if(ipd & I2C_HOLD_SCL)
dev_err(i2c->dev, "SCL was hold by slave\n");
dev_err(i2c->dev, "Addr[0x%04x] wait event timeout, state: %d, is_busy: %d, error: %d, complete_what: 0x%x, ipd: 0x%x\n",
msgs[0].addr, i2c->state, i2c->is_busy, error, i2c->complete_what, ipd);
//rk30_show_regs(i2c);
error = -ETIMEDOUT;
if(in_atomic())
mdelay(msleep_time);
else
msleep(msleep_time);
rk30_i2c_send_stop(i2c);
if(in_atomic())
mdelay(1);
else
msleep(1);
}
else
i2c_dbg(i2c->dev, "Addr[0x%02x] wait event timeout, but transfer complete\n", i2c->addr);
}
i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD);
rk30_i2c_disable_irq(i2c);
rk30_i2c_disable(i2c);
if(error == -EAGAIN)
i2c_dbg(i2c->dev, "No ack(complete_what: 0x%x), Maybe slave(addr: 0x%04x) not exist or abnormal power-on\n",
i2c->complete_what, i2c->addr);
return error;
}
/* rk30_i2c_xfer
*
* first port of call from the i2c bus code when an message needs
* transferring across the i2c bus.
*/
static int rk30_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
int ret = 0, state, retry = 10;
unsigned long scl_rate;
struct rk30_i2c *i2c = (struct rk30_i2c *)adap->algo_data;
clk_enable(i2c->clk);
#ifdef I2C_CHECK_IDLE
while(retry-- && ((state = rk30_i2c_check_idle(i2c)) != I2C_IDLE)){
if(in_atomic())
mdelay(10);
else
msleep(10);
}
if(retry == 0){
dev_err(i2c->dev, "i2c is not in idle(state = %d)\n", state);
return -EIO;
}
#endif
if(msgs[0].scl_rate <= 400000 && msgs[0].scl_rate >= 10000)
scl_rate = msgs[0].scl_rate;
else if(msgs[0].scl_rate > 400000){
dev_warn(i2c->dev, "Warning: addr[0x%04x] msg[0].scl_rate( = %dKhz) is too high!",
msgs[0].addr, msgs[0].scl_rate/1000);
scl_rate = 400000;
}
else{
dev_warn(i2c->dev, "Warning: addr[0x%04x] msg[0].scl_rate( = %dKhz) is too low!",
msgs[0].addr, msgs[0].scl_rate/1000);
scl_rate = 10000;
}
if(i2c->is_div_from_arm[i2c->adap.nr]){
mutex_lock(&i2c->m_lock);
}
rk30_i2c_set_clk(i2c, scl_rate);
i2c_dbg(i2c->dev, "i2c transfer start: addr: 0x%04x, scl_reate: %ldKhz, len: %d\n", msgs[0].addr, scl_rate/1000, num);
ret = rk30_i2c_doxfer(i2c, msgs, num);
i2c_dbg(i2c->dev, "i2c transfer stop: addr: 0x%04x, state: %d, ret: %d\n", msgs[0].addr, ret, i2c->state);
if(i2c->is_div_from_arm[i2c->adap.nr]){
mutex_unlock(&i2c->m_lock);
}
clk_disable(i2c->clk);
return (ret < 0)?ret:num;
}
/* declare our i2c functionality */
static u32 rk30_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
}
/* i2c bus registration info */
static const struct i2c_algorithm rk30_i2c_algorithm = {
.master_xfer = rk30_i2c_xfer,
.functionality = rk30_i2c_func,
};
int i2c_add_rk30_adapter(struct i2c_adapter *adap)
{
int ret = 0;
struct rk30_i2c *i2c = (struct rk30_i2c *)adap->algo_data;
adap->algo = &rk30_i2c_algorithm;
i2c->i2c_init_hw = &rk30_i2c_init_hw;
i2c->i2c_set_clk = &rk30_i2c_set_clk;
i2c->i2c_irq = &rk30_i2c_irq;
ret = i2c_add_numbered_adapter(adap);
return ret;
}

View File

@ -1,407 +0,0 @@
/* drivers/i2c/busses/i2c-rk30.c
*
* Copyright (C) 2012 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include "i2c-rk30.h"
#define TX_SETUP 1
static int i2c_max_adap = 0;
void i2c_adap_sel(struct rk30_i2c *i2c, int nr, int adap_type)
{
i2c_writel((1 << I2C_ADAP_SEL_BIT(nr)) | (1 << I2C_ADAP_SEL_MASK(nr)) ,
i2c->con_base);
}
#ifdef CONFIG_CPU_FREQ
#define freq_to_i2c(_n) container_of(_n, struct rk30_i2c, freq_transition)
static int rk30_i2c_cpufreq_transition(struct notifier_block *nb,
unsigned long val, void *data)
{
struct rk30_i2c *i2c = freq_to_i2c(nb);
struct cpufreq_freqs *freqs = data;
if (freqs->cpu)
return 0;
if(val == CPUFREQ_PRECHANGE)
mutex_lock(&i2c->m_lock);
else if(val == CPUFREQ_POSTCHANGE)
mutex_unlock(&i2c->m_lock);
return 0;
}
static inline int rk30_i2c_register_cpufreq(struct rk30_i2c *i2c)
{
if(!i2c->is_div_from_arm[i2c->adap.nr])
return 0;
i2c->freq_transition.notifier_call = rk30_i2c_cpufreq_transition;
return cpufreq_register_notifier(&i2c->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
}
static inline void rk30_i2c_deregister_cpufreq(struct rk30_i2c *i2c)
{
if(!i2c->is_div_from_arm[i2c->adap.nr])
return;
cpufreq_unregister_notifier(&i2c->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
}
#else
static inline int rk30_i2c_register_cpufreq(struct rk30_i2c *i2c)
{
return 0;
}
static inline void rk30_i2c_deregister_cpufreq(struct rk30_i2c *i2c)
{
}
#endif
/* rk30_i2c_probe
*
* called by the bus driver when a suitable device is found
*/
static int rk30_i2c_probe(struct platform_device *pdev)
{
struct rk30_i2c *i2c = NULL;
struct rk30_i2c_platform_data *pdata = NULL;
struct resource *res;
int ret;
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no platform data\n");
return -EINVAL;
}
i2c = kzalloc(sizeof(struct rk30_i2c), GFP_KERNEL);
if (!i2c) {
dev_err(&pdev->dev, "no memory for state\n");
return -ENOMEM;
}
#if !defined(CONFIG_ARCH_RK319X)
i2c->con_base = (void __iomem *)GRF_I2C_CON_BASE;
i2c_adap_sel(i2c, pdata->bus_num, pdata->adap_type);
#endif
if(pdata->io_init)
pdata->io_init();
i2c->sda_mode = pdata->sda_mode;
i2c->scl_mode = pdata->scl_mode;
strlcpy(i2c->adap.name, "rk30_i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE;
i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
i2c->tx_setup = TX_SETUP;
i2c->adap.retries = 2;
i2c->adap.timeout = msecs_to_jiffies(100);
spin_lock_init(&i2c->lock);
init_waitqueue_head(&i2c->wait);
mutex_init(&i2c->m_lock);
/* find the clock and enable it */
i2c->dev = &pdev->dev;
i2c->clk = clk_get(&pdev->dev, "i2c");
if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
ret = -ENOENT;
goto err_noclk;
}
i2c_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
clk_enable(i2c->clk);
/* map the registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "cannot find IO resource\n");
ret = -ENOENT;
goto err_get_resource;
}
i2c->ioarea = request_mem_region(res->start, resource_size(res),
pdev->name);
if (i2c->ioarea == NULL) {
dev_err(&pdev->dev, "cannot request IO\n");
ret = -ENXIO;
goto err_ioarea;
}
i2c->regs = ioremap(res->start, resource_size(res));
if (i2c->regs == NULL) {
dev_err(&pdev->dev, "cannot map IO\n");
ret = -ENXIO;
goto err_ioremap;
}
i2c_dbg(&pdev->dev, "registers %p (%p, %p)\n",
i2c->regs, i2c->ioarea, res);
/* setup info block for the i2c core */
i2c->adap.algo_data = i2c;
i2c->adap.dev.parent = &pdev->dev;
i2c->adap.nr = pdata->bus_num;
if(pdata->adap_type == I2C_RK29_ADAP)
ret = i2c_add_rk29_adapter(&i2c->adap);
else // I2C_RK30_ADAP
ret = i2c_add_rk30_adapter(&i2c->adap);
if (ret < 0) {
dev_err(&pdev->dev, "failed to add adapter\n");
goto err_add_adapter;
}
/* find the IRQ for this unit (note, this relies on the init call to
* ensure no current IRQs pending
*/
i2c->irq = ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
dev_err(&pdev->dev, "cannot find IRQ\n");
goto err_get_irq;
}
ret = request_irq(i2c->irq, i2c->i2c_irq, IRQF_DISABLED,
dev_name(&pdev->dev), i2c);
if (ret != 0) {
dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
goto err_request_irq;
}
ret = rk30_i2c_register_cpufreq(i2c);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
goto err_register_cpufreq;
}
platform_set_drvdata(pdev, i2c);
i2c->is_div_from_arm[i2c->adap.nr] = pdata->is_div_from_arm;
i2c->i2c_init_hw(i2c, 100 * 1000);
i2c_max_adap++;
dev_info(&pdev->dev, "%s: RK30 I2C adapter\n", dev_name(&i2c->adap.dev));
return 0;
//err_none:
// rk30_i2c_deregister_cpufreq(i2c);
err_register_cpufreq:
free_irq(i2c->irq, i2c);
err_request_irq:
err_get_irq:
i2c_del_adapter(&i2c->adap);
err_add_adapter:
iounmap(i2c->regs);
err_ioremap:
kfree(i2c->ioarea);
err_ioarea:
release_resource(i2c->ioarea);
err_get_resource:
clk_put(i2c->clk);
err_noclk:
kfree(i2c);
return ret;
}
/* rk30_i2c_remove
*
* called when device is removed from the bus
*/
static int rk30_i2c_remove(struct platform_device *pdev)
{
struct rk30_i2c *i2c = platform_get_drvdata(pdev);
rk30_i2c_deregister_cpufreq(i2c);
free_irq(i2c->irq, i2c);
i2c_del_adapter(&i2c->adap);
iounmap(i2c->regs);
kfree(i2c->ioarea);
release_resource(i2c->ioarea);
clk_put(i2c->clk);
kfree(i2c);
return 0;
}
#ifdef CONFIG_PM
static int rk30_i2c_suspend_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rk30_i2c *i2c = platform_get_drvdata(pdev);
i2c->suspended = 1;
return 0;
}
static int rk30_i2c_resume_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rk30_i2c *i2c = platform_get_drvdata(pdev);
i2c->suspended = 0;
i2c->i2c_init_hw(i2c, i2c->scl_rate);
return 0;
}
static const struct dev_pm_ops rk30_i2c_dev_pm_ops = {
.suspend_noirq = rk30_i2c_suspend_noirq,
.resume_noirq = rk30_i2c_resume_noirq,
};
#define rk30_DEV_PM_OPS (&rk30_i2c_dev_pm_ops)
#else
#define rk30_DEV_PM_OPS NULL
#endif
MODULE_DEVICE_TABLE(platform, rk30_driver_ids);
static struct platform_driver rk30_i2c_driver = {
.probe = rk30_i2c_probe,
.remove = rk30_i2c_remove,
.driver = {
.owner = THIS_MODULE,
.name = "rk30_i2c",
.pm = rk30_DEV_PM_OPS,
},
};
static int __init i2c_adap_init(void)
{
return platform_driver_register(&rk30_i2c_driver);
}
subsys_initcall(i2c_adap_init);
static void __exit i2c_adap_exit(void)
{
platform_driver_unregister(&rk30_i2c_driver);
}
module_exit(i2c_adap_exit);
static int detect_read(struct i2c_client *client, char *buf, int len)
{
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = client->flags | I2C_M_RD;
msg.buf = buf;
msg.len = len;
msg.scl_rate = 100 * 1000;
return i2c_transfer(client->adapter, &msg, 1);
}
static void detect_set_client(struct i2c_client *client, __u16 addr, int nr)
{
client->flags = 0;
client->addr = addr;
client->adapter = i2c_get_adapter(nr);
}
static void slave_detect(int nr)
{
int ret = 0;
unsigned short addr;
char val[8];
char buf[6 * 0x80 + 20];
struct i2c_client client;
memset(buf, 0, 6 * 0x80 + 20);
sprintf(buf, "I2c%d slave list: ", nr);
do {
for(addr = 0x01; addr < 0x80; addr++){
detect_set_client(&client, addr, nr);
ret = detect_read(&client, val, 1);
if(ret > 0)
sprintf(buf, "%s 0x%02x", buf, addr);
}
printk("%s\n", buf);
}
while(0);
}
static ssize_t i2c_detect_write(struct file *file,
const char __user *buf, size_t count, loff_t *offset)
{
char nr_buf[8];
int nr = 0, ret;
if(count > 4)
return -EFAULT;
ret = copy_from_user(nr_buf, buf, count);
if(ret < 0)
return -EFAULT;
sscanf(nr_buf, "%d", &nr);
if(nr >= 5 || nr < 0)
return -EFAULT;
slave_detect(nr);
return count;
}
static const struct file_operations i2c_detect_fops = {
.write = i2c_detect_write,
};
static struct miscdevice i2c_detect_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "i2c_detect",
.fops = &i2c_detect_fops,
};
static int __init i2c_detect_init(void)
{
return misc_register(&i2c_detect_device);
}
static void __exit i2c_detect_exit(void)
{
misc_deregister(&i2c_detect_device);
}
module_init(i2c_detect_init);
module_exit(i2c_detect_exit);
static int __init i2c_detect_rk610(void)
{
int i;
for(i = 0; i < i2c_max_adap; i++){
i2c_check_rk610_ex(i);
}
return 0;
}
late_initcall(i2c_detect_rk610);
MODULE_DESCRIPTION("Driver for RK30 I2C Bus");
MODULE_AUTHOR("kfx, kfx@rock-chips.com");
MODULE_LICENSE("GPL");

View File

@ -1,120 +0,0 @@
#ifndef __RK30_I2C_H__
#define __RK30_I2C_H__
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/wakelock.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/clk.h>
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/miscdevice.h>
#include <mach/board.h>
#include <mach/iomux.h>
#include <mach/gpio.h>
#include <asm/irq.h>
#if 0
#define i2c_dbg(dev, format, arg...) \
dev_printk(KERN_INFO , dev , format , ## arg)
#else
#define i2c_dbg(dev, format, arg...)
#endif
#define I2C_CHECK_IDLE
#define i2c_writel writel_relaxed
#define i2c_readl readl_relaxed
#define I2C_WAIT_TIMEOUT 200 //200ms
#define rk30_set_bit(p, v, b) (((p) & ~(1 << (b))) | ((v) << (b)))
#define rk30_get_bit(p, b) (((p) & (1 << (b))) >> (b))
#define rk30_set_bits(p, v, b, m) (((p) & ~(m)) | ((v) << (b)))
#define rk30_get_bits(p, b, m) (((p) & (m)) >> (b))
#define rk30_ceil(x, y) \
({ unsigned long __x = (x), __y = (y); (__x + __y - 1) / __y; })
#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK3188)
#define GRF_I2C_CON_BASE (RK30_GRF_BASE + GRF_SOC_CON1)
#endif
#if defined(CONFIG_ARCH_RK2928) || defined(CONFIG_ARCH_RK3026)
#define GRF_I2C_CON_BASE (RK2928_GRF_BASE + GRF_SOC_CON1)
#endif
#define I2C_ADAP_SEL_BIT(nr) ((nr) + 11)
#define I2C_ADAP_SEL_MASK(nr) ((nr) + 27)
enum rk30_i2c_state {
STATE_IDLE,
STATE_START,
STATE_READ,
STATE_WRITE,
STATE_STOP
};
struct rk30_i2c {
spinlock_t lock;
wait_queue_head_t wait;
struct mutex m_lock;
unsigned int suspended:1;
struct i2c_msg *msg;
union {
unsigned int msg_num;
unsigned int is_busy;
};
union {
unsigned int msg_idx;
int error;
};
unsigned int msg_ptr;
unsigned int tx_setup;
unsigned int irq;
enum rk30_i2c_state state;
unsigned int complete_what;
unsigned long clkrate;
void __iomem *regs;
void __iomem *con_base;
struct clk *clk;
struct device *dev;
struct resource *ioarea;
struct i2c_adapter adap;
unsigned long scl_rate;
unsigned long i2c_rate;
unsigned int addr;
unsigned char addr_1st, addr_2nd;
unsigned int mode;
unsigned int count;
int sda_mode, scl_mode;
struct wake_lock idlelock[5];
int is_div_from_arm[5];
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
void (*i2c_init_hw)(struct rk30_i2c *, unsigned long scl_rate);
void (*i2c_set_clk)(struct rk30_i2c *, unsigned long);
int (*check_idle)(int);
irqreturn_t (*i2c_irq)(int, void *);
};
void i2c_adap_sel(struct rk30_i2c *i2c, int nr, int adap_type);
int i2c_add_rk29_adapter(struct i2c_adapter *);
int i2c_add_rk30_adapter(struct i2c_adapter *);
#endif

File diff suppressed because it is too large Load Diff