Merge remote branch 'origin/develop' into develop_kernel_hxy

This commit is contained in:
root
2010-07-13 17:21:36 +08:00
3 changed files with 81 additions and 48 deletions

View File

@@ -271,6 +271,7 @@ struct rk2818_i2c_platform_data default_i2c0_data = {
.flags = 0,
.slave_addr = 0xff,
.scl_rate = 400*1000,
.mode = I2C_MODE_IRQ, //I2C_MODE_POLL
.cfg_gpio = rk2818_i2c0_cfg_gpio,
};
struct rk2818_i2c_platform_data default_i2c1_data = {
@@ -282,6 +283,7 @@ struct rk2818_i2c_platform_data default_i2c1_data = {
.flags = 0,
.slave_addr = 0xff,
.scl_rate = 400*1000,
.mode = I2C_MODE_IRQ, //I2C_MODE_POLL
.cfg_gpio = rk2818_i2c1_cfg_gpio,
};

View File

@@ -37,6 +37,9 @@ struct rk2818_i2c_platform_data {
unsigned int flags;
unsigned int slave_addr;
unsigned long scl_rate;
#define I2C_MODE_IRQ 0
#define I2C_MODE_POLL 1
unsigned int mode:1;
void (*cfg_gpio)(struct platform_device *dev);
};

View File

@@ -63,6 +63,8 @@ struct rk2818_i2c_data {
unsigned long scl_rate;
struct clk *clk;
unsigned int mode;
unsigned int irq;
spinlock_t cmd_lock;
@@ -95,30 +97,29 @@ static inline void rk2818_i2c_enable_irqs(struct rk2818_i2c_data *i2c)
}
/* scl = pclk/(5 *(rem+1) * 2^(exp+1)) */
static unsigned long rk2818_i2c_calcdivisor(unsigned long pclk,
static void rk2818_i2c_calcdivisor(unsigned long pclk,
unsigned long scl_rate,
unsigned long *real_rate,
unsigned int *rem, unsigned int *exp)
{
unsigned int calc_rem = pclk / (5 * scl_rate);
unsigned int calc_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)
{
calc_exp--;
break;
}
calc_rem = calc_rem >> 1;
}
if(calc_rem >= I2CCDVR_REM_MAX)
return -1;
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 0;
return;
}
/* set i2c bus scl rate */
static unsigned long rk2818_i2c_clockrate(struct rk2818_i2c_data *i2c)
@@ -126,45 +127,37 @@ static unsigned long rk2818_i2c_clockrate(struct rk2818_i2c_data *i2c)
struct rk2818_i2c_platform_data *pdata = i2c->dev->platform_data;
unsigned int rem = 0, exp = 0;
unsigned long scl_rate, real_rate = 0, tmp, pclk;
int ret = 0;
struct clk *arm_pclk;
arm_pclk = clk_get_parent(i2c->clk);
if(IS_ERR(arm_pclk))
{
dev_err(i2c->dev, "cannot get pclk\n");
ret = -ENOENT;
return -ENOENT;
}
pclk = clk_get_rate(arm_pclk);
dev_dbg(i2c->dev, "pdata desired clkrate %lu\n", pdata->scl_rate);
scl_rate = (i2c->scl_rate) ? i2c->scl_rate : ((pdata->scl_rate)? pdata->scl_rate:100000);
scl_rate = pdata->scl_rate ? pdata->scl_rate : 100000;
ret = rk2818_i2c_calcdivisor(pclk, scl_rate, &real_rate, &rem, &exp);
if (ret < 0)
{
dev_err(i2c->dev,
"Unable to achieve desired clkrate %luHz.", scl_rate);
return -EINVAL;
}
rk2818_i2c_calcdivisor(pclk, scl_rate, &real_rate, &rem, &exp);
tmp = readl(i2c->regs + I2C_OPR);
tmp |= exp;
tmp |= rem<<I2CCDVR_EXP_BITS;
writel(tmp, i2c->regs + I2C_OPR);
dev_dbg(i2c->dev, " Scl real rate is %lu\n", real_rate);
return ret;
if(real_rate > 400000)
dev_info(i2c->dev, "WARN: PCLK %luKhz, I2C set rate %luKhz, and real rate is %luKhz > 400Khz\n",
pclk/1000, scl_rate/1000, real_rate/1000);
else
dev_dbg(i2c->dev, " OK: PCLK %luKhz, I2C set rate %luKhz, real rate is %luKhz\n",
pclk/1000, scl_rate/1000, real_rate/1000);
return 0;
}
static int rk2818_event_occurred(struct rk2818_i2c_data *i2c)
{
unsigned long isr, lsr;
unsigned long isr;
isr = readl(i2c->regs + I2C_ISR);
lsr = readl(i2c->regs + I2C_LSR);
if(isr & I2C_ISR_ARBITR_LOSE)
{
isr &= ~I2C_ISR_ARBITR_LOSE;
@@ -195,7 +188,6 @@ static int rk2818_event_occurred(struct rk2818_i2c_data *i2c)
break;
}
i2c->cmd_err = RK2818_ERROR_UNKNOWN;
dev_err(i2c->dev,"Unhandled interrupt!\n");
return 0;
}
@@ -203,20 +195,38 @@ static irqreturn_t rk2818_i2c_irq(int irq, void *data)
{
struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)data;
int res;
rk2818_i2c_disable_irqs(i2c);
spin_lock(&i2c->cmd_lock);
res = rk2818_event_occurred(i2c);
if(res || i2c->cmd_err != RK2818_ERROR_NONE)
complete(&i2c->cmd_complete);
spin_unlock(&i2c->cmd_lock);
return IRQ_HANDLED;
}
static int wait_for_completion_poll_timeout(struct rk2818_i2c_data *i2c)
{
unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT;
unsigned int time = 10;
int res;
while(!time_after(jiffies, timeout))
{
dev_dbg(i2c->dev, "%s: time = %d\n", __func__, time);
res = rk2818_event_occurred(i2c);
if(res || i2c->cmd_err != RK2818_ERROR_NONE)
return 1;
udelay(time);
time *= 2;
}
return 0;
}
static int rk2818_wait_event(struct rk2818_i2c_data *i2c,
enum rk2818_event mr_event)
{
int ret = 0;
if(unlikely(irqs_disabled()))
{
dev_err(i2c->dev, "irqs are disabled on this system!\n");
@@ -231,9 +241,16 @@ static int rk2818_wait_event(struct rk2818_i2c_data *i2c,
spin_unlock_irq(&i2c->cmd_lock);
rk2818_i2c_enable_irqs(i2c);
ret = wait_for_completion_interruptible_timeout(&i2c->cmd_complete,
if(i2c->mode == I2C_MODE_IRQ)
{
ret = wait_for_completion_interruptible_timeout(&i2c->cmd_complete,
RK2818_I2C_TIMEOUT);
}
else
{
ret = wait_for_completion_poll_timeout(i2c);
dev_dbg(i2c->dev, "%s: ret = %d\n", __func__, ret);
}
if(ret < 0)
{
dev_err(i2c->dev, "wait_for_completion_interruptible_timeout(): "
@@ -349,9 +366,6 @@ static int rk2818_xfer_msg(struct i2c_adapter *adap,
}
clk_enable(i2c->clk);
if(msg->scl_rate)
i2c->scl_rate = msg->scl_rate;
rk2818_i2c_clockrate(i2c);
ret = rk2818_send_address(i2c, msg);
if(ret != 0)
@@ -445,7 +459,16 @@ static int rk2818_i2c_xfer(struct i2c_adapter *adap,
if(i2c->suspended ==1)
return -EIO;
i2c->scl_rate = msgs[0].scl_rate;
if(msgs[0].scl_rate <= 400000 && msgs[0].scl_rate > 0)
{
i2c->scl_rate = msgs[0].scl_rate;
}
else
{
dev_info(i2c->dev, "Scl_rate(%uKhz) is failed to change[0 -- 400Khz], current rate(%luKhz)\n",
msgs[0].scl_rate/1000, i2c->scl_rate/1000);
}
ret = rk2818_i2c_init_hw(i2c);
if(ret < 0)
return ret;
@@ -578,6 +601,8 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "no memory for state\n");
return -ENOMEM;
}
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;
@@ -640,15 +665,16 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "cannot find IRQ\n");
goto err_iomap;
}
if(i2c->mode == I2C_MODE_IRQ)
{
ret = request_irq(i2c->irq, rk2818_i2c_irq, IRQF_DISABLED,
dev_name(&pdev->dev), i2c);
ret = request_irq(i2c->irq, rk2818_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_iomap;
if (ret != 0) {
dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
goto err_iomap;
}
}
ret = rk2818_i2c_register_cpufreq(i2c);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
@@ -664,14 +690,15 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, i2c);
dev_dbg(&pdev->dev, "%s: RK2818 I2C adapter\n", dev_name(&i2c->adap.dev));
dev_info(&pdev->dev, "%s: RK2818 I2C adapter\n", dev_name(&i2c->adap.dev));
return 0;
err_cpufreq:
rk2818_i2c_unregister_cpufreq(i2c);
err_irq:
free_irq(i2c->irq, i2c);
if(i2c->mode == I2C_MODE_IRQ)
free_irq(i2c->irq, i2c);
err_iomap:
iounmap(i2c->regs);
@@ -697,7 +724,8 @@ static int rk2818_i2c_remove(struct platform_device *pdev)
rk2818_i2c_unregister_cpufreq(i2c);
i2c_del_adapter(&i2c->adap);
free_irq(i2c->irq, i2c);
if(i2c->mode == I2C_MODE_IRQ)
free_irq(i2c->irq, i2c);
clk_disable(i2c->clk);
clk_put(i2c->clk);