firmware/br-ext-chip-ingenic/board/t40/kernel/patches/00000-tools_pm-sleep_i2c-gp...

277 lines
6.6 KiB
Diff

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
+ * <stop> 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 <ACK>(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 <ACK>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 <ACK>ed\n");
+ return 1;
+ }
+ shift -= 8;
+ }
+
+ while(len-- > 0) {
+ if(write_byte(i2c,*buffer++)) {
+ failures++;
+ }
+ }
+ send_stop(i2c);
+ return failures;
+}