diff -drupN a/tools/pm-sleep/i2c-gpio.c b/tools/pm-sleep/i2c-gpio.c --- a/tools/pm-sleep/i2c-gpio.c 1970-01-01 03:00:00.000000000 +0300 +++ b/tools/pm-sleep/i2c-gpio.c 2022-06-09 05:02:37.000000000 +0300 @@ -0,0 +1,272 @@ +/* + * from ingenic_soft_i2c.c in uboot. + */ +#include "common.h" +#include "i2c-gpio.h" +#include "gpio.h" + +#define I2C_ACK 0 /* PD_SDA level to ack a byte */ +#define I2C_NOACK 1 /* PD_SDA level to noack a byte */ + + +#define printf(x,...) + +/*----------------------------------------------------------------------- + * Local functions + */ +static void i2c_scl(struct i2c_gpio *i2c,int bit) +{ + gpio_direction_output(i2c->scl,bit); +} + +static void i2c_sda(struct i2c_gpio *i2c,int bit) +{ + if(bit) { + gpio_direction_input(i2c->sda); + } else { + gpio_direction_output(i2c->sda,bit); + } +} + +static int i2c_read_sda(struct i2c_gpio *i2c) +{ + return gpio_get_value(i2c->sda); +} +/*----------------------------------------------------------------------- + * START: High -> Low on SDA while SCL is High + */ +static void send_start(struct i2c_gpio *i2c) +{ + + udelay(5); + i2c_sda(i2c,1); + udelay(5); + i2c_scl(i2c,1); + udelay(5); + i2c_sda(i2c,0); + udelay(5); +} + +/*----------------------------------------------------------------------- + * STOP: Low -> High on SDA while SCL is High + */ +static void send_stop(struct i2c_gpio *i2c) +{ + i2c_scl(i2c,0); + udelay(5); + i2c_sda(i2c,0); + udelay(5); + i2c_scl(i2c,1); + udelay(5); + i2c_sda(i2c,1); + udelay(5); +} + +/*----------------------------------------------------------------------- + * ack should be I2C_ACK or I2C_NOACK + */ +static void send_ack(struct i2c_gpio *i2c,int ack) +{ + i2c_scl(i2c,0); + udelay(5); + i2c_sda(i2c,ack); + udelay(5); + i2c_scl(i2c,1); + udelay(5*2); + i2c_scl(i2c,0); + udelay(5); +} + +/*----------------------------------------------------------------------- + * Send a reset sequence consisting of 9 clocks with the data signal high + * to clock any confused device back into an idle state. Also send a + * at the end of the sequence for belts & suspenders. + */ +/* static inline void send_reset(struct i2c_gpio *i2c) */ +/* { */ +/* int j; */ + +/* i2c_scl(i2c,1); */ +/* i2c_sda(i2c,1); */ +/* for(j = 0; j < 9; j++) { */ +/* i2c_scl(i2c,0); */ +/* udelay(5*2); */ +/* i2c_scl(i2c,1); */ +/* udelay(5*2); */ +/* } */ +/* send_stop(i2c); */ +/* } */ +/*----------------------------------------------------------------------- + * Send 8 bits and look for an acknowledgement. + */ +static int write_byte(struct i2c_gpio *i2c,unsigned char data) +{ + int j; + int nack; + + for(j = 0; j < 8; j++) { + i2c_scl(i2c,0); + udelay(5); + i2c_sda(i2c,data & 0x80); + udelay(5); + i2c_scl(i2c,1); + udelay(5*2); + data <<= 1; + } + + /* + * Look for an (negative logic) and return it. + */ + i2c_scl(i2c,0); + udelay(5); + i2c_sda(i2c,1); + udelay(5); + i2c_scl(i2c,1); + udelay(5*2); + nack = i2c_read_sda(i2c); + i2c_scl(i2c,0); + udelay(5); + + return(nack); /* not a nack is an ack */ +} + +/*----------------------------------------------------------------------- + * if ack == I2C_ACK, ACK the byte so can continue reading, else + * send I2C_NOACK to end the read. + */ +static unsigned char read_byte(struct i2c_gpio *i2c,int ack) +{ + int data; + int j; + + /* + * Read 8 bits, MSB first. + */ + i2c_sda(i2c,1); + data = 0; + for(j = 0; j < 8; j++) { + i2c_scl(i2c,0); + udelay(5); + i2c_scl(i2c,1); + udelay(5); + data <<= 1; + data |= i2c_read_sda(i2c); + udelay(5); + } + send_ack(i2c,ack); + + return(data); +} + +/*=====================================================================*/ +/* Public Functions */ +/*=====================================================================*/ + +/*----------------------------------------------------------------------- + * Initialization + */ +/* void i2c_init(struct i2c_gpio *i2c) */ +/* { */ +/* gpio_request(i2c->scl, "soft_i2c"); */ +/* gpio_request(i2c->sda, "soft_i2c"); */ +/* gpio_direction_output(i2c->sda,1); */ +/* gpio_direction_output(i2c->scl,1); */ +/* send_reset(i2c); */ +/* } */ +void i2c_reinit(struct i2c_gpio *i2c) +{ + gpio_direction_output(i2c->sda,1); + gpio_direction_output(i2c->scl,1); +} +/*----------------------------------------------------------------------- + * Read bytes + */ +int i2c_read(struct i2c_gpio *i2c,unsigned char chip, + unsigned int addr, int alen, unsigned char *buffer, int len) +{ + int shift; +#ifdef DEBUG + printf("i2c_read: chip %x addr %x alen %d buffer %p len %d\n", + chip, addr, alen, buffer, len); +#endif + /* + * Do the addressing portion of a write cycle to set the + * chip's address pointer. If the address length is zero, + * don't do the normal write cycle to set the address pointer, + * there is no address pointer in this chip. + */ + send_start(i2c); + if(alen > 0) { + if(write_byte(i2c,chip << 1)) { /* write cycle */ + send_stop(i2c); + printf("i2c_read, no chip responded %02X\n", chip); + return 1; + } + shift = (alen-1) * 8; + while(alen-- > 0) { + if(write_byte(i2c,addr >> shift)) { + printf("i2c_read, address not ed\n"); + return 1; + } + shift -= 8; + } + + /* Some I2C_GPIO chips need a stop/start sequence here, + * other chips don't work with a full stop and need + * only a start. Default behaviour is to send the + * stop/start sequence. + */ +#ifdef CONFIG_SOFT_I2C_READ_REPEATED_START + send_start(i2c); +#else + send_stop(i2c); + send_start(i2c); +#endif + } + /* + * Send the chip address again, this time for a read cycle. + * Then read the data. On the last byte, we do a NACK instead + * of an ACK(len == 0) to terminate the read. + */ + write_byte(i2c,(chip << 1) | 1); /* read cycle */ + while(len-- > 0) { + *buffer++ = read_byte(i2c,len == 0); + } + send_stop(i2c); + return 0; +} + +/*----------------------------------------------------------------------- + * Write bytes + */ +int i2c_write(struct i2c_gpio *i2c,unsigned char chip, unsigned int addr, int alen, unsigned char *buffer, int len) +{ + int shift, failures = 0; + +#ifdef DEBUG + printf("i2c_write: chip %x addr %x alen %d buffer %p len %d\n", + chip, addr, alen, buffer, len); +#endif + send_start(i2c); + if(write_byte(i2c,chip << 1)) { /* write cycle */ + send_stop(i2c); + printf("i2c_write, no chip responded %02X\n", chip); + return 1; + } + shift = (alen-1) * 8; + while(alen-- > 0) { + if(write_byte(i2c,addr >> shift)) { + printf("i2c_write, address not ed\n"); + return 1; + } + shift -= 8; + } + + while(len-- > 0) { + if(write_byte(i2c,*buffer++)) { + failures++; + } + } + send_stop(i2c); + return failures; +}