2005-04-16 15:20:36 -07:00
/*
* arch / arm / mach - imx / generic . c
*
* author : Sascha Hauer
* Created : april 20 th , 2004
* Copyright : Synertronixx GmbH
*
* Common code for i . MX machines
*
* 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
*
*/
2005-10-29 19:07:23 +01:00
# include <linux/platform_device.h>
2005-04-16 15:20:36 -07:00
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
2005-10-30 15:03:48 -08:00
# include <linux/string.h>
2007-05-12 14:31:17 +01:00
# include <asm/errno.h>
2005-05-03 22:57:56 +01:00
# include <asm/arch/imxfb.h>
2005-04-16 15:20:36 -07:00
# include <asm/hardware.h>
2005-10-04 23:17:52 +01:00
# include <asm/arch/imx-regs.h>
2005-04-16 15:20:36 -07:00
# include <asm/mach/map.h>
2006-04-02 19:27:07 +01:00
# include <asm/arch/mmc.h>
2007-05-12 14:31:17 +01:00
# include <asm/arch/gpio.h>
unsigned long imx_gpio_alloc_map [ ( GPIO_PORT_MAX + 1 ) * 32 / BITS_PER_LONG ] ;
2005-04-16 15:20:36 -07:00
void imx_gpio_mode ( int gpio_mode )
{
unsigned int pin = gpio_mode & GPIO_PIN_MASK ;
2005-10-04 23:17:52 +01:00
unsigned int port = ( gpio_mode & GPIO_PORT_MASK ) > > GPIO_PORT_SHIFT ;
unsigned int ocr = ( gpio_mode & GPIO_OCR_MASK ) > > GPIO_OCR_SHIFT ;
2005-04-16 15:20:36 -07:00
unsigned int tmp ;
/* Pullup enable */
if ( gpio_mode & GPIO_PUEN )
PUEN ( port ) | = ( 1 < < pin ) ;
else
PUEN ( port ) & = ~ ( 1 < < pin ) ;
/* Data direction */
if ( gpio_mode & GPIO_OUT )
DDIR ( port ) | = 1 < < pin ;
else
DDIR ( port ) & = ~ ( 1 < < pin ) ;
/* Primary / alternate function */
if ( gpio_mode & GPIO_AF )
GPR ( port ) | = ( 1 < < pin ) ;
else
GPR ( port ) & = ~ ( 1 < < pin ) ;
/* use as gpio? */
2005-10-04 23:17:52 +01:00
if ( gpio_mode & GPIO_GIUS )
2005-04-16 15:20:36 -07:00
GIUS ( port ) | = ( 1 < < pin ) ;
else
GIUS ( port ) & = ~ ( 1 < < pin ) ;
/* Output / input configuration */
/* FIXME: I'm not very sure about OCR and ICONF, someone
* should have a look over it
*/
if ( pin < 16 ) {
tmp = OCR1 ( port ) ;
tmp & = ~ ( 3 < < ( pin * 2 ) ) ;
tmp | = ( ocr < < ( pin * 2 ) ) ;
OCR1 ( port ) = tmp ;
2005-10-04 23:17:52 +01:00
ICONFA1 ( port ) & = ~ ( 3 < < ( pin * 2 ) ) ;
ICONFA1 ( port ) | = ( ( gpio_mode > > GPIO_AOUT_SHIFT ) & 3 ) < < ( pin * 2 ) ;
ICONFB1 ( port ) & = ~ ( 3 < < ( pin * 2 ) ) ;
ICONFB1 ( port ) | = ( ( gpio_mode > > GPIO_BOUT_SHIFT ) & 3 ) < < ( pin * 2 ) ;
2005-04-16 15:20:36 -07:00
} else {
tmp = OCR2 ( port ) ;
tmp & = ~ ( 3 < < ( ( pin - 16 ) * 2 ) ) ;
tmp | = ( ocr < < ( ( pin - 16 ) * 2 ) ) ;
OCR2 ( port ) = tmp ;
2005-10-04 23:17:52 +01:00
ICONFA2 ( port ) & = ~ ( 3 < < ( ( pin - 16 ) * 2 ) ) ;
ICONFA2 ( port ) | = ( ( gpio_mode > > GPIO_AOUT_SHIFT ) & 3 ) < < ( ( pin - 16 ) * 2 ) ;
ICONFB2 ( port ) & = ~ ( 3 < < ( ( pin - 16 ) * 2 ) ) ;
ICONFB2 ( port ) | = ( ( gpio_mode > > GPIO_BOUT_SHIFT ) & 3 ) < < ( ( pin - 16 ) * 2 ) ;
2005-04-16 15:20:36 -07:00
}
}
EXPORT_SYMBOL ( imx_gpio_mode ) ;
2007-05-12 14:31:17 +01:00
int imx_gpio_request ( unsigned gpio , const char * label )
{
2007-08-29 23:23:38 +01:00
if ( gpio > = ( GPIO_PORT_MAX + 1 ) * 32 ) {
2007-05-12 14:31:17 +01:00
printk ( KERN_ERR " imx_gpio: Attempt to request nonexistent GPIO %d for \" %s \" \n " ,
gpio , label ? label : " ? " ) ;
return - EINVAL ;
2007-08-29 23:23:38 +01:00
}
2007-05-12 14:31:17 +01:00
if ( test_and_set_bit ( gpio , imx_gpio_alloc_map ) ) {
printk ( KERN_ERR " imx_gpio: GPIO %d already used. Allocation for \" %s \" failed \n " ,
gpio , label ? label : " ? " ) ;
return - EBUSY ;
}
return 0 ;
}
EXPORT_SYMBOL ( imx_gpio_request ) ;
void imx_gpio_free ( unsigned gpio )
{
if ( gpio > = ( GPIO_PORT_MAX + 1 ) * 32 )
return ;
clear_bit ( gpio , imx_gpio_alloc_map ) ;
}
EXPORT_SYMBOL ( imx_gpio_free ) ;
int imx_gpio_direction_input ( unsigned gpio )
{
2007-08-29 23:23:38 +01:00
imx_gpio_mode ( gpio | GPIO_IN | GPIO_GIUS | GPIO_DR ) ;
2007-05-12 14:31:17 +01:00
return 0 ;
}
EXPORT_SYMBOL ( imx_gpio_direction_input ) ;
int imx_gpio_direction_output ( unsigned gpio , int value )
{
imx_gpio_set_value ( gpio , value ) ;
2007-08-20 21:39:41 +01:00
imx_gpio_mode ( gpio | GPIO_OUT | GPIO_GIUS | GPIO_DR ) ;
2007-05-12 14:31:17 +01:00
return 0 ;
}
EXPORT_SYMBOL ( imx_gpio_direction_output ) ;
int imx_gpio_setup_multiple_pins ( const int * pin_list , unsigned count ,
int alloc_mode , const char * label )
{
const int * p = pin_list ;
int i ;
unsigned gpio ;
unsigned mode ;
for ( i = 0 ; i < count ; i + + ) {
gpio = * p & ( GPIO_PIN_MASK | GPIO_PORT_MASK ) ;
mode = * p & ~ ( GPIO_PIN_MASK | GPIO_PORT_MASK ) ;
if ( gpio > = ( GPIO_PORT_MAX + 1 ) * 32 )
goto setup_error ;
if ( alloc_mode & IMX_GPIO_ALLOC_MODE_RELEASE )
imx_gpio_free ( gpio ) ;
else if ( ! ( alloc_mode & IMX_GPIO_ALLOC_MODE_NO_ALLOC ) )
if ( imx_gpio_request ( gpio , label ) )
if ( ! ( alloc_mode & IMX_GPIO_ALLOC_MODE_TRY_ALLOC ) )
goto setup_error ;
if ( ! ( alloc_mode & ( IMX_GPIO_ALLOC_MODE_ALLOC_ONLY |
IMX_GPIO_ALLOC_MODE_RELEASE ) ) )
imx_gpio_mode ( gpio | mode ) ;
p + + ;
}
return 0 ;
setup_error :
if ( alloc_mode & ( IMX_GPIO_ALLOC_MODE_NO_ALLOC |
IMX_GPIO_ALLOC_MODE_TRY_ALLOC ) )
return - EINVAL ;
while ( p ! = pin_list ) {
p - - ;
gpio = * p & ( GPIO_PIN_MASK | GPIO_PORT_MASK ) ;
imx_gpio_free ( gpio ) ;
}
return - EINVAL ;
}
EXPORT_SYMBOL ( imx_gpio_setup_multiple_pins ) ;
void __imx_gpio_set_value ( unsigned gpio , int value )
{
imx_gpio_set_value_inline ( gpio , value ) ;
}
EXPORT_SYMBOL ( __imx_gpio_set_value ) ;
int imx_gpio_to_irq ( unsigned gpio )
{
return IRQ_GPIOA ( 0 ) + gpio ;
}
EXPORT_SYMBOL ( imx_gpio_to_irq ) ;
int imx_irq_to_gpio ( unsigned irq )
{
if ( irq < IRQ_GPIOA ( 0 ) )
return - EINVAL ;
return irq - IRQ_GPIOA ( 0 ) ;
}
EXPORT_SYMBOL ( imx_irq_to_gpio ) ;
2005-04-16 15:20:36 -07:00
static struct resource imx_mmc_resources [ ] = {
[ 0 ] = {
. start = 0x00214000 ,
. end = 0x002140FF ,
. flags = IORESOURCE_MEM ,
} ,
[ 1 ] = {
. start = ( SDHC_INT ) ,
. end = ( SDHC_INT ) ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
2006-04-02 19:27:07 +01:00
static u64 imxmmmc_dmamask = 0xffffffffUL ;
2005-04-16 15:20:36 -07:00
static struct platform_device imx_mmc_device = {
. name = " imx-mmc " ,
. id = 0 ,
2006-04-02 19:27:07 +01:00
. dev = {
. dma_mask = & imxmmmc_dmamask ,
. coherent_dma_mask = 0xffffffff ,
} ,
2005-04-16 15:20:36 -07:00
. num_resources = ARRAY_SIZE ( imx_mmc_resources ) ,
. resource = imx_mmc_resources ,
} ;
2006-04-02 19:27:07 +01:00
void __init imx_set_mmc_info ( struct imxmmc_platform_data * info )
{
imx_mmc_device . dev . platform_data = info ;
}
2005-05-03 22:57:56 +01:00
static struct imxfb_mach_info imx_fb_info ;
void __init set_imx_fb_info ( struct imxfb_mach_info * hard_imx_fb_info )
{
memcpy ( & imx_fb_info , hard_imx_fb_info , sizeof ( struct imxfb_mach_info ) ) ;
}
EXPORT_SYMBOL ( set_imx_fb_info ) ;
2005-04-16 15:20:36 -07:00
static struct resource imxfb_resources [ ] = {
[ 0 ] = {
. start = 0x00205000 ,
. end = 0x002050FF ,
. flags = IORESOURCE_MEM ,
} ,
[ 1 ] = {
. start = LCDC_INT ,
. end = LCDC_INT ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
2005-05-03 22:57:56 +01:00
static u64 fb_dma_mask = ~ ( u64 ) 0 ;
2005-04-16 15:20:36 -07:00
static struct platform_device imxfb_device = {
. name = " imx-fb " ,
. id = 0 ,
2005-05-03 22:57:56 +01:00
. dev = {
. platform_data = & imx_fb_info ,
. dma_mask = & fb_dma_mask ,
. coherent_dma_mask = 0xffffffff ,
} ,
2005-04-16 15:20:36 -07:00
. num_resources = ARRAY_SIZE ( imxfb_resources ) ,
. resource = imxfb_resources ,
} ;
static struct platform_device * devices [ ] __initdata = {
& imx_mmc_device ,
& imxfb_device ,
} ;
static struct map_desc imx_io_desc [ ] __initdata = {
2005-10-28 15:19:10 +01:00
{
. virtual = IMX_IO_BASE ,
. pfn = __phys_to_pfn ( IMX_IO_PHYS ) ,
. length = IMX_IO_SIZE ,
. type = MT_DEVICE
}
2005-04-16 15:20:36 -07:00
} ;
void __init
imx_map_io ( void )
{
iotable_init ( imx_io_desc , ARRAY_SIZE ( imx_io_desc ) ) ;
}
static int __init imx_init ( void )
{
return platform_add_devices ( devices , ARRAY_SIZE ( devices ) ) ;
}
subsys_initcall ( imx_init ) ;