 +#include <linux/errno.h>
 +#include <linux/io.h>
 +
-+#define SCRATCH_REG_OFF		0x04
-+#define SCRATCH_REG_VALUE	0x12345678
-+#define SCRATCH_LE		0x00000012
-+#define SCRATCH_BE		0x12000000
++#define SCRATCH_REG_OFF         0x04
++#define SCRATCH_REG_SIZE        4
++#define SCRATCH_REG_VALUE       0x12345678
++#define SCRATCH_TEST_VALUE      0xdeadbeef
++
++int accessors_ok = 0;
 +
 +/*
-+ * Pointers for accessor functions
-+ *
-+ * note: or1k and vexriscv kernels use different CONFIG_GENERIC_IOMAP
-+ *	setting and it changes the definition of io{read,write}32
-+ *	functions so we are checking here to use correct definition
-+ */
-+#ifndef CONFIG_GENERIC_IOMAP
-+unsigned int (*litex_read_reg)(const volatile void __iomem *addr) = NULL;
-+void (*litex_write_reg)(u32 val, volatile void __iomem *addr) = NULL;
-+#else
-+unsigned int (*litex_read_reg)(void __iomem *addr) = NULL;
-+void (*litex_write_reg)(u32 val, void __iomem *addr) = NULL;
-+#endif
-+
-+/*
-+ * check if accessors are ready to use
++ * Check if accessors are safe to be used by other drivers
 + * returns true if yes - false if not
 + */
 +int litex_check_accessors(void)
 +{
-+	if (litex_read_reg == NULL || litex_write_reg == NULL)
-+		return 0;
-+	return 1;
++	return accessors_ok;
 +}
 +
 +struct litex_soc_ctrl_device {
 +	void __iomem *base;
 +};
 +
-+/* Check byte order and set correct accessors */
-+static int litex_soc_ctrl_check_endianness(void __iomem *reg_addr)
++/* Check LiteX CSR read/write access */
++static int litex_check_csr_access(void __iomem *reg_addr)
 +{
 +	u32 reg;
-+	u8 le_flag = -1;
-+
-+	/* Read first part of litex CSR with Little Endian function */
-+	reg = ioread32(reg_addr + SCRATCH_REG_OFF);
-+
-+	if (reg == SCRATCH_LE) {
-+		le_flag = 1;
-+		litex_read_reg = ioread32;
-+		litex_write_reg = iowrite32;
-+	} else if (reg == SCRATCH_BE) {
-+		le_flag = 0;
-+		litex_read_reg = ioread32be;
-+		litex_write_reg = iowrite32be;
-+	} else {
-+		panic("Endianness detection failure! scratch: 0x%x", reg);
++
++	reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);
++
++	if (reg != SCRATCH_REG_VALUE) {
++		panic("Scratch register read error! Expected: 0x%x but got: 0x%x",
++							SCRATCH_REG_VALUE, reg);
 +		return -EINVAL;
 +	}
-+	/* Double check - this time whole CSR */
-+	reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, 4);
-+	if (reg != SCRATCH_REG_VALUE) {
-+		panic("Endianness detection failure! scratch: 0x%x should be: 0x%x",
-+							reg, SCRATCH_REG_VALUE);
++
++	litex_set_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE, SCRATCH_TEST_VALUE);
++	reg = litex_get_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE);
++
++	if (reg != SCRATCH_TEST_VALUE) {
++		panic("Scratch register write error! Expected: 0x%x but got: 0x%x",
++							SCRATCH_TEST_VALUE, reg);
 +		return -EINVAL;
 +	}
 +
-+	if (le_flag)
-+		pr_info("LiteX CSR access configured: Little Endian");
-+	else
-+		pr_info("LiteX CSR access configured: Big Endian");
++	/* restore original value of the SCRATCH register */
++	litex_set_reg(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_SIZE, SCRATCH_REG_VALUE);
++
++	/* Set flag for other drivers */
++	accessors_ok = 1;
++	pr_info("LiteX SoC Controller driver initialized");
 +
 +	return 0;
 +}

index 000000000000..ddae454b52e5
--- /dev/null
+++ b/include/linux/litex.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_LITEX_H
+#define _LINUX_LITEX_H

+#define LITEX_SUBREG_SIZE          0x1
+#define LITEX_SUBREG_SIZE_BIT      (LITEX_SUBREG_SIZE * 8)
+
+// function implemented in
+// drivers/soc/litex/litex_soc_controller.c
+// to check if accessors are safe to be used
+// returns true if yes - false if not
+//
+// Important: all drivers that use functions from this header
+// must check at the beginning of their probe()
+// if LiteX SoC Controller driver has checked read and write to CSRs
+// and then return -EPROBE_DEFER when false
+//
+// example:
+// if (!litex_check_accessors())
+//     return -EPROBE_DEFER;
+int litex_check_accessors(void);
+
+static inline u32 read_pointer_with_barrier(const volatile void __iomem *addr)
+{
+    u32 val;
+    __io_br();
+    val = *(const volatile u32 __force *)addr;
+    __io_ar();
+    return val;
+}
+
+static inline void write_pointer_with_barrier(volatile void __iomem *addr, u32 val)
+{
+    __io_br();
+    *(volatile u32 __force *)addr = val;
+    __io_ar();
+}
+
+// Helper functions for manipulating LiteX registers
+static inline void litex_set_reg(void __iomem *reg, u32 reg_size, u32 val)
