215 lines
4.9 KiB
C
215 lines
4.9 KiB
C
#undef DEBUG
|
|
|
|
#include <common.h>
|
|
#include <asm/gpio.h>
|
|
#include <asm/arch/mux.h>
|
|
|
|
#include "shield.h"
|
|
#include "board.h"
|
|
|
|
#define CAN_PORTS 2
|
|
|
|
#define NETBIRD_GPIO_RST_SHIELD_N GPIO_TO_PIN(0, 27)
|
|
#define NETBIRD_GPIO_LATCH GPIO_TO_PIN(0, 7)
|
|
#define NETBIRD_GPIO_MODE_0 GPIO_TO_PIN(1, 10)
|
|
#define NETBIRD_GPIO_MODE_1 GPIO_TO_PIN(1, 8)
|
|
|
|
|
|
static int shield_slot_initialized = 0;
|
|
|
|
|
|
static struct module_pin_mux can_shield_netbird_pin_mux_config[] = {
|
|
/* Leave UART0 unconfigured because we want to configure it as needed by linux (can/spi/uart/etc) */
|
|
{OFFSET(uart0_ctsn), (MODE(7) | PULLUDEN | PULLUP_EN)}, /* (E18) gpio1_8 */ /* Mode 0 */
|
|
{OFFSET(uart0_rxd), (MODE(7) | PULLUDEN | PULLUP_EN)}, /* (E15) gpio1_10 */ /* Mode 1 */
|
|
{OFFSET(ecap0_in_pwm0_out), (MODE(7) | PULLUDEN | PULLUP_EN)}, /* (C18) eCAP0_in_PWM0_out.gpio0[7] */ /* Latch EN */
|
|
{-1},
|
|
};
|
|
|
|
static struct module_pin_mux can_shield_netbird_pin_mux_final[] = {
|
|
{OFFSET(uart0_txd), (MODE(2) | PULLUDDIS | RXACTIVE)}, /* (E16) dcan0_rx */
|
|
{OFFSET(uart0_rxd), (MODE(2) | PULLUDEN | PULLUP_EN)}, /* (E15) dcan0_tx */
|
|
{OFFSET(uart0_rtsn), (MODE(2) | PULLUDDIS | RXACTIVE)}, /* (E17) dcan1_rx */
|
|
{OFFSET(uart0_ctsn), (MODE(2) | PULLUDEN | PULLUP_EN)}, /* (E18) dcan1_tx */
|
|
{-1},
|
|
};
|
|
|
|
|
|
static int request_gpios(void)
|
|
{
|
|
int ret;
|
|
|
|
debug("Shield configure gpios\n");
|
|
ret = shield_gpio_request_as_input(NETBIRD_GPIO_RST_SHIELD_N, "shield-rst");
|
|
if ((ret < 0))
|
|
return -1;
|
|
ret = shield_gpio_request_as_input(NETBIRD_GPIO_LATCH, "shield-load");
|
|
if ((ret < 0))
|
|
return -1;
|
|
ret = shield_gpio_request_as_input(NETBIRD_GPIO_MODE_0, "shield-mode0");
|
|
if ((ret < 0))
|
|
return -1;
|
|
ret = shield_gpio_request_as_input(NETBIRD_GPIO_MODE_1, "shield-mode1");
|
|
if ((ret < 0))
|
|
return -1;
|
|
|
|
shield_slot_initialized = 1;
|
|
return 0;
|
|
}
|
|
|
|
static int configure_shieldmode(int mode)
|
|
{
|
|
int ret;
|
|
|
|
if (mode < 0 || mode > 3) {
|
|
debug("Invalid shield mode %d\n", mode);
|
|
return -1;
|
|
}
|
|
|
|
debug("Shield type dualcan\n");
|
|
debug ("Set shield mode to %d\n", mode);
|
|
|
|
if (!shield_slot_initialized) {
|
|
if (request_gpios()) {
|
|
puts("Failed to request gpios\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
debug("Configure shield pin muxing for configuration\n");
|
|
configure_module_pin_mux(can_shield_netbird_pin_mux_config);
|
|
|
|
debug("Make sure shield module is in reset\n");
|
|
ret = gpio_direction_output(NETBIRD_GPIO_RST_SHIELD_N, 0);
|
|
if (ret < 0) {
|
|
puts("Can not set shield-rst as output\n");
|
|
return -1;
|
|
}
|
|
udelay(10);
|
|
|
|
debug("Set latch to high\n");
|
|
ret = gpio_direction_output(NETBIRD_GPIO_LATCH, 1);
|
|
if (ret < 0) {
|
|
puts("Can not set shield-load as output\n");
|
|
return -1;
|
|
}
|
|
udelay(10);
|
|
|
|
debug("Write mode to GPIOs\n");
|
|
ret = gpio_direction_output(NETBIRD_GPIO_MODE_0, mode & 0x01);
|
|
if (ret < 0) {
|
|
puts("Can not set shield-mode0 as output\n");
|
|
return -1;
|
|
}
|
|
ret = gpio_direction_output(NETBIRD_GPIO_MODE_1, mode & 0x02);
|
|
if (ret < 0) {
|
|
puts("Can not set shield-mode1 as output\n");
|
|
return -1;
|
|
}
|
|
udelay(10);
|
|
|
|
debug("Set latch to low\n");
|
|
gpio_set_value(NETBIRD_GPIO_LATCH, 0);
|
|
udelay(10);
|
|
|
|
debug("Set mode0 and mode1 to highz again\n");
|
|
ret = gpio_direction_input(NETBIRD_GPIO_MODE_0);
|
|
if ((ret < 0)) {
|
|
puts("Could not configure shield slot mode0 gpio as input\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = gpio_direction_input(NETBIRD_GPIO_MODE_1);
|
|
if ((ret < 0)) {
|
|
puts("Could not configure shield slot mode1 gpio as input\n");
|
|
return -1;
|
|
}
|
|
udelay(10);
|
|
|
|
debug("Take shield out of reset\n");
|
|
gpio_set_value(NETBIRD_GPIO_RST_SHIELD_N, 1);
|
|
udelay(10);
|
|
|
|
debug("Set final can shield muxing\n");
|
|
configure_module_pin_mux(can_shield_netbird_pin_mux_final);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int get_termination(const char* termination)
|
|
{
|
|
if (strcmp("on", termination) == 0) {
|
|
return 1;
|
|
}
|
|
else if (strcmp("off", termination) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
debug ("Invalid termination mode %s (falling back to off)", termination);
|
|
return -1;
|
|
}
|
|
|
|
static int get_mode_from_args(char * const argv[], int argc)
|
|
{
|
|
int terminations[CAN_PORTS];
|
|
int i;
|
|
|
|
assert(argc == (CAN_PORTS + 1));
|
|
|
|
if (strcmp ("termination", argv[0])) {
|
|
debug("The only option for dualcan is terminations\n");
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < CAN_PORTS; i ++) {
|
|
terminations[i] = get_termination(argv[i + 1]);
|
|
if (terminations[i] < 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Termination is inverse */
|
|
/* TODO: Double check */
|
|
return (!terminations[0] << 0) | (!terminations[1] << 1);
|
|
}
|
|
|
|
static int set_shieldmode(char * const argv[], int argc)
|
|
{
|
|
if (argc != 3) {
|
|
debug("Too few arguments for dualcan\n");
|
|
return -1;
|
|
}
|
|
|
|
return configure_shieldmode(get_mode_from_args(argv, argc));
|
|
}
|
|
|
|
static int no_options(char * const argv[], int argc)
|
|
{
|
|
if (argc != 0) {
|
|
debug("Too many arguments\n");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static struct shield_t can_shield = {
|
|
"dualcan", set_shieldmode
|
|
};
|
|
|
|
void can_shield_init(void)
|
|
{
|
|
shield_register(&can_shield);
|
|
}
|
|
|
|
static struct shield_t can_shield_passive = {
|
|
"dualcan-passive", no_options
|
|
};
|
|
|
|
void can_shield_passive_init(void)
|
|
{
|
|
shield_register(&can_shield_passive);
|
|
}
|