| From 4230dfe425428acfa51782df22d102c04840366c Mon Sep 17 00:00:00 2001 |
| From: Wolfram Sang <wsa+renesas@sang-engineering.com> |
| Date: Fri, 2 May 2014 21:15:15 +0200 |
| Subject: i2c: sh_mobile: check timing parameters for valid range |
| |
| Due to misconfiguration, it can happen that the calculated timing |
| parameters are out of range. Bail out if that happens. We can also |
| simplify some logic later because of the verified value. Also, make the |
| printouts of the values more precise by adding the hex-prefixes. |
| |
| Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> |
| Signed-off-by: Wolfram Sang <wsa@the-dreams.de> |
| (cherry picked from commit 7663ebefca8079ef0fd2fff1047d3d10af654c78) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/i2c/busses/i2c-sh_mobile.c | 17 +++++++++++++---- |
| 1 file changed, 13 insertions(+), 4 deletions(-) |
| |
| diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c |
| index 9f02013eaeeb..b1d399e3e5fc 100644 |
| --- a/drivers/i2c/busses/i2c-sh_mobile.c |
| +++ b/drivers/i2c/busses/i2c-sh_mobile.c |
| @@ -232,6 +232,7 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) |
| { |
| unsigned long i2c_clk_khz; |
| u32 tHIGH, tLOW, tf; |
| + uint16_t max_val; |
| |
| /* Get clock rate after clock is enabled */ |
| clk_prepare_enable(pd->clk); |
| @@ -254,15 +255,23 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) |
| } |
| |
| pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf); |
| + pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf); |
| + |
| + max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff; |
| + if (pd->iccl > max_val || pd->icch > max_val) { |
| + dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n", |
| + pd->iccl, pd->icch); |
| + return -EINVAL; |
| + } |
| + |
| /* one more bit of ICCL in ICIC */ |
| - if ((pd->iccl > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) |
| + if (pd->iccl & 0x100) |
| pd->icic |= ICIC_ICCLB8; |
| else |
| pd->icic &= ~ICIC_ICCLB8; |
| |
| - pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf); |
| /* one more bit of ICCH in ICIC */ |
| - if ((pd->icch > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) |
| + if (pd->icch & 0x100) |
| pd->icic |= ICIC_ICCHB8; |
| else |
| pd->icic &= ~ICIC_ICCHB8; |
| @@ -717,7 +726,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) |
| } |
| |
| dev_info(&dev->dev, |
| - "I2C adapter %d with bus speed %lu Hz (L/H=%x/%x)\n", |
| + "I2C adapter %d with bus speed %lu Hz (L/H=0x%x/0x%x)\n", |
| adap->nr, pd->bus_speed, pd->iccl, pd->icch); |
| |
| return 0; |
| -- |
| 2.1.2 |
| |