2005-07-10 22:58:12 +04:00
/*
2006-10-04 01:01:26 +04:00
* linux / arch / arm / mach - omap1 / serial . c
2005-07-10 22:58:12 +04:00
*
2006-12-07 04:13:56 +03:00
* OMAP1 serial support .
2005-07-10 22:58:12 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
2006-07-02 01:32:35 +04:00
# include <linux/irq.h>
2005-07-10 22:58:12 +04:00
# include <linux/delay.h>
# include <linux/serial.h>
# include <linux/tty.h>
# include <linux/serial_8250.h>
# include <linux/serial_reg.h>
2006-01-07 19:15:52 +03:00
# include <linux/clk.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2005-07-10 22:58:12 +04:00
# include <asm/mach-types.h>
2009-10-20 20:40:47 +04:00
# include <plat/board.h>
# include <plat/mux.h>
2008-08-05 19:14:15 +04:00
# include <mach/gpio.h>
2009-10-20 20:40:47 +04:00
# include <plat/fpga.h>
2005-07-10 22:58:12 +04:00
2010-11-18 20:59:46 +03:00
# include "pm.h"
2006-04-02 20:46:27 +04:00
static struct clk * uart1_ck ;
static struct clk * uart2_ck ;
static struct clk * uart3_ck ;
2005-07-10 22:58:12 +04:00
static inline unsigned int omap_serial_in ( struct plat_serial8250_port * up ,
int offset )
{
offset < < = up - > regshift ;
return ( unsigned int ) __raw_readb ( up - > membase + offset ) ;
}
static inline void omap_serial_outp ( struct plat_serial8250_port * p , int offset ,
int value )
{
offset < < = p - > regshift ;
__raw_writeb ( value , p - > membase + offset ) ;
}
/*
* Internal UARTs need to be initialized for the 8250 autoconfig to work
* properly . Note that the TX watermark initialization may not be needed
* once the 8250. c watermark handling code is merged .
*/
static void __init omap_serial_reset ( struct plat_serial8250_port * p )
{
2010-12-01 01:11:49 +03:00
omap_serial_outp ( p , UART_OMAP_MDR1 ,
UART_OMAP_MDR1_DISABLE ) ; /* disable UART */
2005-07-10 22:58:12 +04:00
omap_serial_outp ( p , UART_OMAP_SCR , 0x08 ) ; /* TX watermark */
2010-12-01 01:11:49 +03:00
omap_serial_outp ( p , UART_OMAP_MDR1 ,
UART_OMAP_MDR1_16X_MODE ) ; /* enable UART */
2005-07-10 22:58:12 +04:00
2006-12-07 04:13:56 +03:00
if ( ! cpu_is_omap15xx ( ) ) {
2005-07-10 22:58:12 +04:00
omap_serial_outp ( p , UART_OMAP_SYSC , 0x01 ) ;
while ( ! ( omap_serial_in ( p , UART_OMAP_SYSC ) & 0x01 ) ) ;
}
}
static struct plat_serial8250_port serial_platform_data [ ] = {
{
2010-02-15 19:48:53 +03:00
. mapbase = OMAP1_UART1_BASE ,
2005-07-10 22:58:12 +04:00
. irq = INT_UART1 ,
. flags = UPF_BOOT_AUTOCONF ,
. iotype = UPIO_MEM ,
. regshift = 2 ,
. uartclk = OMAP16XX_BASE_BAUD * 16 ,
} ,
{
2010-02-15 19:48:53 +03:00
. mapbase = OMAP1_UART2_BASE ,
2005-07-10 22:58:12 +04:00
. irq = INT_UART2 ,
. flags = UPF_BOOT_AUTOCONF ,
. iotype = UPIO_MEM ,
. regshift = 2 ,
. uartclk = OMAP16XX_BASE_BAUD * 16 ,
} ,
{
2010-02-15 19:48:53 +03:00
. mapbase = OMAP1_UART3_BASE ,
2005-07-10 22:58:12 +04:00
. irq = INT_UART3 ,
. flags = UPF_BOOT_AUTOCONF ,
. iotype = UPIO_MEM ,
. regshift = 2 ,
. uartclk = OMAP16XX_BASE_BAUD * 16 ,
} ,
{ } ,
} ;
static struct platform_device serial_device = {
. name = " serial8250 " ,
2005-09-08 19:04:41 +04:00
. id = PLAT8250_DEV_PLATFORM ,
2005-07-10 22:58:12 +04:00
. dev = {
. platform_data = serial_platform_data ,
} ,
} ;
/*
* Note that on Innovator - 1510 UART2 pins conflict with USB2 .
* By default UART2 does not work on Innovator - 1510 if you have
* USB OHCI enabled . To use UART2 , you must disable USB2 first .
*/
2005-11-10 17:26:48 +03:00
void __init omap_serial_init ( void )
2005-07-10 22:58:12 +04:00
{
int i ;
2009-09-22 08:49:53 +04:00
if ( cpu_is_omap7xx ( ) ) {
2005-07-10 22:58:12 +04:00
serial_platform_data [ 0 ] . regshift = 0 ;
serial_platform_data [ 1 ] . regshift = 0 ;
2009-09-18 07:09:39 +04:00
serial_platform_data [ 0 ] . irq = INT_7XX_UART_MODEM_1 ;
serial_platform_data [ 1 ] . irq = INT_7XX_UART_MODEM_IRDA_2 ;
2009-03-24 04:07:40 +03:00
}
2006-12-07 04:13:56 +03:00
if ( cpu_is_omap15xx ( ) ) {
2005-07-10 22:58:12 +04:00
serial_platform_data [ 0 ] . uartclk = OMAP1510_BASE_BAUD * 16 ;
serial_platform_data [ 1 ] . uartclk = OMAP1510_BASE_BAUD * 16 ;
serial_platform_data [ 2 ] . uartclk = OMAP1510_BASE_BAUD * 16 ;
}
2009-11-22 21:10:47 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( serial_platform_data ) - 1 ; i + + ) {
2005-07-10 22:58:12 +04:00
2010-08-02 15:21:39 +04:00
/* Don't look at UARTs higher than 2 for omap7xx */
if ( cpu_is_omap7xx ( ) & & i > 1 ) {
serial_platform_data [ i ] . membase = NULL ;
serial_platform_data [ i ] . mapbase = 0 ;
continue ;
}
2009-10-16 20:53:00 +04:00
/* Static mapping, never released */
serial_platform_data [ i ] . membase =
ioremap ( serial_platform_data [ i ] . mapbase , SZ_2K ) ;
if ( ! serial_platform_data [ i ] . membase ) {
printk ( KERN_ERR " Could not ioremap uart%i \n " , i ) ;
continue ;
}
2005-07-10 22:58:12 +04:00
switch ( i ) {
case 0 :
uart1_ck = clk_get ( NULL , " uart1_ck " ) ;
if ( IS_ERR ( uart1_ck ) )
printk ( " Could not get uart1_ck \n " ) ;
else {
2006-01-18 02:33:51 +03:00
clk_enable ( uart1_ck ) ;
2006-12-07 04:13:56 +03:00
if ( cpu_is_omap15xx ( ) )
2005-07-10 22:58:12 +04:00
clk_set_rate ( uart1_ck , 12000000 ) ;
}
break ;
case 1 :
uart2_ck = clk_get ( NULL , " uart2_ck " ) ;
if ( IS_ERR ( uart2_ck ) )
printk ( " Could not get uart2_ck \n " ) ;
else {
2006-01-18 02:33:51 +03:00
clk_enable ( uart2_ck ) ;
2006-12-07 04:13:56 +03:00
if ( cpu_is_omap15xx ( ) )
2005-07-10 22:58:12 +04:00
clk_set_rate ( uart2_ck , 12000000 ) ;
else
clk_set_rate ( uart2_ck , 48000000 ) ;
}
break ;
case 2 :
uart3_ck = clk_get ( NULL , " uart3_ck " ) ;
if ( IS_ERR ( uart3_ck ) )
printk ( " Could not get uart3_ck \n " ) ;
else {
2006-01-18 02:33:51 +03:00
clk_enable ( uart3_ck ) ;
2006-12-07 04:13:56 +03:00
if ( cpu_is_omap15xx ( ) )
2005-07-10 22:58:12 +04:00
clk_set_rate ( uart3_ck , 12000000 ) ;
}
break ;
}
omap_serial_reset ( & serial_platform_data [ i ] ) ;
}
}
2005-09-09 02:07:38 +04:00
# ifdef CONFIG_OMAP_SERIAL_WAKE
2006-10-06 21:53:39 +04:00
static irqreturn_t omap_serial_wake_interrupt ( int irq , void * dev_id )
2005-09-09 02:07:38 +04:00
{
/* Need to do something with serial port right after wake-up? */
return IRQ_HANDLED ;
}
/*
* Reroutes serial RX lines to GPIO lines for the duration of
* sleep to allow waking up the device from serial port even
* in deep sleep .
*/
void omap_serial_wake_trigger ( int enable )
{
if ( ! cpu_is_omap16xx ( ) )
return ;
if ( uart1_ck ! = NULL ) {
if ( enable )
omap_cfg_reg ( V14_16XX_GPIO37 ) ;
else
omap_cfg_reg ( V14_16XX_UART1_RX ) ;
}
if ( uart2_ck ! = NULL ) {
if ( enable )
omap_cfg_reg ( R9_16XX_GPIO18 ) ;
else
omap_cfg_reg ( R9_16XX_UART2_RX ) ;
}
if ( uart3_ck ! = NULL ) {
if ( enable )
omap_cfg_reg ( L14_16XX_GPIO49 ) ;
else
omap_cfg_reg ( L14_16XX_UART3_RX ) ;
}
}
static void __init omap_serial_set_port_wakeup ( int gpio_nr )
{
int ret ;
2008-12-11 04:35:30 +03:00
ret = gpio_request ( gpio_nr , " UART wake " ) ;
2005-09-09 02:07:38 +04:00
if ( ret < 0 ) {
printk ( KERN_ERR " Could not request UART wake GPIO: %i \n " ,
gpio_nr ) ;
return ;
}
2008-12-11 04:35:26 +03:00
gpio_direction_input ( gpio_nr ) ;
2008-12-11 04:35:26 +03:00
ret = request_irq ( gpio_to_irq ( gpio_nr ) , & omap_serial_wake_interrupt ,
2006-07-03 04:20:05 +04:00
IRQF_TRIGGER_RISING , " serial wakeup " , NULL ) ;
2005-09-09 02:07:38 +04:00
if ( ret ) {
2008-12-11 04:35:30 +03:00
gpio_free ( gpio_nr ) ;
2005-09-09 02:07:38 +04:00
printk ( KERN_ERR " No interrupt for UART wake GPIO: %i \n " ,
gpio_nr ) ;
return ;
}
2008-12-11 04:35:26 +03:00
enable_irq_wake ( gpio_to_irq ( gpio_nr ) ) ;
2005-09-09 02:07:38 +04:00
}
static int __init omap_serial_wakeup_init ( void )
{
if ( ! cpu_is_omap16xx ( ) )
return 0 ;
if ( uart1_ck ! = NULL )
omap_serial_set_port_wakeup ( 37 ) ;
if ( uart2_ck ! = NULL )
omap_serial_set_port_wakeup ( 18 ) ;
if ( uart3_ck ! = NULL )
omap_serial_set_port_wakeup ( 49 ) ;
return 0 ;
}
late_initcall ( omap_serial_wakeup_init ) ;
# endif /* CONFIG_OMAP_SERIAL_WAKE */
2005-07-10 22:58:12 +04:00
static int __init omap_init ( void )
{
2010-12-10 20:46:24 +03:00
if ( ! cpu_class_is_omap1 ( ) )
return - ENODEV ;
2005-07-10 22:58:12 +04:00
return platform_device_register ( & serial_device ) ;
}
arch_initcall ( omap_init ) ;