summaryrefslogtreecommitdiffstats
path: root/bsps/arm
diff options
context:
space:
mode:
authorG S Niteesh Babu <niteesh.gs@gmail.com>2021-04-11 00:45:27 +0530
committerChristian Mauderer <oss@c-mauderer.de>2021-04-22 18:43:35 +0200
commitd75b29d95e71f04a71e375750c1a02b3bacd533f (patch)
tree8de04e2f1d63559badc3410acd84b4f814396585 /bsps/arm
parentrtems: Mention timer server fire directives (diff)
downloadrtems-d75b29d95e71f04a71e375750c1a02b3bacd533f.tar.bz2
bsps/beagle: Refactored i2c driver
Refactored the i2c driver to parse register values from the device tree rather than hardcoding them. But still the clocks have to initialized manually.
Diffstat (limited to 'bsps/arm')
-rw-r--r--bsps/arm/beagle/i2c/bbb-i2c.c122
-rw-r--r--bsps/arm/beagle/include/bsp.h4
-rw-r--r--bsps/arm/beagle/include/bsp/i2c.h32
-rw-r--r--bsps/arm/beagle/start/bspstart.c51
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 = &REG(AM335X_SOC_CM_WKUP_REGS +
@@ -77,10 +75,6 @@ static int am335x_i2c_fill_registers(
AM335X_CM_WKUP_I2C0_CLKCTRL);
bus->clkregs.clkstctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
AM335X_CM_WKUP_CLKSTCTRL);
- bus->pinregs.conf_sda = &REG(AM335X_PADCONF_BASE + AM335X_CONF_I2C0_SDA);
- bus->pinregs.mmode_sda = 0;
- bus->pinregs.conf_scl = &REG(AM335X_PADCONF_BASE + AM335X_CONF_I2C0_SCL);
- bus->pinregs.mmode_scl = 0;
break;
case AM335X_I2C1_BASE:
bus->clkregs.ctrl_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
@@ -88,10 +82,6 @@ static int am335x_i2c_fill_registers(
bus->clkregs.i2c_clkctrl = &REG(AM335X_CM_PER_ADDR +
AM335X_CM_PER_I2C1_CLKCTRL);
bus->clkregs.clkstctrl = NULL;
- bus->pinregs.conf_sda = &REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_D1);
- bus->pinregs.mmode_sda = 2;
- bus->pinregs.conf_scl = &REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_CS0);
- bus->pinregs.mmode_scl = 2;
break;
case AM335X_I2C2_BASE:
bus->clkregs.ctrl_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
@@ -99,24 +89,12 @@ static int am335x_i2c_fill_registers(
bus->clkregs.i2c_clkctrl = &REG(AM335X_CM_PER_ADDR +
AM335X_CM_PER_I2C2_CLKCTRL);
bus->clkregs.clkstctrl = NULL;
- bus->pinregs.conf_sda = &REG(AM335X_PADCONF_BASE + AM335X_CONF_UART1_CTSN);
- bus->pinregs.mmode_sda = 3;
- bus->pinregs.conf_scl = &REG(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, &reg, 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,