diff options
-rw-r--r-- | drivers/misc/atsha204a-i2c.c | 49 |
1 files changed, 44 insertions, 5 deletions
diff --git a/drivers/misc/atsha204a-i2c.c b/drivers/misc/atsha204a-i2c.c index 29daefb2a52..707daa90bdb 100644 --- a/drivers/misc/atsha204a-i2c.c +++ b/drivers/misc/atsha204a-i2c.c @@ -21,7 +21,6 @@ #include <linux/bitrev.h> #include <u-boot/crc.h> -#define ATSHA204A_TWLO_US 60 #define ATSHA204A_TWHI_US 2500 #define ATSHA204A_TRANSACTION_TIMEOUT 100000 #define ATSHA204A_TRANSACTION_RETRY 5 @@ -34,6 +33,48 @@ static inline u16 atsha204a_crc16(const u8 *buffer, size_t len) return bitrev16(crc16(0, buffer, len)); } +static int atsha204a_ping_bus(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + struct i2c_msg msg; + int speed; + int res; + u8 val = 0; + + speed = dm_i2c_get_bus_speed(bus); + if (speed != I2C_SPEED_STANDARD_RATE) { + int rv; + + rv = dm_i2c_set_bus_speed(bus, I2C_SPEED_STANDARD_RATE); + if (rv) + debug("Couldn't change the I2C bus speed\n"); + } + + /* + * The I2C drivers don't support sending messages when NAK is received. + * This chip requires wake up low signal on SDA for >= 60us. + * To achieve this, we slow the bus to 100kHz and send an empty + * message to address 0. This will hold the SDA line low for the + * required time to wake up the chip. + */ + msg.addr = 0; + msg.flags = I2C_M_STOP; + msg.len = sizeof(val); + msg.buf = &val; + + res = dm_i2c_xfer(dev, &msg, 1); + + if (speed != I2C_SPEED_STANDARD_RATE) { + int rv; + + rv = dm_i2c_set_bus_speed(bus, speed); + if (rv) + debug("Couldn't restore the I2C bus speed\n"); + } + + return res; +} + static int atsha204a_send(struct udevice *dev, const u8 *buf, u8 len) { fdt_addr_t *priv = dev_get_priv(dev); @@ -94,7 +135,6 @@ static int atsha204a_recv_resp(struct udevice *dev, int atsha204a_wakeup(struct udevice *dev) { - u8 req[4]; struct atsha204a_resp resp; int res; @@ -105,10 +145,9 @@ int atsha204a_wakeup(struct udevice *dev) * when the device is idle, asleep or during waking up. * Don't check for error when waking up the device. */ - memset(req, 0, 4); - atsha204a_send(dev, req, 4); + atsha204a_ping_bus(dev); - udelay(ATSHA204A_TWLO_US + ATSHA204A_TWHI_US); + udelay(ATSHA204A_TWHI_US); res = atsha204a_recv_resp(dev, &resp); if (res) { |