diff --git a/libraries/Wire/examples/register_manipulations/register_manipulations.ino b/libraries/Wire/examples/register_manipulations/register_manipulations.ino
new file mode 100644
index 000000000..85097c991
--- /dev/null
+++ b/libraries/Wire/examples/register_manipulations/register_manipulations.ino
@@ -0,0 +1,78 @@
+/*
+ * Wire_register_manipulations
+ * 
+ * This is example showing how to read and write to registers of I2C devices.
+ * 
+ * The example shows:
+ * 1. Writing byte to register
+ * 2. Reading byte from register (both blocking and non-blocking)
+ * 3. Writing byte to register with verification
+ * 4. Writing data block to registers (useful for FIFO buffers)
+ * 5. Reading data block from registers (useful for FIFO buffers)
+ * 
+ * Example is written by Ivan Stefanov on 10 Sep 2023
+ */
+
+#include <Wire.h>
+
+// Demo is made for USB Type-C port controller IC FUSB302B
+#define FUSB302_ADDR    (0x22) // FUSB302B I2C address
+#define FUSB302_REG_R   (0x01) // FUSB302B I2C register read-only
+#define FUSB302_REG_RW  (0x02) // FUSB302B I2C register read/write
+
+void setup() {
+  Wire.begin();
+  Wire.setClock(I2C_FAST_SPEED);
+  delay(100); // I2C device power-up delay
+
+  Serial.begin(115200);
+  Serial.println("Wire library register manipulation functions example");
+
+  uint8_t test = 0;
+  bool dev = false;
+
+  /* Write and read byte from register */
+  
+  // Write byte to device register
+  Wire.registerWrite(FUSB302_ADDR, FUSB302_REG_RW, 0x64);
+  Serial.print("Write to read/write register: ");
+  Serial.println(0x64, HEX);
+
+  // Read(blocking) byte from device register
+  test = Wire.registerRead(FUSB302_ADDR, FUSB302_REG_RW);
+  Serial.print("Read read/write register: ");
+  Serial.println((unsigned int)test, HEX);
+
+  // Write and verify byte to device register
+  dev = Wire.registerWriteVerify(FUSB302_ADDR, FUSB302_REG_R, 0xC8);
+  Serial.print("Write 0xC8 to read-only register > success: ");
+  Serial.println(dev);
+
+  // Read(non-blocking) byte from device register
+  test = Wire.registerRead(FUSB302_ADDR, FUSB302_REG_R, false);
+  Serial.print("Read read-only register: ");
+  Serial.println((unsigned int)test, HEX);
+
+  // Data to be written to register block
+  uint8_t arr[4] = {0}, dat[4] = {0x91, 0x64, 0xA4, 0x30};
+
+  /* Write and read 4 byte block */
+  
+  // write data starting from read-only register followed by 3 read/write registers
+  Wire.registerBlockWrite(FUSB302_ADDR, FUSB302_REG_R, dat, 4);
+  Serial.print("Block write data: {0x91, 0x64, 0xA4, 0x30}\n");
+
+  // read data and print to serial monitor
+  Wire.registerBlockRead(FUSB302_ADDR, FUSB302_REG_R, arr, sizeof(arr));
+  Serial.print("Block Read: ");
+  for (size_t cnt = 0 ; cnt < 4 ; cnt++) {
+    Serial.print((unsigned int)arr[cnt], HEX);
+    Serial.print(", ");
+  }
+  Serial.print("\n");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+
+}
diff --git a/libraries/Wire/keywords.txt b/libraries/Wire/keywords.txt
index ee1d0acc5..abe50c0c7 100644
--- a/libraries/Wire/keywords.txt
+++ b/libraries/Wire/keywords.txt
@@ -19,8 +19,17 @@ endTransmission	KEYWORD2
 requestFrom	KEYWORD2
 onReceive	KEYWORD2
 onRequest	KEYWORD2
+registerRead	KEYWORD2
+registerWrite	KEYWORD2
+registerWriteVerify	KEYWORD2
+registerBlockRead	KEYWORD2
+registerBlockWrite	KEYWORD2
 
 #######################################
 # Constants (LITERAL1)
 #######################################
-
+I2C_LOW_SPEED	LITERAL1
+I2C_STD_SPEED	LITERAL1
+I2C_FAST_SPEED	LITERAL1
+I2C_FAST_PLUS_SPEED	LITERAL1
+I2C_HIGH_SPEED	LITERAL1
diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties
index e19526e87..ae3d32df5 100644
--- a/libraries/Wire/library.properties
+++ b/libraries/Wire/library.properties
@@ -1,5 +1,5 @@
 name=Wire
-version=1.0
+version=1.1
 author=Arduino
 maintainer=Arduino <info@arduino.cc>
 sentence=This library allows you to communicate with I2C and Two Wire Interface devices.
diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp
index 001d924df..7928c7674 100644
--- a/libraries/Wire/src/Wire.cpp
+++ b/libraries/Wire/src/Wire.cpp
@@ -372,6 +372,67 @@ void TwoWire::onRequest( void (*function)(void) )
   user_onRequest = function;
 }
 
+/* Register manipulation functions */
+
+// Reading byte from register (both blocking and non-blocking)
+uint8_t TwoWire::registerRead(uint8_t addr, uint8_t reg, const bool blocking) {
+  uint8_t val = 0;
+
+  beginTransmission(addr);
+  write(reg);
+  endTransmission(false);
+  requestFrom((int)addr, (int)1);
+  if (blocking == true) {
+    // blocking until data is received
+    while (available() == 0) {}
+  }
+  val = (uint8_t)read();
+  endTransmission(true);
+
+  return val;
+}
+
+// Writing byte to register
+void TwoWire::registerWrite(uint8_t addr, uint8_t reg, uint8_t val) {
+  beginTransmission(addr);
+  write(reg);
+  write(val);
+  endTransmission(true);
+}
+
+// Writing byte to register with verification
+bool TwoWire::registerWriteVerify(uint8_t addr, uint8_t reg, uint8_t val) {
+  registerWrite(addr, reg, val);
+  return (registerRead(addr, reg) == val) ? true : false;
+}
+
+// Reading data block from registers
+void TwoWire::registerBlockRead(uint8_t addr, uint8_t reg, uint8_t *data, size_t len, const bool blocking) {
+  beginTransmission(addr);
+  write(reg);
+  endTransmission(false);
+  requestFrom((int)addr, (int)len);
+  for (size_t cnt = 0 ; cnt < len ; cnt++) {
+    // If blocking mode is set check if the next byte is ready for reading after each byte
+    // If clock stretching support is not needed this check can be moved before the loop for better performance
+    // by running only once to check if device has started sending the data
+    if (blocking == true) {
+      // blocking until data is received
+      while (available() == 0) {}
+    }
+    data[cnt] = (uint8_t)read();
+  }
+  endTransmission(true);
+}
+
+// Writing data block to registers
+void TwoWire::registerBlockWrite(uint8_t addr, uint8_t reg, uint8_t *data, size_t len) {
+  beginTransmission(addr);
+  write(reg);
+  write(data, len);
+  endTransmission(true);
+}
+
 // Preinstantiate Objects //////////////////////////////////////////////////////
 
 TwoWire Wire = TwoWire();
diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h
index e70d72edb..895b70680 100644
--- a/libraries/Wire/src/Wire.h
+++ b/libraries/Wire/src/Wire.h
@@ -26,6 +26,13 @@
 #include <inttypes.h>
 #include "Stream.h"
 
+// I2C standard speeds
+#define I2C_LOW_SPEED       (10000)   // 10kHz
+#define I2C_STD_SPEED       (100000)  // 100kHz
+#define I2C_FAST_SPEED      (400000)  // 400kHz
+#define I2C_FAST_PLUS_SPEED (1000000) // 1MHz
+#define I2C_HIGH_SPEED      (3400000) // 3.4MHz
+
 #define BUFFER_LENGTH 32
 
 // WIRE_HAS_END means Wire has end()
@@ -75,6 +82,12 @@ class TwoWire : public Stream
     virtual void flush(void);
     void onReceive( void (*)(int) );
     void onRequest( void (*)(void) );
+    /* Register manipulation functions */
+    uint8_t registerRead(uint8_t addr, uint8_t reg, const bool blocking = true);
+    void registerWrite(uint8_t addr, uint8_t reg, uint8_t val);
+    bool registerWriteVerify(uint8_t addr, uint8_t reg, uint8_t val);
+    void registerBlockRead(uint8_t addr, uint8_t reg, uint8_t *data, size_t len, const bool blocking = true);
+    void registerBlockWrite(uint8_t addr, uint8_t reg, uint8_t *data, size_t len);
 
     inline size_t write(unsigned long n) { return write((uint8_t)n); }
     inline size_t write(long n) { return write((uint8_t)n); }