/* * Copyright (c) 2011 The Chromium OS Authors. * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include #include #include #include #include #include /* position of the UART/SPI select switch */ enum spi_uart_switch { SWITCH_UNKNOWN, SWITCH_SPI, SWITCH_UART, SWITCH_BOTH }; /* Information about the spi/uart switch */ struct spi_uart { int gpio; /* GPIO to control switch */ u32 port; /* Port number of UART affected */ }; static struct spi_uart local; static enum spi_uart_switch switch_pos; /* Current switch position */ static void get_config(struct spi_uart *config) { #if defined CONFIG_SPI_CORRUPTS_UART config->gpio = CONFIG_UART_DISABLE_GPIO; config->port = CONFIG_SPI_CORRUPTS_UART_NR; #else config->gpio = -1; #endif } /* * Init the UART / SPI switch. This can be called before relocation so we must * not access BSS. */ void gpio_early_init_uart(void) { struct spi_uart config; get_config(&config); if (config.gpio != -1) { /* Cannot provide a label prior to relocation */ gpio_request(config.gpio, NULL); gpio_direction_output(config.gpio, 0); } } /* * Configure the UART / SPI switch. */ void gpio_config_uart(void) { get_config(&local); if (local.gpio != -1) { gpio_direction_output(local.gpio, 0); switch_pos = SWITCH_UART; } else { /* * If we're here we don't have a SPI switch; go ahead and * enable the SPI now. We didn't in spi_init() so we wouldn't * kill the UART. */ pinmux_set_func(PINGRP_GMC, PMUX_FUNC_SFLASH); switch_pos = SWITCH_BOTH; } } static void spi_uart_switch(struct spi_uart *config, enum spi_uart_switch new_pos) { if (switch_pos == SWITCH_BOTH || new_pos == switch_pos) return; /* pre-delay, allow SPI/UART to settle, FIFO to empty, etc. */ udelay(CONFIG_SPI_CORRUPTS_UART_DLY); /* We need to dynamically change the pinmux, shared w/UART RXD/CTS */ pinmux_set_func(PINGRP_GMC, new_pos == SWITCH_SPI ? PMUX_FUNC_SFLASH : PMUX_FUNC_UARTD); /* * On Seaboard, MOSI/MISO are shared w/UART. * Use GPIO I3 (UART_DISABLE) to tristate UART during SPI activity. * Enable UART later (cs_deactivate) so we can use it for U-Boot comms. */ gpio_direction_output(config->gpio, new_pos == SWITCH_SPI); switch_pos = new_pos; } void pinmux_select_uart(void) { spi_uart_switch(&local, SWITCH_UART); } void pinmux_select_spi(void) { spi_uart_switch(&local, SWITCH_SPI); }