mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 04:48:04 +09:00
Merge remote branch 'origin/develop' into develop_kernel_hxy
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user