Skip to content

Commit

Permalink
bsps/beagle: Refactored i2c driver
Browse files Browse the repository at this point in the history
  • Loading branch information
gs-niteesh committed Aug 27, 2020
1 parent 0ace491 commit 1dde9fc
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 160 deletions.
166 changes: 51 additions & 115 deletions bsps/arm/beagle/i2c/bbb-i2c.c
Expand Up @@ -25,21 +25,12 @@
#include <bsp/bbb-gpio.h>
#include <rtems/score/assert.h>
#include <dev/i2c/i2c.h>
#include <arm/ti/ti_hwmods.h>
#include <ofw/ofw.h>

typedef struct bbb_i2c_bus {
i2c_bus base;
volatile bbb_i2c_regs *regs;
struct {
volatile uint32_t *ctrl_clkctrl;
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;
Expand All @@ -56,109 +47,35 @@ 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")

static int am335x_i2c_fill_registers(
bbb_i2c_bus *bus,
uintptr_t register_base
phandle_t node
)
{
/* 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;
switch ((intptr_t) bus->regs) {
case AM335X_I2C0_BASE:
bus->clkregs.ctrl_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
AM335X_CM_WKUP_CONTROL_CLKCTRL);
bus->clkregs.i2c_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
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 +
AM335X_CM_WKUP_CONTROL_CLKCTRL);
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 +
AM335X_CM_WKUP_CONTROL_CLKCTRL);
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:
ssize_t rv;
rtems_ofw_memory_area reg;

rv = rtems_ofw_get_reg(node, &reg, sizeof(reg));
if (rv <= 0)
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->regs = (volatile bbb_i2c_regs *)reg.start;

*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 )
static void am335x_i2c_module_clk_enable( phandle_t node )
{
volatile uint32_t *ctrl_clkctrl = bus->clkregs.ctrl_clkctrl;
volatile uint32_t *i2c_clkctrl = bus->clkregs.i2c_clkctrl;
volatile uint32_t *clkstctrl = bus->clkregs.clkstctrl;

/* Writing to MODULEMODE field of AM335X_CM_WKUP_I2C0_CLKCTRL register. */
*i2c_clkctrl |= AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE;

/* Waiting for MODULEMODE field to reflect the written value. */
while ( AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE !=
( *i2c_clkctrl & AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE ) )
{ /* busy wait */ }

/*
* Waiting for IDLEST field in AM335X_CM_WKUP_CONTROL_CLKCTRL
* register to attain desired value.
*/
while ( ( AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST_FUNC <<
AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST_SHIFT ) !=
( *ctrl_clkctrl & AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST ) )
{ /* busy wait */ }

if ( clkstctrl != NULL ) {
/*
* Waiting for CLKACTIVITY_I2C0_GFCLK field in AM335X_CM_WKUP_CLKSTCTRL
* register to attain desired value.
*/
while ( AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK !=
( *clkstctrl & AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK ) )
{ /* busy wait */ }
}
clk_ident_t i2c_clk;

/*
* Waiting for IDLEST field in AM335X_CM_WKUP_I2C0_CLKCTRL register to attain
* desired value.
*/
while ( ( AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST_FUNC <<
AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST_SHIFT ) !=
( *i2c_clkctrl & AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST ) ) ;
i2c_clk = ti_hwmods_get_clock(node);
ti_prcm_clk_enable(i2c_clk);
}

static int am335x_i2c_set_clock(
Expand Down Expand Up @@ -453,34 +370,41 @@ 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(
phandle_t node
)
{
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;
rtems_vector_number irq;
int err;
int unit;
char bus_path[PATH_LEN];

bus = (bbb_i2c_bus *) i2c_bus_alloc_and_init( sizeof( *bus ) );

if ( bus == NULL ) {
return -1;
}

unit = beagle_get_node_unit(node);

snprintf(bus_path, PATH_LEN, "/dev/i2c-%d", unit);

err = rtems_ofw_get_interrupts(node, &irq, sizeof(irq));
if (err < 1) {
( *bus->base.destroy )( &bus->base );
rtems_set_errno_and_return_minus_one( err );
}
bus->irq = irq;

err = am335x_i2c_fill_registers(bus, register_base);
err = am335x_i2c_fill_registers(bus, node);
if (err != 0) {
( *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(node);
err = am335x_i2c_reset( bus );
if (err != 0) {
( *bus->base.destroy )( &bus->base );
Expand All @@ -506,3 +430,15 @@ int am335x_i2c_bus_register(

return i2c_bus_register( &bus->base, bus_path );
}

void beagle_i2c_init(phandle_t node)
{
int rv;

if (!rtems_ofw_is_node_compatible(node, "ti,omap4-i2c"))
return ;

rv = am335x_i2c_bus_register(node);
if (rv != 0)
printk("i2c: Could not register device (%d)\n", rv);
}
4 changes: 4 additions & 0 deletions bsps/arm/beagle/include/bsp.h
Expand Up @@ -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 */
Expand All @@ -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)
Expand Down
32 changes: 2 additions & 30 deletions bsps/arm/beagle/include/bsp/i2c.h
Expand Up @@ -26,6 +26,7 @@
#include <rtems.h>
#include <bsp.h>
#include <dev/i2c/i2c.h>
#include <ofw/ofw.h>

#ifdef __cplusplus
extern "C" {
Expand All @@ -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,
Expand Down Expand Up @@ -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
}
Expand Down
54 changes: 39 additions & 15 deletions bsps/arm/beagle/start/bspstart.c
Expand Up @@ -24,10 +24,17 @@
#include <arm/ti/ti_pinmux.h>
#include <arm/ti/ti_prcm.h>
#include <arm/ti/ti_scm.h>
#include <rtems.h>
#include <ofw/ofw.h>
#include <bsp/i2c.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include "bspdebug.h"

#define MIN(l,r) ((l) < (r) ? (l) : (r))

void bsp_start(void)
{
const char *type;
Expand Down Expand Up @@ -75,6 +82,7 @@ static void traverse_fdt_nodes( phandle_t node )
beagle_pinmux_init(node);
am335x_prcm_init(node);
beagle_scm_init(node);
beagle_i2c_init(node);
}
}

Expand All @@ -85,24 +93,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,
Expand Down

0 comments on commit 1dde9fc

Please sign in to comment.