Browse Source

I2C driver cleanup (#21273)

* remove i2c_start and i2c_stop from i2c drivers

* remove static i2c_address variable from chibios i2c driver
David Hoelscher 2 years ago
parent
commit
e9bd7d7ad3
49 changed files with 288 additions and 611 deletions
  1. 17 19
      docs/i2c_driver.md
  2. 1 2
      docs/ja/i2c_driver.md
  3. 0 2
      drivers/gpio/pca9505.c
  4. 0 2
      drivers/gpio/pca9555.c
  5. 1 6
      drivers/oled/oled_driver.c
  6. 2 6
      drivers/painter/comms/qp_comms_i2c.c
  7. 0 2
      drivers/sensors/cirque_pinnacle_i2c.c
  8. 2 2
      keyboards/3w6/rev2/keymaps/default_pimoroni/pimoroni_trackball.c
  9. 1 3
      keyboards/3w6/rev2/keymaps/default_pimoroni/pimoroni_trackball.h
  10. 15 32
      keyboards/bajjak/bajjak.c
  11. 1 3
      keyboards/bajjak/bajjak.h
  12. 5 11
      keyboards/bajjak/matrix.c
  13. 6 30
      keyboards/dc01/left/matrix.c
  14. 15 36
      keyboards/ergodox_ez/ergodox_ez.c
  15. 1 3
      keyboards/ergodox_ez/ergodox_ez.h
  16. 19 8
      keyboards/ergodox_ez/led_i2c.c
  17. 5 12
      keyboards/ergodox_ez/matrix.c
  18. 8 16
      keyboards/ferris/0_2/matrix.c
  19. 11 17
      keyboards/gboards/ergotaco/ergotaco.c
  20. 1 4
      keyboards/gboards/ergotaco/ergotaco.h
  21. 4 14
      keyboards/gboards/ergotaco/matrix.c
  22. 10 16
      keyboards/gboards/georgi/georgi.c
  23. 1 4
      keyboards/gboards/georgi/georgi.h
  24. 4 13
      keyboards/gboards/georgi/matrix.c
  25. 9 15
      keyboards/gboards/gergo/gergo.c
  26. 1 4
      keyboards/gboards/gergo/gergo.h
  27. 5 15
      keyboards/gboards/gergo/matrix.c
  28. 10 24
      keyboards/gboards/gergoplex/gergoplex.c
  29. 1 3
      keyboards/gboards/gergoplex/gergoplex.h
  30. 8 20
      keyboards/gboards/gergoplex/matrix.c
  31. 0 1
      keyboards/handwired/d48/ds1307.c
  32. 10 17
      keyboards/handwired/frenchdev/frenchdev.c
  33. 1 3
      keyboards/handwired/frenchdev/frenchdev.h
  34. 9 19
      keyboards/handwired/frenchdev/matrix.c
  35. 2 13
      keyboards/handwired/onekey/keymaps/i2c_scanner/keymap.c
  36. 20 63
      keyboards/handwired/pterodactyl/matrix.c
  37. 11 23
      keyboards/hotdox/left.c
  38. 1 6
      keyboards/hotdox/left.h
  39. 6 8
      keyboards/ingrained/matrix.c
  40. 1 2
      keyboards/kagizaraya/chidori/board.c
  41. 1 3
      keyboards/nek_type_a/nek_type_a.h
  42. 13 64
      keyboards/system76/launch_1/usb_mux.c
  43. 2 2
      keyboards/ymdk/sp64/matrix.c
  44. 3 3
      keyboards/ymdk/sp64/sp64.c
  45. 1 3
      keyboards/ymdk/sp64/sp64.h
  46. 25 6
      platforms/avr/drivers/i2c_master.c
  47. 2 5
      platforms/avr/drivers/i2c_master.h
  48. 15 24
      platforms/chibios/drivers/i2c_master.c
  49. 1 2
      platforms/chibios/drivers/i2c_master.h

+ 17 - 19
docs/i2c_driver.md

@@ -138,23 +138,6 @@ void i2c_init(void) {
 
 ---
 
-### `i2c_status_t i2c_start(uint8_t address, uint16_t timeout)` :id=api-i2c-start
-
-Start an I2C transaction.
-
-#### Arguments :id=api-i2c-start-arguments
-
- - `uint8_t address`  
-   The 7-bit I2C address of the device (ie. without the read/write bit - this will be set automatically).
- - `uint16_t timeout`  
-   The time in milliseconds to wait for a response from the target device.
-
-#### Return Value :id=api-i2c-start-return
-
-`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
-
----
-
 ### `i2c_status_t i2c_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout)` :id=api-i2c-transmit
 
 Send multiple bytes to the selected I2C device.
@@ -285,6 +268,21 @@ Reads from a register with a 16-bit address (big endian) on the I2C device.
 
 ---
 
-### `i2c_status_t i2c_stop(void)` :id=api-i2c-stop
+### `i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout)` :id=api-i2c-ping-address
 
-Stop the current I2C transaction.
+Pings the I2C bus for a specific address. 
+
+On ChibiOS a "best effort" attempt is made by reading a single byte from register 0 at the requested address. This should generally work except for I2C devices that do not not respond to a register 0 read request, which will result in a false negative result (unsucessful response to ping attempt).
+
+This function is weakly defined, meaning it can be overridden if necessary for your particular use case:
+
+#### Arguments
+
+ - `uint8_t address`  
+   The 7-bit I2C address of the device (ie. without the read/write bit - this will be set automatically).
+ - `uint16_t timeout`  
+   The time in milliseconds to wait for a response from the target device.
+
+#### Return Value
+
+`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.

+ 1 - 2
docs/ja/i2c_driver.md

@@ -23,12 +23,11 @@ I2C アドレスと他の技術詳細について、さらなる情報を得る
 | 関数                                                                                                        | 説明                                                                                                                                                                                |
 |-------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
 | `void i2c_init(void);`                                                                                      | I2C ドライバを初期化します。他のあらゆるトランザクションを開始する前に、この関数を一度だけ呼ぶ必要があります。                                                                      |
-| `i2c_status_t i2c_start(uint8_t address, uint16_t timeout);`                                                     | I2C トランザクションを開始します。アドレスは方向ビットのない7ビットスレーブアドレスです。                                                                                           |
 | `i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);`                  | I2C 経由でデータを送信します。アドレスは方向ビットのない7ビットスレーブアドレスです。トランザクションのステータスを返します。                                                       |
 | `i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);`                   | I2C 経由でデータを受信します。アドレスは方向ビットのない7ビットスレーブアドレスです。 `length` で指定した長さのバイト列を `data` に保存し、トランザクションのステータスを返します。 |
 | `i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);` | `i2c_transmit` と同様ですが、 `regaddr` でスレーブのデータ書き込み先のレジスタを指定します。                                                                                    |
 | `i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);`  | `i2c_receive` と同様ですが、 `regaddr` でスレーブのデータ読み込み先のレジスタを指定します。                                                                                     |
-| `i2c_status_t i2c_stop(void);`                                                                                   | I2C トランザクションを終了します。                                                                                                                                                  |
+| `i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout);`                                              | I2C アドレスをテストします。アドレスは方向ビットのない7ビットスレーブアドレスです。                                                                                           |
 
 ### 関数の戻り値 :id=function-return
 

+ 0 - 2
drivers/gpio/pca9505.c

@@ -41,8 +41,6 @@ void pca9505_init(uint8_t slave_addr) {
     }
 
     // TODO: could check device connected
-    // i2c_start(SLAVE_TO_ADDR(slave) | I2C_WRITE);
-    // i2c_stop();
 }
 
 bool pca9505_set_config(uint8_t slave_addr, pca9505_port_t port, uint8_t conf) {

+ 0 - 2
drivers/gpio/pca9555.c

@@ -29,8 +29,6 @@ void pca9555_init(uint8_t slave_addr) {
     }
 
     // TODO: could check device connected
-    // i2c_start(SLAVE_TO_ADDR(slave) | I2C_WRITE);
-    // i2c_stop();
 }
 
 bool pca9555_set_config(uint8_t slave_addr, pca9555_port_t port, uint8_t conf) {

+ 1 - 6
drivers/oled/oled_driver.c

@@ -223,13 +223,8 @@ __attribute__((weak)) bool oled_send_cmd_P(const uint8_t *data, uint16_t size) {
     spi_stop();
     return (status >= 0);
 #    elif defined(OLED_TRANSPORT_I2C)
-    i2c_status_t status = i2c_start((OLED_DISPLAY_ADDRESS << 1) | I2C_WRITE, OLED_I2C_TIMEOUT);
 
-    for (uint16_t i = 0; i < size && status >= 0; i++) {
-        status = i2c_write(pgm_read_byte((const char *)data++), OLED_I2C_TIMEOUT);
-    }
-
-    i2c_stop();
+    i2c_status_t status = i2c_transmit_P((OLED_DISPLAY_ADDRESS << 1), data, size, OLED_I2C_TIMEOUT);
 
     return (status == I2C_STATUS_SUCCESS);
 #    endif

+ 2 - 6
drivers/painter/comms/qp_comms_i2c.c

@@ -28,18 +28,14 @@ bool qp_comms_i2c_init(painter_device_t device) {
 }
 
 bool qp_comms_i2c_start(painter_device_t device) {
-    painter_driver_t *     driver       = (painter_driver_t *)device;
-    qp_comms_i2c_config_t *comms_config = (qp_comms_i2c_config_t *)driver->comms_config;
-    return i2c_start(comms_config->chip_address << 1) == I2C_STATUS_SUCCESS;
+    return true;
 }
 
 uint32_t qp_comms_i2c_send_data(painter_device_t device, const void *data, uint32_t byte_count) {
     return qp_comms_i2c_send_raw(device, data, byte_count);
 }
 
-void qp_comms_i2c_stop(painter_device_t device) {
-    i2c_stop();
-}
+void qp_comms_i2c_stop(painter_device_t device) {}
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // Command+Data I2C support

+ 0 - 2
drivers/sensors/cirque_pinnacle_i2c.c

@@ -19,7 +19,6 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {
             pd_dprintf("error cirque_pinnacle i2c_read_register\n");
             touchpad_init = false;
         }
-        i2c_stop();
     }
 }
 
@@ -32,6 +31,5 @@ void RAP_Write(uint8_t address, uint8_t data) {
             pd_dprintf("error cirque_pinnacle i2c_write_register\n");
             touchpad_init = false;
         }
-        i2c_stop();
     }
 }

+ 2 - 2
keyboards/3w6/rev2/keymaps/default_pimoroni/pimoroni_trackball.c

@@ -38,7 +38,7 @@ static uint16_t i2c_timeout_timer;
 
 void trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
     uint8_t data[] = {0x00, red, green, blue, white};
-    i2c_transmit(TRACKBALL_WRITE, data, sizeof(data), I2C_TIMEOUT);
+    i2c_transmit(TRACKBALL_ADDRESS, data, sizeof(data), I2C_TIMEOUT);
 }
 
 int16_t mouse_offset(uint8_t positive, uint8_t negative, int16_t scale) {
@@ -120,7 +120,7 @@ bool pointing_device_task(void) {
     static uint16_t debounce_timer;
     uint8_t         state[5] = {};
     if (timer_elapsed(i2c_timeout_timer) > I2C_WAITCHECK) {
-        if (i2c_read_register(TRACKBALL_WRITE, 0x04, state, 5, I2C_TIMEOUT) == I2C_STATUS_SUCCESS) {
+        if (i2c_read_register(TRACKBALL_ADDRESS, 0x04, state, 5, I2C_TIMEOUT) == I2C_STATUS_SUCCESS) {
             if (!state[4] && !debounce) {
                 if (scrolling) {
 #ifdef PIMORONI_TRACKBALL_INVERT_X

+ 1 - 3
keyboards/3w6/rev2/keymaps/default_pimoroni/pimoroni_trackball.h

@@ -20,10 +20,8 @@
 #include "pointing_device.h"
 
 #ifndef TRACKBALL_ADDRESS
-#    define TRACKBALL_ADDRESS 0x0A
+#    define TRACKBALL_ADDRESS (0x0A << 1)
 #endif
-#define TRACKBALL_WRITE ((TRACKBALL_ADDRESS << 1) | I2C_WRITE)
-#define TRACKBALL_READ  ((TRACKBALL_ADDRESS << 1) | I2C_READ)
 
 void trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white);
 void trackball_check_click(bool pressed, report_mouse_t *mouse);

+ 15 - 32
keyboards/bajjak/bajjak.c

@@ -137,23 +137,16 @@ uint8_t init_mcp23018(void) {
     // - unused  : input  : 1
     // - input   : input  : 1
     // - driving : output : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, BAJJAK_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(IODIRA, BAJJAK_EZ_I2C_TIMEOUT);            if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00000000, BAJJAK_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00111111, BAJJAK_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    i2c_stop();
-
-    // set pull-up
-    // - unused  : on  : 1
-    // - input   : on  : 1
-    // - driving : off : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, BAJJAK_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(GPPUA, BAJJAK_EZ_I2C_TIMEOUT);             if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00000000, BAJJAK_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b01111111, BAJJAK_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-
-out:
-    i2c_stop();
+    uint8_t data[] = {0b00000000, 0b00111111};
+    mcp23018_status = i2c_writeReg(I2C_ADDR, IODIRA, data, 2, BAJJAK_EZ_I2C_TIMEOUT);
+
+    if (!mcp23018_status) {
+        // set pull-up
+        // - unused  : on  : 1
+        // - input   : on  : 1
+        // - driving : off : 0
+        mcp23018_status = i2c_writeReg(I2C_ADDR, IODIRA, data, 2, BAJJAK_EZ_I2C_TIMEOUT);
+    }
 
 #ifdef LEFT_LEDS
     if (!mcp23018_status) mcp23018_status = bajjak_left_leds_update();
@@ -176,21 +169,11 @@ uint8_t bajjak_left_leds_update(void) {
     // - unused  : hi-Z : 1
     // - input   : hi-Z : 1
     // - driving : hi-Z : 1
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, BAJJAK_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(OLATA, BAJJAK_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111
-                                & ~(bajjak_left_led_1<<LEFT_LED_1_SHIFT),
-                                BAJJAK_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111
-                                & ~(bajjak_left_led_2<<LEFT_LED_2_SHIFT),
-                                BAJJAK_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-
- out:
-    i2c_stop();
+    uint8_t data[2];
+    data[0] = 0b11111111 & ~(bajjak_left_led_1<<LEFT_LED_1_SHIFT);
+    data[1] = 0b11111111 & ~(bajjak_left_led_2<<LEFT_LED_2_SHIFT);
+    mcp23018_status = i2c_writeReg(I2C_ADDR, OLATA, data, 2, BAJJAK_EZ_I2C_TIMEOUT);
+
     return mcp23018_status;
 }
 #endif

+ 1 - 3
keyboards/bajjak/bajjak.h

@@ -27,9 +27,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "i2c_master.h"
 
 // I2C aliases and register addresses (see "mcp23018.md")
-#define I2C_ADDR        0b0100000
-#define I2C_ADDR_WRITE  ( (I2C_ADDR<<1) | I2C_WRITE )
-#define I2C_ADDR_READ   ( (I2C_ADDR<<1) | I2C_READ  )
+#define I2C_ADDR        (0b0100000<<1)
 #define IODIRA          0x00            // i/o direction register
 #define IODIRB          0x01
 #define GPPUA           0x0C            // GPIO pull-up resistor register

+ 5 - 11
keyboards/bajjak/matrix.c

@@ -145,12 +145,7 @@ static matrix_row_t read_cols(uint8_t row) {
             uint8_t data = 0;
             // reading GPIOB (column port) since in mcp23018's sequential mode
             // it is addressed directly after writing to GPIOA in select_row()
-            mcp23018_status = i2c_start(I2C_ADDR_READ, BAJJAK_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-            mcp23018_status = i2c_read_nack(BAJJAK_EZ_I2C_TIMEOUT);               if (mcp23018_status < 0) goto out;
-            data            = ~((uint8_t)mcp23018_status);
-            mcp23018_status = I2C_STATUS_SUCCESS;
-        out:
-            i2c_stop();
+            mcp23018_status = i2c_receive(I2C_ADDR, &data, 1, BAJJAK_EZ_I2C_TIMEOUT);
             return data;
         }
     } else {
@@ -195,11 +190,10 @@ static void select_row(uint8_t row) {
         if (!mcp23018_status) {
             // set active row low  : 0
             // set other rows hi-Z : 1
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, BAJJAK_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOA, BAJJAK_EZ_I2C_TIMEOUT);                 if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(0xFF & ~(1 << row), BAJJAK_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-        out:
-            i2c_stop();
+            uint8_t data;
+            data = 0xFF & ~(1 << row);
+            mcp23018_status = i2c_writeReg(I2C_ADDR, GPIOA, &data, 1, BAJJAK_EZ_I2C_TIMEOUT);
+
         }
     } else {
         // select on teensy

+ 6 - 30
keyboards/dc01/left/matrix.c

@@ -387,37 +387,13 @@ static void unselect_cols(void)
 
 // Complete rows from other modules over i2c
 i2c_status_t i2c_transaction(uint8_t address, uint32_t mask, uint8_t col_offset) {
-    i2c_status_t status = i2c_start(address, 5);
-    if (status < 0) {
-        goto error;
-    }
-
-    status = i2c_write(0x01, 50);
-    if (status < 0) {
-        goto error;
-    }
-
-    status = i2c_start(address | I2C_READ, 50);
+    uint8_t data[MATRIX_ROWS + 1];
+    i2c_status_t status = i2c_readReg(address, 0x01, data, (MATRIX_ROWS + 1), 5);
 
-    status = i2c_read_ack(50);
-    if (status != 0x55) { //synchronization byte
-        goto error;
+    for (uint8_t i = 0; i < (MATRIX_ROWS) && status >= 0; i++) { //assemble slave matrix in main matrix
+        matrix[i] &= mask;  //mask bits to keep
+        matrix[i] |= ((uint32_t)data[i+1] << (MATRIX_COLS_SCANNED + col_offset)); //add new bits at the end
     }
 
-    for (uint8_t i = 0; i < MATRIX_ROWS-1 && status >= 0; i++) { //assemble slave matrix in main matrix
-        matrix[i] &= mask; //mask bits to keep
-        status = i2c_read_ack(50);
-            matrix[i] |= ((uint32_t)status << (MATRIX_COLS_SCANNED + col_offset)); //add new bits at the end
-        }
-    //last read request must be followed by a NACK
-    if (status >= 0) {
-        matrix[MATRIX_ROWS - 1] &= mask; //mask bits to keep
-        status = i2c_read_nack(50);
-        matrix[MATRIX_ROWS - 1] |= ((uint32_t)status << (MATRIX_COLS_SCANNED + col_offset)); //add new bits at the end
-    }
-
-error:
-    i2c_stop();
-
-    return (status < 0) ? status : I2C_STATUS_SUCCESS;
+    return status;
 }

+ 15 - 36
keyboards/ergodox_ez/ergodox_ez.c

@@ -155,31 +155,16 @@ uint8_t init_mcp23018(void) {
     // - unused  : input  : 1
     // - input   : input  : 1
     // - driving : output : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(IODIRA, ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00000000, ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00111111, ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    i2c_stop();
-
-    // set pull-up
-    // - unused  : on  : 1
-    // - input   : on  : 1
-    // - driving : off : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(GPPUA, ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00000000, ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00111111, ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-
-out:
-    i2c_stop();
+    uint8_t data[] = {0b00000000, 0b00111111};
+    mcp23018_status = i2c_writeReg(I2C_ADDR, IODIRA, data, 2, ERGODOX_EZ_I2C_TIMEOUT);
+
+    if (!mcp23018_status) {
+        // set pull-up
+        // - unused  : on  : 1
+        // - input   : on  : 1
+        // - driving : off : 0
+        mcp23018_status = i2c_writeReg(I2C_ADDR, GPPUA, data, 2, ERGODOX_EZ_I2C_TIMEOUT);
+    }
 
 #ifdef LEFT_LEDS
     if (!mcp23018_status) mcp23018_status = ergodox_left_leds_update();
@@ -203,17 +188,11 @@ uint8_t ergodox_left_leds_update(void) {
     // - unused  : hi-Z : 1
     // - input   : hi-Z : 1
     // - driving : hi-Z : 1
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(OLATA, ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111 & ~(ergodox_left_led_3 << LEFT_LED_3_SHIFT), ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111 & ~(ergodox_left_led_2 << LEFT_LED_2_SHIFT) & ~(ergodox_left_led_1 << LEFT_LED_1_SHIFT), ERGODOX_EZ_I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-
-out:
-    i2c_stop();
+    uint8_t data[2];
+    data[0] = 0b11111111 & ~(ergodox_left_led_3 << LEFT_LED_3_SHIFT);
+    data[1] = 0b11111111 & ~(ergodox_left_led_2 << LEFT_LED_2_SHIFT) & ~(ergodox_left_led_1 << LEFT_LED_1_SHIFT);
+    mcp23018_status = i2c_writeReg(I2C_ADDR, OLATA, data, 2, ERGODOX_EZ_I2C_TIMEOUT);
+
     return mcp23018_status;
 }
 #endif

+ 1 - 3
keyboards/ergodox_ez/ergodox_ez.h

@@ -26,9 +26,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "i2c_master.h"
 
 // I2C aliases and register addresses (see "mcp23018.md")
-#define I2C_ADDR        0b0100000
-#define I2C_ADDR_WRITE  ( (I2C_ADDR<<1) | I2C_WRITE )
-#define I2C_ADDR_READ   ( (I2C_ADDR<<1) | I2C_READ  )
+#define I2C_ADDR        (0b0100000<<1)
 #define IODIRA          0x00            // i/o direction register
 #define IODIRB          0x01
 #define GPPUA           0x0C            // GPIO pull-up resistor register

+ 19 - 8
keyboards/ergodox_ez/led_i2c.c

@@ -24,30 +24,41 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #    include "ws2812.h"
 
 void setleds_custom(rgb_led_t *led, uint16_t led_num) {
-    i2c_init();
-    i2c_start(0x84, ERGODOX_EZ_I2C_TIMEOUT);
+    uint16_t length = 0;
     int i = 0;
+    int j = 0;
+#    ifdef RGBW
+    int bytes_per_led = 4;
+#    else
+    int bytes_per_led = 3;
+#    endif
 #    if defined(ERGODOX_LED_30)
     // prevent right-half code from trying to bitbang all 30
     // so with 30 LEDs, we count from 29 to 15 here, and the
     // other half does 0 to 14.
     uint8_t half_led_num = RGBLIGHT_LED_COUNT / 2;
+    length = half_led_num * bytes_per_led;
+    uint8_t data[length];
     for (i = half_led_num + half_led_num - 1; i >= half_led_num; --i)
 #    elif defined(ERGODOX_LED_15_MIRROR)
+    length = led_num * bytes_per_led;
+    uint8_t data[length];
     for (i = 0; i < led_num; ++i)
 #    else  // ERGDOX_LED_15 non-mirrored
+    length = led_num * bytes_per_led;
+    uint8_t data[length];
     for (i = led_num - 1; i >= 0; --i)
 #    endif
     {
-        uint8_t *data = (uint8_t *)(led + i);
-        i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
-        i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
-        i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
+        uint8_t *data_byte = (uint8_t *)(led + i);
+        data[j++] = data_byte[0];
+        data[j++] = data_byte[1];
+        data[j++] = data_byte[2];
 #ifdef RGBW
-        i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
+        data[j++] = data_byte[3];
 #endif
     }
-    i2c_stop();
+    i2c_transmit(0x84, data, sizeof(data), ERGODOX_EZ_I2C_TIMEOUT);
 
     ws2812_setleds(led, led_num);
 }

+ 5 - 12
keyboards/ergodox_ez/matrix.c

@@ -146,13 +146,8 @@ static matrix_row_t read_cols(uint8_t row) {
             uint8_t data = 0;
             // reading GPIOB (column port) since in mcp23018's sequential mode
             // it is addressed directly after writing to GPIOA in select_row()
-            mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-            mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT);               if (mcp23018_status < 0) goto out;
-            data            = ~((uint8_t)mcp23018_status);
-            mcp23018_status = I2C_STATUS_SUCCESS;
-        out:
-            i2c_stop();
-            return data;
+            mcp23018_status = i2c_receive(I2C_ADDR, &data, 1, ERGODOX_EZ_I2C_TIMEOUT);
+            return ~data;
         }
     } else {
         /* read from teensy
@@ -196,11 +191,9 @@ static void select_row(uint8_t row) {
         if (!mcp23018_status) {
             // set active row low  : 0
             // set other rows hi-Z : 1
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT);                 if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(0xFF & ~(1 << row), ERGODOX_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-        out:
-            i2c_stop();
+            uint8_t data;
+            data = 0xFF & ~(1 << row);
+            mcp23018_status = i2c_writeReg(I2C_ADDR, GPIOA, &data, 1, ERGODOX_EZ_I2C_TIMEOUT);
         }
     } else {
         // select on teensy

+ 8 - 16
keyboards/ferris/0_2/matrix.c

@@ -42,9 +42,7 @@ extern i2c_status_t mcp23017_status;
 // All address pins of the mcp23017 are connected to the ground on the ferris
 // | 0  | 1  | 0  | 0  | A2 | A1 | A0 |
 // | 0  | 1  | 0  | 0  | 0  | 0  | 0  |
-#define I2C_ADDR 0b0100000
-#define I2C_ADDR_WRITE ((I2C_ADDR << 1) | I2C_WRITE)
-#define I2C_ADDR_READ ((I2C_ADDR << 1) | I2C_READ)
+#define I2C_ADDR (0b0100000 << 1)
 
 // Register addresses
 // See https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/blob/master/Adafruit_MCP23017.h
@@ -77,9 +75,9 @@ uint8_t init_mcp23017(void) {
     // - driving : output : 0
     // This means: we will read all the bits on GPIOA
     // This means: we will write to the pins 0-4 on GPIOB (in select_rows)
-    uint8_t buf[] = {IODIRA, 0b11111111, 0b11110000};
+    uint8_t buf[] = {0b11111111, 0b11110000};
     print("before transmit\n");
-    mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), MCP23017_I2C_TIMEOUT);
+    mcp23017_status = i2c_writeReg(I2C_ADDR, IODIRA, buf, sizeof(buf), MCP23017_I2C_TIMEOUT)
     uprintf("after transmit %i\n", mcp23017_status);
     if (!mcp23017_status) {
         // set pull-up
@@ -88,8 +86,7 @@ uint8_t init_mcp23017(void) {
         // - driving : off : 0
         // This means: we will read all the bits on GPIOA
         // This means: we will write to the pins 0-4 on GPIOB (in select_rows)
-        uint8_t pullup_buf[] = {GPPUA, 0b11111111, 0b11110000};
-        mcp23017_status      = i2c_transmit(I2C_ADDR_WRITE, pullup_buf, sizeof(pullup_buf), MCP23017_I2C_TIMEOUT);
+        mcp23017_status = i2c_writeReg(I2C_ADDR, GPPUA, buf, sizeof(buf), MCP23017_I2C_TIMEOUT)
         uprintf("after transmit2 %i\n", mcp23017_status);
     }
     return mcp23017_status;
@@ -189,18 +186,13 @@ static matrix_row_t read_cols(uint8_t row) {
         if (mcp23017_status) {  // if there was an error
             return 0;
         } else {
-            uint8_t buf[]   = {MCP23017_GPIOA};
-            mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), MCP23017_I2C_TIMEOUT);
             // We read all the pins on GPIOA.
             // The initial state was all ones and any depressed key at a given column for the currently selected row will have its bit flipped to zero.
             // The return value is a row as represented in the generic matrix code were the rightmost bits represent the lower columns and zeroes represent non-depressed keys while ones represent depressed keys.
             // Since the pins connected to eact columns are sequential, and counting from zero up (col 5 -> GPIOA0, col 6 -> GPIOA1 and so on), the only transformation needed is a bitwise not to swap all zeroes and ones.
             uint8_t data[] = {0};
-            if (!mcp23017_status) {
-                mcp23017_status = i2c_receive(I2C_ADDR_READ, data, sizeof(data), MCP23017_I2C_TIMEOUT);
-                data[0]         = ~(data[0]);
-            }
-            return data[0];
+            mcp23017_status = i2c_readReg(I2C_ADDR, MCP23017_GPIOA, data, sizeof(data), MCP23017_I2C_TIMEOUT);
+            return ~data[0];
         }
     }
 }
@@ -244,8 +236,8 @@ static void select_row(uint8_t row) {
         } else {
             // Select the desired row by writing a byte for the entire GPIOB bus where only the bit representing the row we want to select is a zero (write instruction) and every other bit is a one.
             // Note that the row - MATRIX_ROWS_PER_SIDE reflects the fact that being on the right hand, the columns are numbered from MATRIX_ROWS_PER_SIDE to MATRIX_ROWS, but the pins we want to write to are indexed from zero up on the GPIOB bus.
-            uint8_t buf[]   = {MCP23017_GPIOB, 0xFF & ~(1 << (row - MATRIX_ROWS_PER_SIDE))};
-            mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), I2C_TIMEOUT);
+            uint8_t buf[]   = {0xFF & ~(1 << (row - MATRIX_ROWS_PER_SIDE))};
+            mcp23017_status = i2c_writeReg(I2C_ADDR, MCP23017_GPIOB, buf, sizeof(buf), MCP23017_I2C_TIMEOUT);
         }
     }
 }

+ 11 - 17
keyboards/gboards/ergotaco/ergotaco.c

@@ -49,23 +49,17 @@ uint8_t init_mcp23018(void) {
     // - unused  : input  : 1
     // - input   : input  : 1
     // - driving : output : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(IODIRA, ERGODOX_EZ_I2C_TIMEOUT);            if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00000000, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    i2c_stop();
-
-    // set pull-up
-    // - unused  : on  : 1
-    // - input   : on  : 1
-    // - driving : off : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(GPPUA, ERGODOX_EZ_I2C_TIMEOUT);             if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00000000, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-
-out:
-    i2c_stop();
+    uint8_t data[] = {0b00000000, 0b00111111};
+    mcp23018_status = i2c_writeReg(I2C_ADDR, IODIRA, data, sizeof(data), ERGODOX_EZ_I2C_TIMEOUT);
+
+    if (!mcp23018_status) {
+        // set pull-up
+        // - unused  : on  : 1
+        // - input   : on  : 1
+        // - driving : off : 0
+        mcp23018_status = i2c_writeReg(I2C_ADDR, GPPUA, data, sizeof(data), ERGODOX_EZ_I2C_TIMEOUT);
+    }
+
     // SREG=sreg_prev;
     //uprintf("Init %x\n", mcp23018_status);
     return mcp23018_status;

+ 1 - 4
keyboards/gboards/ergotaco/ergotaco.h

@@ -11,10 +11,7 @@ extern i2c_status_t mcp23018_status;
 #define ERGODOX_EZ_I2C_TIMEOUT 1000
 
 // I2C aliases and register addresses (see "mcp23018.md")
-//#define I2C_ADDR        0b0100000
-#define I2C_ADDR        0x20
-#define I2C_ADDR_WRITE  ( (I2C_ADDR<<1) | I2C_WRITE )
-#define I2C_ADDR_READ   ( (I2C_ADDR<<1) | I2C_READ  )
+#define I2C_ADDR        (0x20<<1)
 #define IODIRA          0x00            // i/o direction register
 #define IODIRB          0x01
 #define GPPUA           0x0C            // GPIO pull-up resistor register

+ 4 - 14
keyboards/gboards/ergotaco/matrix.c

@@ -234,15 +234,8 @@ static matrix_row_t read_cols(uint8_t row)
             return 0;
         } else {
             uint8_t data = 0;
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT);             if (mcp23018_status) goto out;
-            mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT);     if (mcp23018_status) goto out;
-            mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT);                if (mcp23018_status < 0) goto out;
-            data = (~((uint8_t)mcp23018_status) >> 2) & 0x01 ;
-            mcp23018_status = I2C_STATUS_SUCCESS;
-        out:
-            i2c_stop();
-
+            mcp23018_status = i2c_readReg(I2C_ADDR, GPIOB, &data, 1, ERGODOX_EZ_I2C_TIMEOUT);
+            data = (~((uint8_t)data) >> 2) & 0x01 ;
 #ifdef DEBUG_MATRIX
             if (data != 0x00) xprintf("I2C: %d\n", data);
 #endif
@@ -274,11 +267,8 @@ static void select_row(uint8_t row)
         if (mcp23018_status) { // do nothing on error
 			// Read using bitmask
         } else { // set active row low  : 0 // set other rows hi-Z : 1
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT);                 if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(~(1<<row), ERGODOX_EZ_I2C_TIMEOUT);      		if (mcp23018_status) goto out;
-        out:
-            i2c_stop();
+            uint8_t data = ~(1<<row);
+            mcp23018_status = i2c_writeReg(I2C_ADDR, GPIOA, &data, 1, ERGODOX_EZ_I2C_TIMEOUT);
         }
     } else {
         // Output low(DDR:1, PORT:0) to select

+ 10 - 16
keyboards/gboards/georgi/georgi.c

@@ -45,23 +45,17 @@ uint8_t init_mcp23018(void) {
     // - unused  : input  : 1
     // - input   : input  : 1
     // - driving : output : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(IODIRA, ERGODOX_EZ_I2C_TIMEOUT);            if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b10000000, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    i2c_stop();
-
-    // set pull-up
-    // - unused  : on  : 1
-    // - input   : on  : 1
-    // - driving : off : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(GPPUA, ERGODOX_EZ_I2C_TIMEOUT);             if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b10000000, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
+    uint8_t data[] = {0b10000000, 0b11111111};
+    mcp23018_status = i2c_writeReg(I2C_ADDR, IODIRA, data, 2, ERGODOX_EZ_I2C_TIMEOUT);
+
+    if (!mcp23018_status) {
+        // set pull-up
+        // - unused  : on  : 1
+        // - input   : on  : 1
+        // - driving : off : 0
+        mcp23018_status = i2c_writeReg(I2C_ADDR, GPPUA, data, 2, ERGODOX_EZ_I2C_TIMEOUT);
+    }
 
-out:
-    i2c_stop();
     // SREG=sreg_prev;
     //uprintf("Init %x\n", mcp23018_status);
     return mcp23018_status;

+ 1 - 4
keyboards/gboards/georgi/georgi.h

@@ -11,10 +11,7 @@ extern i2c_status_t mcp23018_status;
 #define ERGODOX_EZ_I2C_TIMEOUT 1000
 
 // I2C aliases and register addresses (see "mcp23018.md")
-//#define I2C_ADDR        0b0100000
-#define I2C_ADDR        0x20
-#define I2C_ADDR_WRITE  ( (I2C_ADDR<<1) | I2C_WRITE )
-#define I2C_ADDR_READ   ( (I2C_ADDR<<1) | I2C_READ  )
+#define I2C_ADDR        (0x20<<1)
 #define IODIRA          0x00            // i/o direction register
 #define IODIRB          0x01
 #define GPPUA           0x0C            // GPIO pull-up resistor register

+ 4 - 13
keyboards/gboards/georgi/matrix.c

@@ -254,14 +254,7 @@ static matrix_row_t read_cols(uint8_t row)
             return 0;
         } else {
             uint8_t data = 0;
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT);             if (mcp23018_status) goto out;
-            mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT);     if (mcp23018_status) goto out;
-            mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT);                if (mcp23018_status < 0) goto out;
-            data = ~((uint8_t)mcp23018_status);
-            mcp23018_status = I2C_STATUS_SUCCESS;
-        out:
-            i2c_stop();
+            mcp23018_status = i2c_readReg(I2C_ADDR, GPIOB, &data, 1, ERGODOX_EZ_I2C_TIMEOUT);
 
 #ifdef DEBUG_MATRIX
             if (data != 0x00) xprintf("I2C: %d\n", data);
@@ -304,11 +297,9 @@ static void select_row(uint8_t row)
         // select on mcp23018
         if (mcp23018_status) { // do nothing on error
         } else { // set active row low  : 0 // set other rows hi-Z : 1
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT);                 if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(0xFF & ~(1<<row), ERGODOX_EZ_I2C_TIMEOUT);      if (mcp23018_status) goto out;
-        out:
-            i2c_stop();
+        uint8_t data = 0xFF & ~(1<<row);
+        mcp23018_status = i2c_writeReg(I2C_ADDR, GPIOA, &data, 1, ERGODOX_EZ_I2C_TIMEOUT);
+
         }
     } else {
         // Output low(DDR:1, PORT:0) to select

+ 9 - 15
keyboards/gboards/gergo/gergo.c

@@ -43,23 +43,17 @@ uint8_t init_mcp23018(void) {
     // - unused  : input  : 1
     // - input   : input  : 1
     // - driving : output : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(IODIRA, I2C_TIMEOUT);            if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b10000000, I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111, I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    i2c_stop();
+    uint8_t data[] = {0b10000000, 0b11111111};
+    mcp23018_status = i2c_writeReg(I2C_ADDR, IODIRA, data, sizeof(data), I2C_TIMEOUT);
 
-    // set pull-up
-    // - unused  : on  : 1
-    // - input   : on  : 1
-    // - driving : off : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(GPPUA, I2C_TIMEOUT);             if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b10000000, I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111, I2C_TIMEOUT);        if (mcp23018_status) goto out;
+    if (!mcp23018_status) {
+        // set pull-up
+        // - unused  : on  : 1
+        // - input   : on  : 1
+        // - driving : off : 0
+        mcp23018_status = i2c_writeReg(I2C_ADDR, GPPUA, data, sizeof(data), I2C_TIMEOUT);
+    }
 
-out:
-    i2c_stop();
     // SREG=sreg_prev;
     //uprintf("Init %x\n", mcp23018_status);
     return mcp23018_status;

+ 1 - 4
keyboards/gboards/gergo/gergo.h

@@ -11,10 +11,7 @@ extern i2c_status_t mcp23018_status;
 #define I2C_TIMEOUT 1000
 
 // I2C aliases and register addresses (see "mcp23018.md")
-//#define I2C_ADDR        0b0100000
-#define I2C_ADDR        0x20
-#define I2C_ADDR_WRITE  ( (I2C_ADDR<<1) | I2C_WRITE )
-#define I2C_ADDR_READ   ( (I2C_ADDR<<1) | I2C_READ  )
+#define I2C_ADDR        (0x20<<1)
 #define IODIRA          0x00            // i/o direction register
 #define IODIRB          0x01
 #define GPPUA           0x0C            // GPIO pull-up resistor register

+ 5 - 15
keyboards/gboards/gergo/matrix.c

@@ -297,19 +297,12 @@ static matrix_row_t read_cols(uint8_t row) {
             return 0;
         } else {
             uint8_t data = 0;
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);    if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOB, I2C_TIMEOUT);             if (mcp23018_status) goto out;
-            mcp23018_status = i2c_start(I2C_ADDR_READ, I2C_TIMEOUT);     if (mcp23018_status) goto out;
-            mcp23018_status = i2c_read_nack(I2C_TIMEOUT);                if (mcp23018_status < 0) goto out;
-            data = ~((uint8_t)mcp23018_status);
-            mcp23018_status = I2C_STATUS_SUCCESS;
-        out:
-            i2c_stop();
+            mcp23018_status = i2c_readReg(I2C_ADDR, GPIOB, &data, 1, I2C_TIMEOUT);
 
 #ifdef DEBUG_MATRIX
-            if (data != 0x00) xprintf("I2C: %d\n", data);
+            if (~data != 0x00) xprintf("I2C: %d\n", ~data);
 #endif
-            return data;
+            return ~data;
         }
     } else {
          /* read from teensy
@@ -350,11 +343,8 @@ static void select_row(uint8_t row)
         // select on mcp23018
         if (mcp23018_status) { // do nothing on error
         } else { // set active row low  : 0 // set other rows hi-Z : 1
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);        if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOA, I2C_TIMEOUT);                 if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(0xFF & ~(1<<row), I2C_TIMEOUT);      if (mcp23018_status) goto out;
-        out:
-            i2c_stop();
+            uint8_t data = 0xFF & ~(1<<row);
+            mcp23018_status = i2c_writeReg(I2C_ADDR, GPIOA, &data, 1, I2C_TIMEOUT);
         }
     } else {
         // Output low(DDR:1, PORT:0) to select

+ 10 - 24
keyboards/gboards/gergoplex/gergoplex.c

@@ -39,30 +39,16 @@ uint8_t init_mcp23018(void) {
     // - unused  : input  : 1
     // - input   : input  : 1
     // - driving : output : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(IODIRA, I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11000001, I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111, I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    i2c_stop();
-
-    // set pull-up
-    // - unused  : on  : 1
-    // - input   : on  : 1
-    // - driving : off : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(GPPUA, I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11000001, I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b11111111, I2C_TIMEOUT);
-    if (mcp23018_status) goto out;
+    uint8_t data[] = {0b11000001, 0b11111111};
+    mcp23018_status = i2c_writeReg(I2C_ADDR, IODIRA, data, sizeof(data), I2C_TIMEOUT);
+
+    if (!mcp23018_status) {
+        // set pull-up
+        // - unused  : on  : 1
+        // - input   : on  : 1
+        // - driving : off : 0
+        mcp23018_status = i2c_writeReg(I2C_ADDR, GPPUA, data, sizeof(data), I2C_TIMEOUT);
+    }
 
-out:
-    i2c_stop();
     return mcp23018_status;
 }

+ 1 - 3
keyboards/gboards/gergoplex/gergoplex.h

@@ -25,9 +25,7 @@ extern i2c_status_t mcp23018_status;
 #define XXX KC_NO
 
 // I2C aliases and register addresses (see "mcp23018.md")
-#define I2C_ADDR 0x20  // 0b0100000
-#define I2C_ADDR_WRITE ((I2C_ADDR << 1) | I2C_WRITE)
-#define I2C_ADDR_READ ((I2C_ADDR << 1) | I2C_READ)
+#define I2C_ADDR (0x20 << 1)  // 0b0100000
 #define IODIRA 0x00  // i/o direction register
 #define IODIRB 0x01
 #define GPPUA 0x0C  // GPIO pull-up resistor register

+ 8 - 20
keyboards/gboards/gergoplex/matrix.c

@@ -177,20 +177,12 @@ static matrix_row_t read_cols(uint8_t row) {
         if (mcp23018_status) {  // if there was an error
             return 0;
         } else {
-            uint8_t data    = 0;
-            mcp23018_status = i2c_start(I2C_ADDR_READ, I2C_TIMEOUT);
-            if (mcp23018_status) goto out;
-            mcp23018_status = i2c_read_nack(I2C_TIMEOUT);
-            if (mcp23018_status < 0) goto out;
-            data            = ~((uint8_t)mcp23018_status);
-            mcp23018_status = I2C_STATUS_SUCCESS;
-        out:
-            i2c_stop();
-
+            uint8_t data = 0;
+            mcp23018_status = i2c_receive(I2C_ADDR, &data, 1, I2C_TIMEOUT);
 #ifdef DEBUG_MATRIX
-            if (data != 0x00) xprintf("I2C: %d\n", data);
+            if (~data != 0x00) xprintf("I2C: %d\n", ~data);
 #endif
-            return data;
+            return ~data;
         }
     } else {
         return ~((((PINF & COL4) >> 1) | ((PINF & (COL1 | COL2 | COL3)) >> 3)) & 0xF);
@@ -213,14 +205,10 @@ static void select_row(uint8_t row) {
         // select on mcp23018
         if (mcp23018_status) {  // do nothing on error
         } else {                // set active row low  : 0 // set other rows hi-Z : 1
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);
-            if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOA, I2C_TIMEOUT);
-            if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(0xFF & ~(1 << (row + 1)), I2C_TIMEOUT);
-            if (mcp23018_status) goto out;
-        out:
-            i2c_stop();
+            uint8_t data;
+            data = 0xFF & ~(1 << (row + 1));
+            mcp23018_status = i2c_writeReg(I2C_ADDR, GPIOA, &data, 1, I2C_TIMEOUT);
+
         }
     } else {
         setPinOutput(row_pins[row - MATRIX_ROWS_PER_SIDE]);

+ 0 - 1
keyboards/handwired/d48/ds1307.c

@@ -14,7 +14,6 @@ void ds1307_set_time(uint8_t h, uint8_t m, uint8_t s) {
 void ds1307_get_time(uint8_t *h, uint8_t *m, uint8_t *s) {
     uint8_t data[3];
     i2c_read_register(DS1307_ADDR, 0, data, 3, 100);
-    i2c_stop();
     *s = (data[0] & 0b1111) + ((data[0] & 0b1110000) >> 4) * 10;
     *m = (data[1] & 0b1111) + ((data[1] & 0b1110000) >> 4) * 10;
     *h = (data[2] & 0b1111) + ((data[2] & 0b0110000) >> 4) * 10;

+ 10 - 17
keyboards/handwired/frenchdev/frenchdev.c

@@ -83,23 +83,16 @@ uint8_t init_mcp23018(void) {
     // - unused  : input  : 1
     // - input   : input  : 1
     // - driving : output : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(IODIRA, I2C_TIMEOUT);            if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00000000, I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00111111, I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    i2c_stop();
-
-    // set pull-up
-    // - unused  : on  : 1
-    // - input   : on  : 1
-    // - driving : off : 0
-    mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);    if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(GPPUA, I2C_TIMEOUT);             if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00000000, I2C_TIMEOUT);        if (mcp23018_status) goto out;
-    mcp23018_status = i2c_write(0b00111111, I2C_TIMEOUT);        if (mcp23018_status) goto out;
-
-out:
-    i2c_stop();
+    uint8_t data[] = {0b00000000, 0b00111111};
+    mcp23018_status = i2c_writeReg(I2C_ADDR, IODIRA, data, sizeof(data), I2C_TIMEOUT);
+
+    if (!mcp23018_status) {
+        // set pull-up
+        // - unused  : on  : 1
+        // - input   : on  : 1
+        // - driving : off : 0
+        mcp23018_status = i2c_writeReg(I2C_ADDR, GPPUA, data, sizeof(data), I2C_TIMEOUT);
+    }
 
     // SREG=sreg_prev;
 

+ 1 - 3
keyboards/handwired/frenchdev/frenchdev.h

@@ -7,9 +7,7 @@
 #include <util/delay.h>
 
 // I2C aliases and register addresses (see "mcp23018.md" on tmk repository)
-#define I2C_ADDR        0b0100000
-#define I2C_ADDR_WRITE  ( (I2C_ADDR<<1) | I2C_WRITE )
-#define I2C_ADDR_READ   ( (I2C_ADDR<<1) | I2C_READ  )
+#define I2C_ADDR        (0b0100000<<1)
 #define IODIRA          0x00            // i/o direction register
 #define IODIRB          0x01
 #define GPPUA           0x0C            // GPIO pull-up resistor register

+ 9 - 19
keyboards/handwired/frenchdev/matrix.c

@@ -224,15 +224,9 @@ static matrix_row_t read_cols(uint8_t row)
             return 0;
         } else {
             uint8_t data = 0;
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);   if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOB, I2C_TIMEOUT);            if (mcp23018_status) goto out;
-            mcp23018_status = i2c_start(I2C_ADDR_READ, I2C_TIMEOUT);    if (mcp23018_status) goto out;
-            data = i2c_read_nack(I2C_TIMEOUT);                         if (mcp23018_status < 0) goto out;
-            data = ~((uint8_t)mcp23018_status);
-            mcp23018_status = I2C_STATUS_SUCCESS;
-        out:
-            i2c_stop();
-            return data;
+            mcp23018_status = i2c_readReg(I2C_ADDR, GPIOB, &data, 1, I2C_TIMEOUT);
+
+            return ~data;
         }
     } else {
         // read from teensy
@@ -263,11 +257,10 @@ static void unselect_rows(void)
         // do nothing
     } else {
         // set all rows hi-Z : 1
-        mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);    if (mcp23018_status) goto out;
-        mcp23018_status = i2c_write(GPIOA, I2C_TIMEOUT);             if (mcp23018_status) goto out;
-        mcp23018_status = i2c_write( 0xFF & ~(0<<8), I2C_TIMEOUT);   if (mcp23018_status) goto out;
-    out:
-        i2c_stop();
+        uint8_t data;
+        data = 0xFF & ~(0<<8);
+        mcp23018_status = i2c_writeReg(I2C_ADDR, GPIOA, &data, 1, I2C_TIMEOUT);
+
     }
 
     // unselect on teensy
@@ -289,11 +282,8 @@ static void select_row(uint8_t row)
         } else {
             // set active row low  : 0
             // set other rows hi-Z : 1
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);                          if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOA, I2C_TIMEOUT);                                   if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write( 0xFF & ~(1<<row) & ~(0<<8), I2C_TIMEOUT);             if (mcp23018_status) goto out;
-        out:
-            i2c_stop();
+            uint8_t data = 0xFF & ~(1<<row) & ~(0<<8);
+            mcp23018_status = i2c_writeReg(I2C_ADDR, GPIOA, &data, 1, I2C_TIMEOUT);
         }
     } else {
         // select on teensy

+ 2 - 13
keyboards/handwired/onekey/keymaps/i2c_scanner/keymap.c

@@ -8,16 +8,6 @@
 // TODO: remove patch
 #ifdef PROTOCOL_CHIBIOS
 #    pragma message("ChibiOS is currently 'best effort' and might not report accurate results")
-
-i2c_status_t i2c_start_bodge(uint8_t address, uint16_t timeout) {
-    i2c_start(address);
-
-    // except on ChibiOS where the only way is do do "something"
-    uint8_t data = 0;
-    return i2c_read_register(address, 0, &data, sizeof(data), TIMEOUT);
-}
-
-#    define i2c_start i2c_start_bodge
 #endif
 
 const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
@@ -31,10 +21,9 @@ void do_scan(void) {
 
     for (uint8_t address = 1; address < 127; address++) {
         // The i2c_scanner uses the return value of
-        // i2c_start to see if a device did acknowledge to the address.
-        i2c_status_t error = i2c_start(address << 1, TIMEOUT);
+        // i2c_ping_address to see if a device did acknowledge to the address.
+        i2c_status_t error = i2c_ping_address(address << 1, TIMEOUT);
         if (error == I2C_STATUS_SUCCESS) {
-            i2c_stop();
             dprintf("  I2C device found at address 0x%02X\n", address);
             nDevices++;
         } else {

+ 20 - 63
keyboards/handwired/pterodactyl/matrix.c

@@ -29,9 +29,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 #define I2C_TIMEOUT 100
 
-#define I2C_ADDR        0b0100000
-#define I2C_ADDR_WRITE  ( (I2C_ADDR<<1) | I2C_WRITE )
-#define I2C_ADDR_READ   ( (I2C_ADDR<<1) | I2C_READ  )
+#define I2C_ADDR        (0b0100000<<1)
 #define IODIRA          0x00            // i/o direction register
 #define IODIRB          0x01
 #define GPPUA           0x0C            // GPIO pull-up resistor register
@@ -159,9 +157,6 @@ void init_expander(void) {
 #endif
     }
 
-    expander_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT); if (expander_status) goto out;
-    expander_status = i2c_write(IODIRA, I2C_TIMEOUT);         if (expander_status) goto out;
-
     /*
     Pin direction and pull-up depends on both the diode direction
     and on whether the column register is GPIOA or GPIOB
@@ -176,50 +171,27 @@ void init_expander(void) {
 
 #if (EXPANDER_COL_REGISTER == GPIOA)
 #   if (DIODE_DIRECTION == COL2ROW)
-        expander_status = i2c_write(expander_input_pin_mask, I2C_TIMEOUT); if (expander_status) goto out;
-        expander_status = i2c_write(0, I2C_TIMEOUT);                       if (expander_status) goto out;
+    uint8_t data[] = { expander_input_pin_mask, 0};
 #   elif (DIODE_DIRECTION == ROW2COL)
-        expander_status = i2c_write(0, I2C_TIMEOUT);                       if (expander_status) goto out;
-        expander_status = i2c_write(expander_input_pin_mask, I2C_TIMEOUT); if (expander_status) goto out;
+    uint8_t data[] = { 0, expander_input_pin_mask};
 #   endif
 #elif (EXPANDER_COL_REGISTER == GPIOB)
 #   if (DIODE_DIRECTION == COL2ROW)
-        expander_status = i2c_write(0, I2C_TIMEOUT);                       if (expander_status) goto out;
-        expander_status = i2c_write(expander_input_pin_mask, I2C_TIMEOUT); if (expander_status) goto out;
+    uint8_t data[] = { 0, expander_input_pin_mask};
 #   elif (DIODE_DIRECTION == ROW2COL)
-        expander_status = i2c_write(expander_input_pin_mask, I2C_TIMEOUT); if (expander_status) goto out;
-        expander_status = i2c_write(0, I2C_TIMEOUT);                       if (expander_status) goto out;
-#   endif
-#endif
-
-    i2c_stop();
-
-    // set pull-up
-    // - unused  : off : 0
-    // - input   : on  : 1
-    // - driving : off : 0
-    expander_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);              if (expander_status) goto out;
-    expander_status = i2c_write(GPPUA, I2C_TIMEOUT);                       if (expander_status) goto out;
-#if (EXPANDER_COL_REGISTER == GPIOA)
-#   if (DIODE_DIRECTION == COL2ROW)
-        expander_status = i2c_write(expander_input_pin_mask, I2C_TIMEOUT); if (expander_status) goto out;
-        expander_status = i2c_write(0, I2C_TIMEOUT);                       if (expander_status) goto out;
-#   elif (DIODE_DIRECTION == ROW2COL)
-        expander_status = i2c_write(0, I2C_TIMEOUT);                       if (expander_status) goto out;
-        expander_status = i2c_write(expander_input_pin_mask, I2C_TIMEOUT); if (expander_status) goto out;
-#   endif
-#elif (EXPANDER_COL_REGISTER == GPIOB)
-#   if (DIODE_DIRECTION == COL2ROW)
-        expander_status = i2c_write(0, I2C_TIMEOUT);                       if (expander_status) goto out;
-        expander_status = i2c_write(expander_input_pin_mask, I2C_TIMEOUT); if (expander_status) goto out;
-#   elif (DIODE_DIRECTION == ROW2COL)
-        expander_status = i2c_write(expander_input_pin_mask, I2C_TIMEOUT); if (expander_status) goto out;
-        expander_status = i2c_write(0, I2C_TIMEOUT);                       if (expander_status) goto out;
+    uint8_t data[] = { expander_input_pin_mask, 0};
 #   endif
 #endif
+    expander_status = i2c_writeReg(I2C_ADDR, IODIRA, data, sizeof(data), I2C_TIMEOUT);
+
+    if (!expander_status) {
+        // set pull-up
+        // - unused  : off : 0
+        // - input   : on  : 1
+        // - driving : off : 0
+        expander_status = i2c_writeReg(I2C_ADDR, GPPUA, data, sizeof(data), I2C_TIMEOUT);
+    }
 
-out:
-    i2c_stop();
 }
 
 uint8_t matrix_scan(void)
@@ -332,14 +304,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
 
     // Read columns from expander, unless it's in an error state
     if (! expander_status) {
-        expander_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);           if (expander_status) goto out;
-        expander_status = i2c_write(EXPANDER_COL_REGISTER, I2C_TIMEOUT);    if (expander_status) goto out;
-        expander_status = i2c_start(I2C_ADDR_READ, I2C_TIMEOUT);            if (expander_status) goto out;
-
-        current_matrix[current_row] |= (~i2c_read_nack(I2C_TIMEOUT)) & expander_input_pin_mask;
-
-        out:
-            i2c_stop();
+        uint8_t data;
+        i2c_readReg(I2C_ADDR, EXPANDER_COL_REGISTER, &data, 1, I2C_TIMEOUT);
+        current_matrix[current_row] |= (~data) & expander_input_pin_mask;
     }
 
     // Read columns from onboard pins
@@ -361,11 +328,8 @@ static void select_row(uint8_t row) {
     if (! expander_status) {
         // set active row low  : 0
         // set other rows hi-Z : 1
-        expander_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);           if (expander_status) goto out;
-        expander_status = i2c_write(EXPANDER_ROW_REGISTER, I2C_TIMEOUT);    if (expander_status) goto out;
-        expander_status = i2c_write(0xFF & ~(1<<row), I2C_TIMEOUT);         if (expander_status) goto out;
-    out:
-        i2c_stop();
+        uint8_t data = 0xFF & ~(1<<row);
+        i2c_writeReg(I2C_ADDR, EXPANDER_ROW_REGISTER, &data, 1, I2C_TIMEOUT);
     }
 
     // select on teensy
@@ -421,14 +385,7 @@ static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
             return false;
         }
 
-        expander_status = i2c_start(I2C_ADDR_WRITE, I2C_TIMEOUT);           if (expander_status) goto out;
-        expander_status = i2c_write(EXPANDER_ROW_REGISTER, I2C_TIMEOUT);    if (expander_status) goto out;
-        expander_status = i2c_start(I2C_ADDR_READ, I2C_TIMEOUT);            if (expander_status) goto out;
-        column_state = i2c_read_nack(I2C_TIMEOUT);
-
-        out:
-            i2c_stop();
-
+        i2c_writeReg(I2C_ADDR, EXPANDER_ROW_REGISTER, &column_state, 1, I2C_TIMEOUT);
         column_state = ~column_state;
     } else {
         for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {

+ 11 - 23
keyboards/hotdox/left.c

@@ -5,8 +5,8 @@
 bool i2c_initialized = false;
 
 void left_config(void);
-uint8_t left_write(uint8_t reg, uint8_t data);
-uint8_t left_read(uint8_t reg, uint8_t *data);
+i2c_status_t left_write(uint8_t reg, uint8_t data);
+i2c_status_t left_read(uint8_t reg, uint8_t *data);
 
 uint8_t init_mcp23017(void)
 {
@@ -35,12 +35,11 @@ void left_init(void)
 
 void left_scan(void)
 {
-    uint8_t ret = i2c_start(I2C_ADDR_WRITE, HOTDOX_I2C_TIMEOUT);
+    
+    i2c_status_t ret = i2c_ping_address(I2C_ADDR, HOTDOX_I2C_TIMEOUT);
 
-    if (ret == 0)
+    if (ret == I2C_STATUS_SUCCESS)
     {
-        i2c_stop();
-
         if (!i2c_initialized)
         {
             i2c_initialized = true;
@@ -91,40 +90,29 @@ void left_config(void)
   left_write(MCP23017_B0_GPIOB,  0xC0);
 }
 
-uint8_t left_write(uint8_t reg, uint8_t data)
+i2c_status_t left_write(uint8_t reg, uint8_t data)
 {
   if (!i2c_initialized)
   {
     return 0;
   }
 
-  uint8_t ret;
+  i2c_status_t ret;
 
-  ret = i2c_start(I2C_ADDR_WRITE, HOTDOX_I2C_TIMEOUT);     if (ret) goto out;
-  ret = i2c_write(reg, HOTDOX_I2C_TIMEOUT);                if (ret) goto out;
-  ret = i2c_write(data, HOTDOX_I2C_TIMEOUT);
+  ret = i2c_writeReg(I2C_ADDR, reg,  &data, sizeof(data), HOTDOX_I2C_TIMEOUT); 
 
-out:
-  i2c_stop();
   return ret;
 }
 
-uint8_t left_read(uint8_t reg, uint8_t *data)
+i2c_status_t left_read(uint8_t reg, uint8_t *data)
 {
   if (!i2c_initialized)
   {
     return 0;
   }
 
-  uint8_t ret = 0;
-
-  ret = i2c_start(I2C_ADDR_WRITE, HOTDOX_I2C_TIMEOUT);     if (ret) goto out;
-  ret = i2c_write(reg, HOTDOX_I2C_TIMEOUT);                if (ret) goto out;
-  ret = i2c_start(I2C_ADDR_READ, HOTDOX_I2C_TIMEOUT);      if (ret) goto out;
-
-  *data = i2c_read_nack(HOTDOX_I2C_TIMEOUT);
+  i2c_status_t ret = 0;
+  ret = i2c_readReg(I2C_ADDR, reg, data, 1, HOTDOX_I2C_TIMEOUT);
 
-out:
-  i2c_stop();
   return ret;
 }

+ 1 - 6
keyboards/hotdox/left.h

@@ -10,10 +10,7 @@
 #define MCP23017_A1 0
 #define MCP23017_A2 0
 
-#define I2C_ADDR        (0x20)
-#define I2C_ADDR_WRITE  ((I2C_ADDR << 1) | I2C_WRITE)
-#define I2C_ADDR_READ   ((I2C_ADDR << 1) | I2C_READ)
-
+#define I2C_ADDR        ((0x20) << 1)
 
 #define MCP23017_B0_IODIRA     0x00
 #define MCP23017_B0_IODIRB     0x01
@@ -40,8 +37,6 @@
 
 #define HOTDOX_I2C_TIMEOUT     100
 
-typedef int16_t i2c_status_t;
-
 void left_init(void);
 void left_scan(void);
 

+ 6 - 8
keyboards/ingrained/matrix.c

@@ -41,9 +41,7 @@ extern i2c_status_t mcp23017_status;
 // All address pins of the mcp23017 are connected to the ground on the ferris
 // | 0  | 1  | 0  | 0  | A2 | A1 | A0 |
 // | 0  | 1  | 0  | 0  | 0  | 0  | 0  |
-#define I2C_ADDR 0b0100000
-#define I2C_ADDR_WRITE ((I2C_ADDR << 1) | I2C_WRITE)
-#define I2C_ADDR_READ ((I2C_ADDR << 1) | I2C_READ)
+#define I2C_ADDR (0b0100000<<1)
 
 // Register addresses
 // See https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/blob/master/Adafruit_MCP23017.h
@@ -77,7 +75,7 @@ uint8_t init_mcp23017(void) {
     // This means: we will read all the bits on GPIOA
     // This means: we will write to the pins 0-4 on GPIOB (in select_rows)
     uint8_t buf[]   = {IODIRA, 0b11111111, 0b11110000};
-    mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), I2C_TIMEOUT);
+    mcp23017_status = i2c_transmit(I2C_ADDR, buf, sizeof(buf), I2C_TIMEOUT);
     if (!mcp23017_status) {
         // set pull-up
         // - unused  : on  : 1
@@ -86,7 +84,7 @@ uint8_t init_mcp23017(void) {
         // This means: we will read all the bits on GPIOA
         // This means: we will write to the pins 0-4 on GPIOB (in select_rows)
         uint8_t pullup_buf[] = {GPPUA, 0b11111111, 0b11110000};
-        mcp23017_status      = i2c_transmit(I2C_ADDR_WRITE, pullup_buf, sizeof(pullup_buf), I2C_TIMEOUT);
+        mcp23017_status      = i2c_transmit(I2C_ADDR, pullup_buf, sizeof(pullup_buf), I2C_TIMEOUT);
     }
     return mcp23017_status;
 }
@@ -205,14 +203,14 @@ static matrix_row_t read_cols(uint8_t row) {
             return 0;
         } else {
             uint8_t buf[]   = {GPIOA};
-            mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), I2C_TIMEOUT);
+            mcp23017_status = i2c_transmit(I2C_ADDR, buf, sizeof(buf), I2C_TIMEOUT);
             // We read all the pins on GPIOA.
             // The initial state was all ones and any depressed key at a given column for the currently selected row will have its bit flipped to zero.
             // The return value is a row as represented in the generic matrix code were the rightmost bits represent the lower columns and zeroes represent non-depressed keys while ones represent depressed keys.
             // Since the pins connected to eact columns are sequential, and counting from zero up (col 5 -> GPIOA0, col 6 -> GPIOA1 and so on), the only transformation needed is a bitwise not to swap all zeroes and ones.
             uint8_t data[] = {0};
             if (!mcp23017_status) {
-                mcp23017_status = i2c_receive(I2C_ADDR_READ, data, sizeof(data), I2C_TIMEOUT);
+                mcp23017_status = i2c_receive(I2C_ADDR, data, sizeof(data), I2C_TIMEOUT);
                 data[0]         = ~(data[0]);
             }
             return data[0];
@@ -249,7 +247,7 @@ static void select_row(uint8_t row) {
             // Select the desired row by writing a byte for the entire GPIOB bus where only the bit representing the row we want to select is a zero (write instruction) and every other bit is a one.
             // Note that the row - MATRIX_ROWS_PER_SIDE reflects the fact that being on the right hand, the columns are numbered from MATRIX_ROWS_PER_SIDE to MATRIX_ROWS, but the pins we want to write to are indexed from zero up on the GPIOB bus.
             uint8_t buf[]   = {GPIOB, 0xFF & ~(1 << (row - MATRIX_ROWS_PER_SIDE))};
-            mcp23017_status = i2c_transmit(I2C_ADDR_WRITE, buf, sizeof(buf), I2C_TIMEOUT);
+            mcp23017_status = i2c_transmit(I2C_ADDR, buf, sizeof(buf), I2C_TIMEOUT);
         }
     }
 }

+ 1 - 2
keyboards/kagizaraya/chidori/board.c

@@ -124,10 +124,9 @@ static void board_slave_init(void) {
         if (board_is_master(board)) {
             continue;
         }
-        if (i2c_start(EXPANDER_ADDR(board->i2c_address), BOARD_I2C_TIMEOUT) != I2C_STATUS_SUCCESS) {
+        if (i2c_ping_address(EXPANDER_ADDR(board->i2c_address), BOARD_I2C_TIMEOUT) != I2C_STATUS_SUCCESS) {
             continue;
         }
-        i2c_stop();
         if (board_slave_config(board)) {
             board->initialized = true;
         }

+ 1 - 3
keyboards/nek_type_a/nek_type_a.h

@@ -21,9 +21,7 @@
 #include <stdbool.h>
 #include <util/delay.h>
 
-#define I2C_ADDR        0b0100000
-#define I2C_ADDR_WRITE  ( (I2C_ADDR<<1) | I2C_WRITE )
-#define I2C_ADDR_READ   ( (I2C_ADDR<<1) | I2C_READ  )
+#define I2C_ADDR        (0b0100000<<1)
 #define IODIRA          0x00            // i/o direction register
 #define IODIRB          0x01
 #define GPPUA           0x0C            // GPIO pull-up resistor register

+ 13 - 64
keyboards/system76/launch_1/usb_mux.c

@@ -77,51 +77,14 @@ i2c_status_t usb7206_read_reg(struct USB7206* self, uint32_t addr, uint8_t* data
         return status;
     }
 
-    uint8_t read[2] = {
-        0x00,  // Buffer address MSB: always 0
-        0x06,  // Buffer address LSB: 6 to skip header
-    };
-
-    status = i2c_start((self->addr << 1) | I2C_WRITE, I2C_TIMEOUT);
-    if (status >= 0) {
-        for (uint16_t i = 0; i < sizeof(read); i++) {
-            status = i2c_write(read[i], I2C_TIMEOUT);
-            if (status < 0) {
-                goto error;
-            }
-        }
-    } else {
-        goto error;
-    }
-
-    status = i2c_start((self->addr << 1) | I2C_READ, I2C_TIMEOUT);
-    if (status < 0) {
-        goto error;
-    }
-
-    // Read and ignore buffer length
-    status = i2c_read_ack(I2C_TIMEOUT);
-    if (status < 0) {
-        goto error;
-    }
+    uint16_t read = 0x0006; // Buffer address 6 to skip header
+    uint8_t data_with_buffer_length[length];
+    status = i2c_readReg16((self->addr << 1), read, data_with_buffer_length, length, I2C_TIMEOUT);
 
     for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
-        status = i2c_read_ack(I2C_TIMEOUT);
-        if (status >= 0) {
-            data[i] = (uint8_t)status;
-        }
+        data[i] = data_with_buffer_length[i+1];
     }
 
-    if (status >= 0) {
-        status = i2c_read_nack(I2C_TIMEOUT);
-        if (status >= 0) {
-            data[(length - 1)] = (uint8_t)status;
-        }
-    }
-
-error:
-    i2c_stop();
-
     return (status < 0) ? status : length;
 }
 
@@ -160,35 +123,21 @@ i2c_status_t usb7206_write_reg(struct USB7206* self, uint32_t addr, uint8_t* dat
         (uint8_t)(addr >> 8),   // Register address byte 1
         (uint8_t)(addr >> 0),   // Register address byte 0
     };
+    uint8_t send_buffer_length = sizeof(register_write) + length;
+    uint8_t send_buffer[send_buffer_length];
+    uint8_t j = 0;
 
-    status = i2c_start((self->addr << 1) | I2C_WRITE, I2C_TIMEOUT);
-    if (status >= 0) {
-        for (uint16_t i = 0; i < sizeof(register_write); i++) {
-            status = i2c_write(register_write[i], I2C_TIMEOUT);
-            if (status < 0) {
-                goto error;
-            }
-        }
+    for (uint16_t i = 0; i < sizeof(register_write); i++) {
+        send_buffer[j++] = register_write[i];
+    }
 
-        for (uint16_t i = 0; i < length; i++) {
-            status = i2c_write(data[i], I2C_TIMEOUT);
-            if (status < 0) {
-                goto error;
-            }
-        }
-    } else {
-        goto error;
+    for (uint16_t i = 0; i < length; i++) {
+        send_buffer[j++] = data[i];
     }
 
-    i2c_stop();
+    status = i2c_transmit((self->addr << 1), send_buffer, send_buffer_length, I2C_TIMEOUT);
 
     status = usb7206_register_access(self);
-    if (status < 0) {
-        goto error;
-    }
-
-error:
-    i2c_stop();
 
     return (status < 0) ? status : length;
 }

+ 2 - 2
keyboards/ymdk/sp64/matrix.c

@@ -114,7 +114,7 @@ uint8_t matrix_scan(void)
 #ifdef RIGHT_HALF
     uint8_t data = 0x7F;
     // Receive the columns from right half
-    i2c_receive(I2C_ADDR_WRITE, &data, 1, MCP23018_I2C_TIMEOUT);
+    i2c_receive(I2C_ADDR, &data, 1, MCP23018_I2C_TIMEOUT);
     cols |= ((~(data) & 0x7F) << 7);
 #endif
 
@@ -162,7 +162,7 @@ static void matrix_select_row(uint8_t row)
   //Set the remote row on port A
   txdata[0] = GPIOA;
   txdata[1] = 0xFF & ~(1<<row);
-  mcp23018_status = i2c_transmit(I2C_ADDR_WRITE, (uint8_t *)txdata, 2, MCP23018_I2C_TIMEOUT);
+  mcp23018_status = i2c_transmit(I2C_ADDR, (uint8_t *)txdata, 2, MCP23018_I2C_TIMEOUT);
 #endif
 
   // select other half

+ 3 - 3
keyboards/ymdk/sp64/sp64.c

@@ -39,7 +39,7 @@ uint8_t init_mcp23018(void)
   data[0] = IODIRA;
   data[1] = 0b00000000;
   data[2] = 0b11111111;
-  mcp23018_status = i2c_transmit(I2C_ADDR_WRITE, (uint8_t *)data, 3, MCP23018_I2C_TIMEOUT);
+  mcp23018_status = i2c_transmit(I2C_ADDR, (uint8_t *)data, 3, MCP23018_I2C_TIMEOUT);
   if (mcp23018_status != I2C_STATUS_SUCCESS)
     goto out;
 
@@ -50,7 +50,7 @@ uint8_t init_mcp23018(void)
   data[0] = GPPUA;
   data[1] = 0b00000000;
   data[2] = 0b11111111;
-  mcp23018_status = i2c_transmit(I2C_ADDR_WRITE, (uint8_t *)data, 3, MCP23018_I2C_TIMEOUT);
+  mcp23018_status = i2c_transmit(I2C_ADDR, (uint8_t *)data, 3, MCP23018_I2C_TIMEOUT);
   if (mcp23018_status != I2C_STATUS_SUCCESS)
     goto out;
 
@@ -61,7 +61,7 @@ uint8_t init_mcp23018(void)
   data[0] = OLATA;
   data[1] = 0b11111111;
   data[2] = 0b11111111;
-  mcp23018_status = i2c_transmit(I2C_ADDR_WRITE, (uint8_t *)data, 3, MCP23018_I2C_TIMEOUT);
+  mcp23018_status = i2c_transmit(I2C_ADDR, (uint8_t *)data, 3, MCP23018_I2C_TIMEOUT);
 
 out:
   return (mcp23018_status);

+ 1 - 3
keyboards/ymdk/sp64/sp64.h

@@ -23,9 +23,7 @@
 # include "i2c_master.h"
 
 // I2C aliases and register addresses (see "mcp23018.md")
-# define I2C_ADDR        0b0100000
-# define I2C_ADDR_WRITE  ( (I2C_ADDR<<1) | I2C_WRITE )
-# define I2C_ADDR_READ   ( (I2C_ADDR<<1) | I2C_READ  )
+# define I2C_ADDR        (0b0100000<<1)
 # define IODIRA          0x00            // i/o direction register
 # define IODIRB          0x01
 # define GPPUA           0x0C            // GPIO pull-up resistor register

+ 25 - 6
platforms/avr/drivers/i2c_master.c

@@ -24,6 +24,7 @@
 #include "timer.h"
 #include "wait.h"
 #include "util.h"
+#include "progmem.h"
 
 #ifndef F_SCL
 #    define F_SCL 400000UL // SCL frequency
@@ -38,7 +39,7 @@
 
 #define TWBR_val (((F_CPU / F_SCL) - 16) / 2)
 
-void i2c_init(void) {
+__attribute__((weak)) void i2c_init(void) {
     TWSR = 0; /* no prescaler */
     TWBR = (uint8_t)TWBR_val;
 
@@ -94,7 +95,7 @@ static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) {
     return I2C_STATUS_SUCCESS;
 }
 
-i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
+__attribute__((always_inline)) static inline i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
     // Retry i2c_start_impl a bunch times in case the remote side has interrupts disabled.
     uint16_t     timeout_timer = timer_read();
     uint16_t     time_slice    = MAX(1, (timeout == (I2C_TIMEOUT_INFINITE)) ? 5 : (timeout / (I2C_START_RETRY_COUNT))); // if it's infinite, wait 1ms between attempts, otherwise split up the entire timeout into the number of retries
@@ -105,6 +106,11 @@ i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
     return status;
 }
 
+__attribute__((always_inline)) static inline void i2c_stop(void) {
+    // transmit STOP condition
+    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
+}
+
 i2c_status_t i2c_write(uint8_t data, uint16_t timeout) {
     // load data into data register
     TWDR = data;
@@ -167,6 +173,18 @@ i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length,
     return status;
 }
 
+i2c_status_t i2c_transmit_P(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) {
+    i2c_status_t status = i2c_start(address | I2C_ACTION_WRITE, timeout);
+
+    for (uint16_t i = 0; i < length && status >= 0; i++) {
+        status = i2c_write(pgm_read_byte((const char*)data++), timeout);
+    }
+
+    i2c_stop();
+
+    return status;
+}
+
 i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
     i2c_status_t status = i2c_start(address | I2C_ACTION_READ, timeout);
 
@@ -293,7 +311,8 @@ error:
     return (status < 0) ? status : I2C_STATUS_SUCCESS;
 }
 
-void i2c_stop(void) {
-    // transmit STOP condition
-    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
-}
+__attribute__((weak)) i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout) {
+    i2c_status_t status = i2c_start(address, timeout);
+    i2c_stop();
+    return status;
+}

+ 2 - 5
platforms/avr/drivers/i2c_master.h

@@ -41,14 +41,11 @@ typedef int16_t i2c_status_t;
 #define I2C_TIMEOUT_INFINITE (0xFFFF)
 
 void         i2c_init(void);
-i2c_status_t i2c_start(uint8_t address, uint16_t timeout);
-i2c_status_t i2c_write(uint8_t data, uint16_t timeout);
-int16_t      i2c_read_ack(uint16_t timeout);
-int16_t      i2c_read_nack(uint16_t timeout);
 i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
+i2c_status_t i2c_transmit_P(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_write_register(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_write_register16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_read_register(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_read_register16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
-void         i2c_stop(void);
+i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout);

+ 15 - 24
platforms/chibios/drivers/i2c_master.c

@@ -1,5 +1,6 @@
 /* Copyright 2018 Jack Humbert
  * Copyright 2018 Yiancar
+ * Copyright 2023 customMK
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -90,8 +91,6 @@
 #    endif
 #endif
 
-static uint8_t i2c_address;
-
 static const I2CConfig i2cconfig = {
 #if defined(USE_I2CV1_CONTRIB)
     I2C1_CLOCK_SPEED,
@@ -125,7 +124,7 @@ static i2c_status_t i2c_epilogue(const msg_t status) {
     // From ChibiOS HAL: "After a timeout the driver must be stopped and
     // restarted because the bus is in an uncertain state." We also issue that
     // hard stop in case of any error.
-    i2c_stop();
+    i2cStop(&I2C_DRIVER);
 
     return status == MSG_TIMEOUT ? I2C_STATUS_TIMEOUT : I2C_STATUS_ERROR;
 }
@@ -150,28 +149,19 @@ __attribute__((weak)) void i2c_init(void) {
     }
 }
 
-i2c_status_t i2c_start(uint8_t address) {
-    i2c_address = address;
-    i2cStart(&I2C_DRIVER, &i2cconfig);
-    return I2C_STATUS_SUCCESS;
-}
-
 i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) {
-    i2c_address = address;
     i2cStart(&I2C_DRIVER, &i2cconfig);
-    msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, TIME_MS2I(timeout));
+    msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (address >> 1), data, length, 0, 0, TIME_MS2I(timeout));
     return i2c_epilogue(status);
 }
 
 i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
-    i2c_address = address;
     i2cStart(&I2C_DRIVER, &i2cconfig);
-    msg_t status = i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, TIME_MS2I(timeout));
+    msg_t status = i2cMasterReceiveTimeout(&I2C_DRIVER, (address >> 1), data, length, TIME_MS2I(timeout));
     return i2c_epilogue(status);
 }
 
 i2c_status_t i2c_write_register(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
-    i2c_address = devaddr;
     i2cStart(&I2C_DRIVER, &i2cconfig);
 
     uint8_t complete_packet[length + 1];
@@ -180,12 +170,11 @@ i2c_status_t i2c_write_register(uint8_t devaddr, uint8_t regaddr, const uint8_t*
     }
     complete_packet[0] = regaddr;
 
-    msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, TIME_MS2I(timeout));
+    msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (devaddr >> 1), complete_packet, length + 1, 0, 0, TIME_MS2I(timeout));
     return i2c_epilogue(status);
 }
 
 i2c_status_t i2c_write_register16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
-    i2c_address = devaddr;
     i2cStart(&I2C_DRIVER, &i2cconfig);
 
     uint8_t complete_packet[length + 2];
@@ -195,25 +184,27 @@ i2c_status_t i2c_write_register16(uint8_t devaddr, uint16_t regaddr, const uint8
     complete_packet[0] = regaddr >> 8;
     complete_packet[1] = regaddr & 0xFF;
 
-    msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 2, 0, 0, TIME_MS2I(timeout));
+    msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (devaddr >> 1), complete_packet, length + 2, 0, 0, TIME_MS2I(timeout));
     return i2c_epilogue(status);
 }
 
 i2c_status_t i2c_read_register(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
-    i2c_address = devaddr;
     i2cStart(&I2C_DRIVER, &i2cconfig);
-    msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), &regaddr, 1, data, length, TIME_MS2I(timeout));
+    msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (devaddr >> 1), &regaddr, 1, data, length, TIME_MS2I(timeout));
     return i2c_epilogue(status);
 }
 
 i2c_status_t i2c_read_register16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
-    i2c_address = devaddr;
     i2cStart(&I2C_DRIVER, &i2cconfig);
     uint8_t register_packet[2] = {regaddr >> 8, regaddr & 0xFF};
-    msg_t   status             = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), register_packet, 2, data, length, TIME_MS2I(timeout));
+    msg_t   status             = i2cMasterTransmitTimeout(&I2C_DRIVER, (devaddr >> 1), register_packet, 2, data, length, TIME_MS2I(timeout));
     return i2c_epilogue(status);
 }
 
-void i2c_stop(void) {
-    i2cStop(&I2C_DRIVER);
-}
+__attribute__((weak)) i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout) {
+    // ChibiOS does not provide low level enough control to check for an ack.
+    // Best effort instead tries reading register 0 which will either succeed or timeout.
+    // This approach may produce false negative results for I2C devices that do not respond to a register 0 read request.
+    uint8_t data = 0;
+    return i2c_readReg(address, 0, &data, sizeof(data), timeout);
+}

+ 1 - 2
platforms/chibios/drivers/i2c_master.h

@@ -40,11 +40,10 @@ typedef int16_t i2c_status_t;
 #define I2C_STATUS_TIMEOUT (-2)
 
 void         i2c_init(void);
-i2c_status_t i2c_start(uint8_t address);
 i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_write_register(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_write_register16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_read_register(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_read_register16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
-void         i2c_stop(void);
+i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout);