[PATCH RTEMS v2 1/1] bsps/beagle: Refactored i2c driver
G S Niteesh Babu
niteesh.gs at gmail.com
Sat Apr 10 19:15:27 UTC 2021
Refactored the i2c driver to parse register values from the device
tree rather than hardcoding them. But still the clocks have to
initialized manually.
---
bsps/arm/beagle/i2c/bbb-i2c.c | 122 ++++++++++++++++++------------
bsps/arm/beagle/include/bsp.h | 4 +
bsps/arm/beagle/include/bsp/i2c.h | 32 +-------
bsps/arm/beagle/start/bspstart.c | 51 +++++++++----
4 files changed, 114 insertions(+), 95 deletions(-)
diff --git a/bsps/arm/beagle/i2c/bbb-i2c.c b/bsps/arm/beagle/i2c/bbb-i2c.c
index b2a7cf814d..b842fd820a 100644
--- a/bsps/arm/beagle/i2c/bbb-i2c.c
+++ b/bsps/arm/beagle/i2c/bbb-i2c.c
@@ -25,6 +25,7 @@
#include <bsp/bbb-gpio.h>
#include <rtems/score/assert.h>
#include <dev/i2c/i2c.h>
+#include <ofw/ofw.h>
typedef struct bbb_i2c_bus {
i2c_bus base;
@@ -34,12 +35,6 @@ typedef struct bbb_i2c_bus {
volatile uint32_t *i2c_clkctrl;
volatile uint32_t *clkstctrl;
} clkregs;
- struct {
- volatile uint32_t *conf_sda;
- uint32_t mmode_sda;
- volatile uint32_t *conf_scl;
- uint32_t mmode_scl;
- } pinregs;
rtems_id task_id;
rtems_vector_number irq;
i2c_msg *buffer;
@@ -56,19 +51,22 @@ typedef struct bbb_i2c_bus {
#else
#define debug_print(fmt, args...)
#endif
+/*
+ * Here we assume the number of i2c nodes
+ * will be less than 100.
+ */
+#define PATH_LEN (strlen("/dev/i2c-xx") + 1)
static int am335x_i2c_fill_registers(
bbb_i2c_bus *bus,
- uintptr_t register_base
+ uint32_t base
)
{
- /* FIXME: The pin handling should be replaced by a proper pin handling during
- * initialization. This one is heavily board specific. */
-#if ! IS_AM335X
- printk ("The I2C driver currently only works on Beagle Bone. Please add your pin configs.");
- return EINVAL;
-#endif
- bus->regs = (volatile bbb_i2c_regs *) register_base;
+ bus->regs = (volatile bbb_i2c_regs *)base;
+
+ /*
+ * FIXME: Implement a clock driver to parse and setup clocks
+ */
switch ((intptr_t) bus->regs) {
case AM335X_I2C0_BASE:
bus->clkregs.ctrl_clkctrl = ®(AM335X_SOC_CM_WKUP_REGS +
@@ -77,10 +75,6 @@ static int am335x_i2c_fill_registers(
AM335X_CM_WKUP_I2C0_CLKCTRL);
bus->clkregs.clkstctrl = ®(AM335X_SOC_CM_WKUP_REGS +
AM335X_CM_WKUP_CLKSTCTRL);
- bus->pinregs.conf_sda = ®(AM335X_PADCONF_BASE + AM335X_CONF_I2C0_SDA);
- bus->pinregs.mmode_sda = 0;
- bus->pinregs.conf_scl = ®(AM335X_PADCONF_BASE + AM335X_CONF_I2C0_SCL);
- bus->pinregs.mmode_scl = 0;
break;
case AM335X_I2C1_BASE:
bus->clkregs.ctrl_clkctrl = ®(AM335X_SOC_CM_WKUP_REGS +
@@ -88,10 +82,6 @@ static int am335x_i2c_fill_registers(
bus->clkregs.i2c_clkctrl = ®(AM335X_CM_PER_ADDR +
AM335X_CM_PER_I2C1_CLKCTRL);
bus->clkregs.clkstctrl = NULL;
- bus->pinregs.conf_sda = ®(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_D1);
- bus->pinregs.mmode_sda = 2;
- bus->pinregs.conf_scl = ®(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_CS0);
- bus->pinregs.mmode_scl = 2;
break;
case AM335X_I2C2_BASE:
bus->clkregs.ctrl_clkctrl = ®(AM335X_SOC_CM_WKUP_REGS +
@@ -99,24 +89,12 @@ static int am335x_i2c_fill_registers(
bus->clkregs.i2c_clkctrl = ®(AM335X_CM_PER_ADDR +
AM335X_CM_PER_I2C2_CLKCTRL);
bus->clkregs.clkstctrl = NULL;
- bus->pinregs.conf_sda = ®(AM335X_PADCONF_BASE + AM335X_CONF_UART1_CTSN);
- bus->pinregs.mmode_sda = 3;
- bus->pinregs.conf_scl = ®(AM335X_PADCONF_BASE + AM335X_CONF_UART1_RTSN);
- bus->pinregs.mmode_scl = 3;
break;
default:
return EINVAL;
}
- return 0;
-}
-
-static void am335x_i2c_pinmux( bbb_i2c_bus *bus )
-{
- *bus->pinregs.conf_sda =
- ( BBB_RXACTIVE | BBB_SLEWCTRL | bus->pinregs.mmode_sda);
- *bus->pinregs.conf_scl =
- ( BBB_RXACTIVE | BBB_SLEWCTRL | bus->pinregs.mmode_scl);
+ return 0;
}
static void am335x_i2c_module_clk_enable( bbb_i2c_bus *bus )
@@ -453,36 +431,34 @@ static void am335x_i2c_destroy( i2c_bus *base )
i2c_bus_destroy_and_free( &bus->base );
}
-int am335x_i2c_bus_register(
- const char *bus_path,
- uintptr_t register_base,
- uint32_t input_clock,
- rtems_vector_number irq
+static int am335x_i2c_bus_register(
+ uint32_t reg_base,
+ rtems_vector_number irq,
+ const char *bus_path
)
{
- bbb_i2c_bus *bus;
- rtems_status_code sc;
- int err;
-
- (void) input_clock; /* FIXME: Unused. Left for compatibility. */
+ bbb_i2c_bus *bus;
+ rtems_status_code sc;
+ int err;
bus = (bbb_i2c_bus *) i2c_bus_alloc_and_init( sizeof( *bus ) );
+ bus->irq = irq;
if ( bus == NULL ) {
return -1;
}
- bus->irq = irq;
-
- err = am335x_i2c_fill_registers(bus, register_base);
+ err = am335x_i2c_fill_registers(bus, reg_base);
if (err != 0) {
+ printf("i2c: invalid register base\n");
( *bus->base.destroy )( &bus->base );
rtems_set_errno_and_return_minus_one( err );
}
- am335x_i2c_module_clk_enable(bus);
- am335x_i2c_pinmux( bus );
+
+ am335x_i2c_module_clk_enable( bus );
err = am335x_i2c_reset( bus );
if (err != 0) {
+ printk("i2c: reset timed out\n");
( *bus->base.destroy )( &bus->base );
rtems_set_errno_and_return_minus_one( err );
}
@@ -506,3 +482,49 @@ int am335x_i2c_bus_register(
return i2c_bus_register( &bus->base, bus_path );
}
+
+void beagle_i2c_init(phandle_t node)
+{
+ int err;
+ int unit;
+ char bus_path[PATH_LEN];
+ rtems_vector_number irq;
+ rtems_ofw_memory_area reg;
+
+ if (!rtems_ofw_is_node_compatible(node, "ti,omap4-i2c"))
+ /* We cannot handle this device */
+ return ;
+
+ unit = beagle_get_node_unit(node);
+ if (unit < 0 || unit >= 100) {
+ printk("i2c: cannot register device, node unit number invalid.");
+ printk(" Valid range is 0 <= unit < 100\n");
+ return ;
+ }
+
+ err = rtems_ofw_get_prop(node, "rtems,path", (void *)bus_path, PATH_LEN);
+ if (err < 0) {
+ /* No path was provided in the device tree therefore use the default one */
+ snprintf(bus_path, PATH_LEN, "/dev/i2c-%d", unit);
+ } else if (err >= PATH_LEN) {
+ /* Null terminate the string */
+ bus_path[PATH_LEN - 1] = 0;
+ printk("i2c: bus path too long, trucated %s\n", bus_path);
+ }
+
+ err = rtems_ofw_get_interrupts(node, &irq, sizeof(irq));
+ if (err < 1) {
+ printk("i2c: cannot register device, irq missing in device tree\n");
+ return ;
+ }
+
+ err = rtems_ofw_get_reg(node, ®, sizeof(reg));
+ if (err <= 0) {
+ printk("i2c: cannot register device, regs field missing\n");
+ return ;
+ }
+
+ err = am335x_i2c_bus_register(reg.start, irq, bus_path);
+ if (err != 0)
+ printk("i2c: Could not register device (%d)\n", err);
+}
diff --git a/bsps/arm/beagle/include/bsp.h b/bsps/arm/beagle/include/bsp.h
index cb415fda89..80a9cc291d 100644
--- a/bsps/arm/beagle/include/bsp.h
+++ b/bsps/arm/beagle/include/bsp.h
@@ -49,6 +49,8 @@
#include <libcpu/omap3.h>
#include <libcpu/am335x.h>
+#include <ofw/ofw.h>
+
#define BSP_FEATURE_IRQ_EXTENSION
/* UART base clock frequency */
@@ -68,6 +70,8 @@
#define udelay(u) rtems_task_wake_after(1 + ((u)/rtems_configuration_get_microseconds_per_tick()))
+int beagle_get_node_unit(phandle_t node);
+
/* Write a uint32_t value to a memory address. */
static inline void
write32(uint32_t address, uint32_t value)
diff --git a/bsps/arm/beagle/include/bsp/i2c.h b/bsps/arm/beagle/include/bsp/i2c.h
index 60f71194bf..d80b376fa0 100644
--- a/bsps/arm/beagle/include/bsp/i2c.h
+++ b/bsps/arm/beagle/include/bsp/i2c.h
@@ -26,6 +26,7 @@
#include <rtems.h>
#include <bsp.h>
#include <dev/i2c/i2c.h>
+#include <ofw/ofw.h>
#ifdef __cplusplus
extern "C" {
@@ -38,10 +39,6 @@ extern "C" {
#define BBB_I2C_1_BUS_PATH "/dev/i2c-1"
#define BBB_I2C_2_BUS_PATH "/dev/i2c-2"
-#define BBB_I2C0_IRQ 70
-#define BBB_I2C1_IRQ 71
-#define BBB_I2C2_IRQ 30
-
typedef enum {
I2C0,
I2C1,
@@ -87,32 +84,7 @@ typedef struct i2c_regs {
uint32_t BBB_I2C_SBLOCK;
} bbb_i2c_regs;
-int am335x_i2c_bus_register(
- const char *bus_path,
- uintptr_t register_base,
- uint32_t input_clock, /* FIXME: Unused. Left for compatibility. */
- rtems_vector_number irq
-);
-
-static inline int bbb_register_i2c_1( void )
-{
- return am335x_i2c_bus_register(
- BBB_I2C_1_BUS_PATH,
- AM335X_I2C1_BASE,
- I2C_BUS_CLOCK_DEFAULT,
- BBB_I2C1_IRQ
- );
-}
-
-static inline int bbb_register_i2c_2( void )
-{
- return am335x_i2c_bus_register(
- BBB_I2C_2_BUS_PATH,
- AM335X_I2C2_BASE,
- I2C_BUS_CLOCK_DEFAULT,
- BBB_I2C2_IRQ
- );
-}
+void beagle_i2c_init( phandle_t node );
#ifdef __cplusplus
}
diff --git a/bsps/arm/beagle/start/bspstart.c b/bsps/arm/beagle/start/bspstart.c
index a0736294c9..cb488626f1 100644
--- a/bsps/arm/beagle/start/bspstart.c
+++ b/bsps/arm/beagle/start/bspstart.c
@@ -22,6 +22,10 @@
#include "bsp-soc-detect.h"
#include <arm/ti/ti_pinmux.h>
#include <ofw/ofw.h>
+#include <bsp/i2c.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
#include "bspdebug.h"
@@ -70,6 +74,7 @@ static void traverse_fdt_nodes( phandle_t node )
* Put all driver initialization functions here
*/
beagle_pinmux_init(node);
+ beagle_i2c_init(node);
}
}
@@ -80,24 +85,40 @@ static void bbb_drivers_initialize(void)
traverse_fdt_nodes(node);
}
-static void bbb_i2c_0_initialize(void)
+int beagle_get_node_unit(phandle_t node)
{
- int err;
-
- err = am335x_i2c_bus_register(BBB_I2C_0_BUS_PATH,
- AM335X_I2C0_BASE,
- I2C_BUS_CLOCK_DEFAULT,
- BBB_I2C0_IRQ);
- if (err != 0) {
- printk("rtems i2c-0: Device could not be registered (%d)", err);
+ char name[30];
+ char prop[30];
+ char prop_val[30];
+ static int unit;
+ phandle_t aliases;
+ int rv;
+ int i;
+
+ rv = rtems_ofw_get_prop(node, "name", name, sizeof(name));
+ if (rv <= 0)
+ return unit++;
+
+ aliases = rtems_ofw_find_device("/aliases");
+
+ rv = rtems_ofw_next_prop(aliases, NULL, &prop[0], sizeof(prop));
+
+ while (rv > 0) {
+ rv = rtems_ofw_get_prop(aliases, prop, prop_val, sizeof(prop_val));
+
+ if (strstr(prop_val, name) != NULL) {
+ for (i = strlen(prop) - 1; i >= 0; i--) {
+ if (!isdigit(prop[i]))
+ break;
+ }
+
+ return strtol(&prop[i + 1], NULL, 10);
+ }
+ rv = rtems_ofw_next_prop(aliases, prop, prop, sizeof(prop));
}
-}
-RTEMS_SYSINIT_ITEM(
- bbb_i2c_0_initialize,
- RTEMS_SYSINIT_LAST,
- RTEMS_SYSINIT_ORDER_LAST_BUT_5
-);
+ return unit++;
+}
RTEMS_SYSINIT_ITEM(
bbb_drivers_initialize,
--
2.17.1
More information about the devel
mailing list