2005-04-17 02:20:36 +04:00
/*
* linux / arch / arm / mach - sa1100 / assabet . c
*
* Author : Nicolas Pitre
*
* This file contains all Assabet - specific tweaks .
*
* 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/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/errno.h>
2016-08-31 10:49:45 +03:00
# include <linux/gpio/gpio-reg.h>
2016-08-31 10:49:47 +03:00
# include <linux/gpio/machine.h>
2005-04-17 02:20:36 +04:00
# include <linux/ioport.h>
2012-09-21 13:18:58 +04:00
# include <linux/platform_data/sa11x0-serial.h>
2016-08-31 10:49:47 +03:00
# include <linux/regulator/fixed.h>
# include <linux/regulator/machine.h>
2005-04-17 02:20:36 +04:00
# include <linux/serial_core.h>
2013-02-15 02:26:50 +04:00
# include <linux/platform_device.h>
2012-01-21 02:18:06 +04:00
# include <linux/mfd/ucb1x00.h>
2005-04-17 02:20:36 +04:00
# include <linux/mtd/mtd.h>
# include <linux/mtd/partitions.h>
# include <linux/delay.h>
# include <linux/mm.h>
2012-03-13 22:22:03 +04:00
# include <linux/leds.h>
# include <linux/slab.h>
2005-04-17 02:20:36 +04:00
2012-01-14 15:50:04 +04:00
# include <video/sa1100fb.h>
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2005-04-17 02:20:36 +04:00
# include <asm/mach-types.h>
# include <asm/setup.h>
# include <asm/page.h>
2006-03-16 17:44:36 +03:00
# include <asm/pgtable-hwdef.h>
2005-04-17 02:20:36 +04:00
# include <asm/pgtable.h>
# include <asm/tlbflush.h>
# include <asm/mach/arch.h>
# include <asm/mach/flash.h>
2014-12-24 01:14:14 +03:00
# include <linux/platform_data/irda-sa11x0.h>
2005-04-17 02:20:36 +04:00
# include <asm/mach/map.h>
2008-08-05 19:14:15 +04:00
# include <mach/assabet.h>
2012-08-24 17:17:38 +04:00
# include <linux/platform_data/mfd-mcp-sa11x0.h>
2012-02-24 03:06:51 +04:00
# include <mach/irqs.h>
2005-04-17 02:20:36 +04:00
# include "generic.h"
# define ASSABET_BCR_DB1110 \
2012-01-22 01:17:06 +04:00
( ASSABET_BCR_SPK_OFF | \
2005-04-17 02:20:36 +04:00
ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \
ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \
ASSABET_BCR_IRDA_MD0 )
# define ASSABET_BCR_DB1111 \
2012-01-22 01:17:06 +04:00
( ASSABET_BCR_SPK_OFF | \
2005-04-17 02:20:36 +04:00
ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \
ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \
ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \
ASSABET_BCR_IRDA_MD0 | ASSABET_BCR_CF_RST )
unsigned long SCR_value = ASSABET_SCR_INIT ;
EXPORT_SYMBOL ( SCR_value ) ;
2016-08-31 10:49:45 +03:00
static struct gpio_chip * assabet_bcr_gc ;
static const char * assabet_names [ ] = {
" cf_pwr " , " cf_gfx_reset " , " nsoft_reset " , " irda_fsel " ,
" irda_md0 " , " irda_md1 " , " stereo_loopback " , " ncf_bus_on " ,
" audio_pwr_on " , " light_pwr_on " , " lcd16data " , " lcd_pwr_on " ,
" rs232_on " , " nred_led " , " ngreen_led " , " vib_on " ,
" com_dtr " , " com_rts " , " radio_wake_mod " , " i2c_enab " ,
" tvir_enab " , " qmute " , " radio_pwr_on " , " spkr_off " ,
" rs232_valid " , " com_dcd " , " com_cts " , " com_dsr " ,
" radio_cts " , " radio_dsr " , " radio_dcd " , " radio_ri " ,
} ;
2005-04-17 02:20:36 +04:00
2016-08-31 10:49:45 +03:00
/* The old deprecated interface */
2005-04-17 02:20:36 +04:00
void ASSABET_BCR_frob ( unsigned int mask , unsigned int val )
{
2016-08-31 10:49:45 +03:00
unsigned long m = mask , v = val ;
2005-04-17 02:20:36 +04:00
2016-08-31 10:49:45 +03:00
assabet_bcr_gc - > set_multiple ( assabet_bcr_gc , & m , & v ) ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( ASSABET_BCR_frob ) ;
2016-08-31 10:49:45 +03:00
static int __init assabet_init_gpio ( void __iomem * reg , u32 def_val )
{
struct gpio_chip * gc ;
writel_relaxed ( def_val , reg ) ;
gc = gpio_reg_init ( NULL , reg , - 1 , 32 , " assabet " , 0xff000000 , def_val ,
assabet_names , NULL , NULL ) ;
if ( IS_ERR ( gc ) )
return PTR_ERR ( gc ) ;
assabet_bcr_gc = gc ;
return gc - > base ;
}
2013-07-09 13:27:12 +04:00
/*
* The codec reset goes to three devices , so we need to release
* the rest when any one of these requests it . However , that
* causes the ADV7171 to consume around 100 mA - more than half
* the LCD - blanked power .
*
* With the ADV7171 , LCD and backlight enabled , we go over
* budget on the MAX846 Li - Ion charger , and if no Li - Ion battery
* is connected , the Assabet crashes .
*/
# define RST_UCB1X00 (1 << 0)
# define RST_UDA1341 (1 << 1)
# define RST_ADV7171 (1 << 2)
# define SDA GPIO_GPIO(15)
# define SCK GPIO_GPIO(18)
# define MOD GPIO_GPIO(17)
static void adv7171_start ( void )
{
GPSR = SCK ;
udelay ( 1 ) ;
GPSR = SDA ;
udelay ( 2 ) ;
GPCR = SDA ;
}
static void adv7171_stop ( void )
{
GPSR = SCK ;
udelay ( 2 ) ;
GPSR = SDA ;
udelay ( 1 ) ;
}
static void adv7171_send ( unsigned byte )
{
unsigned i ;
for ( i = 0 ; i < 8 ; i + + , byte < < = 1 ) {
GPCR = SCK ;
udelay ( 1 ) ;
if ( byte & 0x80 )
GPSR = SDA ;
else
GPCR = SDA ;
udelay ( 1 ) ;
GPSR = SCK ;
udelay ( 1 ) ;
}
GPCR = SCK ;
udelay ( 1 ) ;
GPSR = SDA ;
udelay ( 1 ) ;
GPDR & = ~ SDA ;
GPSR = SCK ;
udelay ( 1 ) ;
if ( GPLR & SDA )
printk ( KERN_WARNING " No ACK from ADV7171 \n " ) ;
udelay ( 1 ) ;
GPCR = SCK | SDA ;
udelay ( 1 ) ;
GPDR | = SDA ;
udelay ( 1 ) ;
}
static void adv7171_write ( unsigned reg , unsigned val )
{
unsigned gpdr = GPDR ;
unsigned gplr = GPLR ;
2016-08-31 10:49:45 +03:00
ASSABET_BCR_frob ( ASSABET_BCR_AUDIO_ON , ASSABET_BCR_AUDIO_ON ) ;
2013-07-09 13:27:12 +04:00
udelay ( 100 ) ;
GPCR = SDA | SCK | MOD ; /* clear L3 mode to ensure UDA1341 doesn't respond */
GPDR = ( GPDR | SCK | MOD ) & ~ SDA ;
udelay ( 10 ) ;
if ( ! ( GPLR & SDA ) )
printk ( KERN_WARNING " Something dragging SDA down? \n " ) ;
GPDR | = SDA ;
adv7171_start ( ) ;
adv7171_send ( 0x54 ) ;
adv7171_send ( reg ) ;
adv7171_send ( val ) ;
adv7171_stop ( ) ;
/* Restore GPIO state for L3 bus */
GPSR = gplr & ( SDA | SCK | MOD ) ;
GPCR = ( ~ gplr ) & ( SDA | SCK | MOD ) ;
GPDR = gpdr ;
}
static void adv7171_sleep ( void )
{
/* Put the ADV7171 into sleep mode */
adv7171_write ( 0x04 , 0x40 ) ;
}
static unsigned codec_nreset ;
static void assabet_codec_reset ( unsigned mask , int set )
{
unsigned long flags ;
bool old ;
local_irq_save ( flags ) ;
old = ! codec_nreset ;
if ( set )
codec_nreset & = ~ mask ;
else
codec_nreset | = mask ;
if ( old ! = ! codec_nreset ) {
if ( codec_nreset ) {
ASSABET_BCR_set ( ASSABET_BCR_NCODEC_RST ) ;
adv7171_sleep ( ) ;
} else {
ASSABET_BCR_clear ( ASSABET_BCR_NCODEC_RST ) ;
}
}
local_irq_restore ( flags ) ;
}
2012-01-22 23:23:33 +04:00
static void assabet_ucb1x00_reset ( enum ucb1x00_reset state )
{
2013-07-09 13:27:12 +04:00
int set = state = = UCB_RST_REMOVE | | state = = UCB_RST_SUSPEND | |
state = = UCB_RST_PROBE_FAIL ;
assabet_codec_reset ( RST_UCB1X00 , set ) ;
}
void assabet_uda1341_reset ( int set )
{
assabet_codec_reset ( RST_UDA1341 , set ) ;
2012-01-22 23:23:33 +04:00
}
2013-07-09 13:27:12 +04:00
EXPORT_SYMBOL ( assabet_uda1341_reset ) ;
2012-01-22 23:23:33 +04:00
2005-04-17 02:20:36 +04:00
/*
* Assabet flash support code .
*/
# ifdef ASSABET_REV_4
/*
* Phase 4 Assabet has two 28F 160 B3 flash parts in bank 0 :
*/
static struct mtd_partition assabet_partitions [ ] = {
{
. name = " bootloader " ,
. size = 0x00020000 ,
. offset = 0 ,
. mask_flags = MTD_WRITEABLE ,
} , {
. name = " bootloader params " ,
. size = 0x00020000 ,
. offset = MTDPART_OFS_APPEND ,
. mask_flags = MTD_WRITEABLE ,
} , {
. name = " jffs " ,
. size = MTDPART_SIZ_FULL ,
. offset = MTDPART_OFS_APPEND ,
}
} ;
# else
/*
* Phase 5 Assabet has two 28F 128 J3A flash parts in bank 0 :
*/
static struct mtd_partition assabet_partitions [ ] = {
{
. name = " bootloader " ,
. size = 0x00040000 ,
. offset = 0 ,
. mask_flags = MTD_WRITEABLE ,
} , {
. name = " bootloader params " ,
. size = 0x00040000 ,
. offset = MTDPART_OFS_APPEND ,
. mask_flags = MTD_WRITEABLE ,
} , {
. name = " jffs " ,
. size = MTDPART_SIZ_FULL ,
. offset = MTDPART_OFS_APPEND ,
}
} ;
# endif
static struct flash_platform_data assabet_flash_data = {
. map_name = " cfi_probe " ,
. parts = assabet_partitions ,
. nr_parts = ARRAY_SIZE ( assabet_partitions ) ,
} ;
static struct resource assabet_flash_resources [ ] = {
2012-01-12 14:25:29 +04:00
DEFINE_RES_MEM ( SA1100_CS0_PHYS , SZ_32M ) ,
DEFINE_RES_MEM ( SA1100_CS1_PHYS , SZ_32M ) ,
2005-04-17 02:20:36 +04:00
} ;
/*
* Assabet IrDA support code .
*/
static int assabet_irda_set_power ( struct device * dev , unsigned int state )
{
static unsigned int bcr_state [ 4 ] = {
ASSABET_BCR_IRDA_MD0 ,
ASSABET_BCR_IRDA_MD1 | ASSABET_BCR_IRDA_MD0 ,
ASSABET_BCR_IRDA_MD1 ,
0
} ;
2013-07-09 13:32:30 +04:00
if ( state < 4 )
ASSABET_BCR_frob ( ASSABET_BCR_IRDA_MD1 | ASSABET_BCR_IRDA_MD0 ,
bcr_state [ state ] ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void assabet_irda_set_speed ( struct device * dev , unsigned int speed )
{
if ( speed < 4000000 )
ASSABET_BCR_clear ( ASSABET_BCR_IRDA_FSEL ) ;
else
ASSABET_BCR_set ( ASSABET_BCR_IRDA_FSEL ) ;
}
static struct irda_platform_data assabet_irda_data = {
. set_power = assabet_irda_set_power ,
. set_speed = assabet_irda_set_speed ,
} ;
2012-01-21 02:18:06 +04:00
static struct ucb1x00_plat_data assabet_ucb1x00_data = {
2012-01-22 23:23:33 +04:00
. reset = assabet_ucb1x00_reset ,
2012-01-21 02:18:06 +04:00
. gpio_base = - 1 ,
2013-07-09 13:31:20 +04:00
. can_wakeup = 1 ,
2012-01-21 02:18:06 +04:00
} ;
2005-08-18 13:10:46 +04:00
static struct mcp_plat_data assabet_mcp_data = {
. mccr0 = MCCR0_ADM ,
. sclk_rate = 11981000 ,
2012-01-21 02:18:06 +04:00
. codec_pdata = & assabet_ucb1x00_data ,
2005-08-18 13:10:46 +04:00
} ;
2012-01-14 16:03:22 +04:00
static void assabet_lcd_set_visual ( u32 visual )
{
u_int is_true_color = visual = = FB_VISUAL_TRUECOLOR ;
if ( machine_is_assabet ( ) ) {
# if 1 // phase 4 or newer Assabet's
if ( is_true_color )
ASSABET_BCR_set ( ASSABET_BCR_LCD_12RGB ) ;
else
ASSABET_BCR_clear ( ASSABET_BCR_LCD_12RGB ) ;
# else
// older Assabet's
if ( is_true_color )
ASSABET_BCR_clear ( ASSABET_BCR_LCD_12RGB ) ;
else
ASSABET_BCR_set ( ASSABET_BCR_LCD_12RGB ) ;
# endif
}
}
2012-01-14 15:50:04 +04:00
# ifndef ASSABET_PAL_VIDEO
2012-01-14 16:03:22 +04:00
static void assabet_lcd_backlight_power ( int on )
{
if ( on )
ASSABET_BCR_set ( ASSABET_BCR_LIGHT_ON ) ;
else
ASSABET_BCR_clear ( ASSABET_BCR_LIGHT_ON ) ;
}
/*
* Turn on / off the backlight . When turning the backlight on , we wait
* 500u s after turning it on so we don ' t cause the supplies to droop
* when we enable the LCD controller ( and cause a hard reset . )
*/
static void assabet_lcd_power ( int on )
{
if ( on ) {
ASSABET_BCR_set ( ASSABET_BCR_LCD_ON ) ;
udelay ( 500 ) ;
} else
ASSABET_BCR_clear ( ASSABET_BCR_LCD_ON ) ;
}
2012-01-14 15:50:04 +04:00
/*
* The assabet uses a sharp LQ039Q2DS54 LCD module . It is actually
* takes an RGB666 signal , but we provide it with an RGB565 signal
* instead ( def_rgb_16 ) .
*/
static struct sa1100fb_mach_info lq039q2ds54_info = {
. pixclock = 171521 , . bpp = 16 ,
. xres = 320 , . yres = 240 ,
. hsync_len = 5 , . vsync_len = 1 ,
. left_margin = 61 , . upper_margin = 3 ,
. right_margin = 9 , . lower_margin = 0 ,
. sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT ,
. lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act ,
. lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv ( 2 ) ,
2012-01-14 16:03:22 +04:00
. backlight_power = assabet_lcd_backlight_power ,
. lcd_power = assabet_lcd_power ,
. set_visual = assabet_lcd_set_visual ,
2012-01-14 15:50:04 +04:00
} ;
# else
2012-01-14 16:03:22 +04:00
static void assabet_pal_backlight_power ( int on )
{
ASSABET_BCR_clear ( ASSABET_BCR_LIGHT_ON ) ;
}
static void assabet_pal_power ( int on )
{
ASSABET_BCR_clear ( ASSABET_BCR_LCD_ON ) ;
}
2012-01-14 15:50:04 +04:00
static struct sa1100fb_mach_info pal_info = {
. pixclock = 67797 , . bpp = 16 ,
. xres = 640 , . yres = 512 ,
. hsync_len = 64 , . vsync_len = 6 ,
. left_margin = 125 , . upper_margin = 70 ,
. right_margin = 115 , . lower_margin = 36 ,
. lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act ,
. lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv ( 512 ) ,
2012-01-14 16:03:22 +04:00
. backlight_power = assabet_pal_backlight_power ,
. lcd_power = assabet_pal_power ,
. set_visual = assabet_lcd_set_visual ,
2012-01-14 15:50:04 +04:00
} ;
# endif
2012-01-26 15:50:23 +04:00
# ifdef CONFIG_ASSABET_NEPONSET
static struct resource neponset_resources [ ] = {
DEFINE_RES_MEM ( 0x10000000 , 0x08000000 ) ,
DEFINE_RES_MEM ( 0x18000000 , 0x04000000 ) ,
DEFINE_RES_MEM ( 0x40000000 , SZ_8K ) ,
DEFINE_RES_IRQ ( IRQ_GPIO25 ) ,
} ;
# endif
2016-08-31 10:49:47 +03:00
static struct gpiod_lookup_table assabet_cf_gpio_table = {
. dev_id = " sa11x0-pcmcia.1 " ,
. table = {
GPIO_LOOKUP ( " gpio " , 21 , " ready " , GPIO_ACTIVE_HIGH ) ,
GPIO_LOOKUP ( " gpio " , 22 , " detect " , GPIO_ACTIVE_LOW ) ,
GPIO_LOOKUP ( " gpio " , 24 , " bvd2 " , GPIO_ACTIVE_HIGH ) ,
GPIO_LOOKUP ( " gpio " , 25 , " bvd1 " , GPIO_ACTIVE_HIGH ) ,
GPIO_LOOKUP ( " assabet " , 1 , " reset " , GPIO_ACTIVE_HIGH ) ,
GPIO_LOOKUP ( " assabet " , 7 , " bus-enable " , GPIO_ACTIVE_LOW ) ,
{ } ,
} ,
} ;
static struct regulator_consumer_supply assabet_cf_vcc_consumers [ ] = {
REGULATOR_SUPPLY ( " vcc " , " sa11x0-pcmcia.1 " ) ,
} ;
static struct fixed_voltage_config assabet_cf_vcc_pdata __initdata = {
. supply_name = " cf-power " ,
. microvolts = 3300000 ,
. enable_high = 1 ,
} ;
2005-04-17 02:20:36 +04:00
static void __init assabet_init ( void )
{
/*
* Ensure that the power supply is in " high power " mode .
*/
GPSR = GPIO_GPIO16 ;
2012-01-24 13:23:19 +04:00
GPDR | = GPIO_GPIO16 ;
2005-04-17 02:20:36 +04:00
/*
* Ensure that these pins are set as outputs and are driving
* logic 0. This ensures that we won ' t inadvertently toggle
* the WS latch in the CPLD , and we don ' t float causing
* excessive power drain . - - rmk
*/
GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM ;
2012-01-24 13:23:19 +04:00
GPDR | = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM ;
2005-04-17 02:20:36 +04:00
2012-01-24 13:25:57 +04:00
/*
* Also set GPIO27 as an output ; this is used to clock UART3
* via the FPGA and as otherwise has no pullups or pulldowns ,
* so stop it floating .
*/
GPCR = GPIO_GPIO27 ;
GPDR | = GPIO_GPIO27 ;
2005-04-17 02:20:36 +04:00
/*
* Set up registers for sleep mode .
*/
PWER = PWER_GPIO0 ;
PGSR = 0 ;
PCFR = 0 ;
PSDR = 0 ;
PPDR | = PPC_TXD3 | PPC_TXD1 ;
PPSR | = PPC_TXD3 | PPC_TXD1 ;
2012-01-21 02:24:07 +04:00
sa11x0_ppc_configure_mcp ( ) ;
2005-04-17 02:20:36 +04:00
if ( machine_has_neponset ( ) ) {
# ifndef CONFIG_ASSABET_NEPONSET
printk ( " Warning: Neponset detected but full support "
" hasn't been configured in the kernel \n " ) ;
2012-01-26 15:50:23 +04:00
# else
platform_device_register_simple ( " neponset " , 0 ,
neponset_resources , ARRAY_SIZE ( neponset_resources ) ) ;
2005-04-17 02:20:36 +04:00
# endif
2016-08-31 10:49:47 +03:00
} else {
sa11x0_register_fixed_regulator ( 0 , & assabet_cf_vcc_pdata ,
assabet_cf_vcc_consumers ,
ARRAY_SIZE ( assabet_cf_vcc_consumers ) ) ;
2005-04-17 02:20:36 +04:00
}
2012-01-14 15:50:04 +04:00
# ifndef ASSABET_PAL_VIDEO
sa11x0_register_lcd ( & lq039q2ds54_info ) ;
# else
sa11x0_register_lcd ( & pal_video ) ;
# endif
2009-10-06 17:55:53 +04:00
sa11x0_register_mtd ( & assabet_flash_data , assabet_flash_resources ,
ARRAY_SIZE ( assabet_flash_resources ) ) ;
sa11x0_register_irda ( & assabet_irda_data ) ;
sa11x0_register_mcp ( & assabet_mcp_data ) ;
2016-08-31 10:49:47 +03:00
if ( ! machine_has_neponset ( ) )
sa11x0_register_pcmcia ( 1 , & assabet_cf_gpio_table ) ;
2005-04-17 02:20:36 +04:00
}
/*
* On Assabet , we must probe for the Neponset board _before_
* paging_init ( ) has occurred to actually determine the amount
* of RAM available . To do so , we map the appropriate IO section
* in the page table here in order to access GPIO registers .
*/
static void __init map_sa1100_gpio_regs ( void )
{
unsigned long phys = __PREG ( GPLR ) & PMD_MASK ;
2012-06-06 14:42:36 +04:00
unsigned long virt = ( unsigned long ) io_p2v ( phys ) ;
2005-04-17 02:20:36 +04:00
int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN ( DOMAIN_IO ) ;
pmd_t * pmd ;
2012-01-14 20:10:53 +04:00
pmd = pmd_offset ( pud_offset ( pgd_offset_k ( virt ) , virt ) , virt ) ;
2005-04-17 02:20:36 +04:00
* pmd = __pmd ( phys | prot ) ;
flush_pmd_entry ( pmd ) ;
}
/*
* Read System Configuration " Register "
* ( taken from " Intel StrongARM SA-1110 Microprocessor Development Board
* User ' s Guide " , section 4.4.1)
*
* This same scan is performed in arch / arm / boot / compressed / head - sa1100 . S
* to set up the serial port for decompression status messages . We
* repeat it here because the kernel may not be loaded as a zImage , and
* also because it ' s a hassle to communicate the SCR value to the kernel
* from the decompressor .
*
* Note that IRQs are guaranteed to be disabled .
*/
static void __init get_assabet_scr ( void )
{
2012-04-30 16:41:21 +04:00
unsigned long uninitialized_var ( scr ) , i ;
2005-04-17 02:20:36 +04:00
GPDR | = 0x3fc ; /* Configure GPIO 9:2 as outputs */
GPSR = 0x3fc ; /* Write 0xFF to GPIO 9:2 */
GPDR & = ~ ( 0x3fc ) ; /* Configure GPIO 9:2 as inputs */
2005-11-21 20:01:13 +03:00
for ( i = 100 ; i - - ; ) /* Read GPIO 9:2 */
scr = GPLR ;
2005-04-17 02:20:36 +04:00
GPDR | = 0x3fc ; /* restore correct pin direction */
scr & = 0x3fc ; /* save as system configuration byte. */
SCR_value = scr ;
}
static void __init
2014-04-14 01:54:58 +04:00
fixup_assabet ( struct tag * tags , char * * cmdline )
2005-04-17 02:20:36 +04:00
{
/* This must be done before any call to machine_has_neponset() */
map_sa1100_gpio_regs ( ) ;
get_assabet_scr ( ) ;
if ( machine_has_neponset ( ) )
printk ( " Neponset expansion board detected \n " ) ;
}
static void assabet_uart_pm ( struct uart_port * port , u_int state , u_int oldstate )
{
if ( port - > mapbase = = _Ser1UTCR0 ) {
if ( state )
ASSABET_BCR_clear ( ASSABET_BCR_RS232EN |
ASSABET_BCR_COM_RTS |
ASSABET_BCR_COM_DTR ) ;
else
ASSABET_BCR_set ( ASSABET_BCR_RS232EN |
ASSABET_BCR_COM_RTS |
ASSABET_BCR_COM_DTR ) ;
}
}
/*
* Assabet uses COM_RTS and COM_DTR for both UART1 ( com port )
* and UART3 ( radio module ) . We only handle them for UART1 here .
*/
static void assabet_set_mctrl ( struct uart_port * port , u_int mctrl )
{
if ( port - > mapbase = = _Ser1UTCR0 ) {
u_int set = 0 , clear = 0 ;
if ( mctrl & TIOCM_RTS )
clear | = ASSABET_BCR_COM_RTS ;
else
set | = ASSABET_BCR_COM_RTS ;
if ( mctrl & TIOCM_DTR )
clear | = ASSABET_BCR_COM_DTR ;
else
set | = ASSABET_BCR_COM_DTR ;
ASSABET_BCR_clear ( clear ) ;
ASSABET_BCR_set ( set ) ;
}
}
static u_int assabet_get_mctrl ( struct uart_port * port )
{
u_int ret = 0 ;
u_int bsr = ASSABET_BSR ;
/* need 2 reads to read current value */
bsr = ASSABET_BSR ;
if ( port - > mapbase = = _Ser1UTCR0 ) {
if ( bsr & ASSABET_BSR_COM_DCD )
ret | = TIOCM_CD ;
if ( bsr & ASSABET_BSR_COM_CTS )
ret | = TIOCM_CTS ;
if ( bsr & ASSABET_BSR_COM_DSR )
ret | = TIOCM_DSR ;
} else if ( port - > mapbase = = _Ser3UTCR0 ) {
if ( bsr & ASSABET_BSR_RAD_DCD )
ret | = TIOCM_CD ;
if ( bsr & ASSABET_BSR_RAD_CTS )
ret | = TIOCM_CTS ;
if ( bsr & ASSABET_BSR_RAD_DSR )
ret | = TIOCM_DSR ;
if ( bsr & ASSABET_BSR_RAD_RI )
ret | = TIOCM_RI ;
} else {
ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR ;
}
return ret ;
}
static struct sa1100_port_fns assabet_port_fns __initdata = {
. set_mctrl = assabet_set_mctrl ,
. get_mctrl = assabet_get_mctrl ,
. pm = assabet_uart_pm ,
} ;
static struct map_desc assabet_io_desc [ ] __initdata = {
2005-10-28 18:19:04 +04:00
{ /* Board Control Register */
. virtual = 0xf1000000 ,
. pfn = __phys_to_pfn ( 0x12000000 ) ,
. length = 0x00100000 ,
. type = MT_DEVICE
} , { /* MQ200 */
. virtual = 0xf2800000 ,
. pfn = __phys_to_pfn ( 0x4b800000 ) ,
. length = 0x00800000 ,
. type = MT_DEVICE
}
2005-04-17 02:20:36 +04:00
} ;
static void __init assabet_map_io ( void )
{
sa1100_map_io ( ) ;
iotable_init ( assabet_io_desc , ARRAY_SIZE ( assabet_io_desc ) ) ;
/*
* Set SUS bit in SDCR0 so serial port 1 functions .
* Its called GPCLKR0 in my SA1110 manual .
*/
Ser1SDCR0 | = SDCR0_SUS ;
2013-10-16 03:09:02 +04:00
MSC1 = ( MSC1 & ~ 0xffff ) |
MSC_NonBrst | MSC_32BitStMem |
MSC_RdAcc ( 2 ) | MSC_WrAcc ( 2 ) | MSC_Rec ( 0 ) ;
2005-04-17 02:20:36 +04:00
2012-03-26 02:54:16 +04:00
if ( ! machine_has_neponset ( ) )
2005-04-17 02:20:36 +04:00
sa1100_register_uart_fns ( & assabet_port_fns ) ;
/*
* When Neponset is attached , the first UART should be
* UART3 . That ' s what Angel is doing and many documents
* are stating this .
*
* We do the Neponset mapping even if Neponset support
* isn ' t compiled in so the user will still get something on
* the expected physical serial port .
*
* We no longer do this ; not all boot loaders support it ,
* and UART3 appears to be somewhat unreliable with blob .
*/
sa1100_register_uart ( 0 , 1 ) ;
sa1100_register_uart ( 2 , 3 ) ;
}
2012-03-13 22:22:03 +04:00
/* LEDs */
# if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
struct assabet_led {
struct led_classdev cdev ;
u32 mask ;
} ;
/*
* The triggers lines up below will only be used if the
* LED triggers are compiled in .
*/
static const struct {
const char * name ;
const char * trigger ;
} assabet_leds [ ] = {
{ " assabet:red " , " cpu0 " , } ,
{ " assabet:green " , " heartbeat " , } ,
} ;
/*
* The LED control in Assabet is reversed :
* - setting bit means turn off LED
* - clearing bit means turn on LED
*/
static void assabet_led_set ( struct led_classdev * cdev ,
enum led_brightness b )
{
struct assabet_led * led = container_of ( cdev ,
struct assabet_led , cdev ) ;
if ( b ! = LED_OFF )
ASSABET_BCR_clear ( led - > mask ) ;
else
ASSABET_BCR_set ( led - > mask ) ;
}
static enum led_brightness assabet_led_get ( struct led_classdev * cdev )
{
struct assabet_led * led = container_of ( cdev ,
struct assabet_led , cdev ) ;
return ( ASSABET_BCR & led - > mask ) ? LED_OFF : LED_FULL ;
}
static int __init assabet_leds_init ( void )
{
int i ;
if ( ! machine_is_assabet ( ) )
return - ENODEV ;
for ( i = 0 ; i < ARRAY_SIZE ( assabet_leds ) ; i + + ) {
struct assabet_led * led ;
led = kzalloc ( sizeof ( * led ) , GFP_KERNEL ) ;
if ( ! led )
break ;
led - > cdev . name = assabet_leds [ i ] . name ;
led - > cdev . brightness_set = assabet_led_set ;
led - > cdev . brightness_get = assabet_led_get ;
led - > cdev . default_trigger = assabet_leds [ i ] . trigger ;
if ( ! i )
led - > mask = ASSABET_BCR_LED_RED ;
else
led - > mask = ASSABET_BCR_LED_GREEN ;
if ( led_classdev_register ( NULL , & led - > cdev ) < 0 ) {
kfree ( led ) ;
break ;
}
}
return 0 ;
}
/*
* Since we may have triggers on any subsystem , defer registration
* until after subsystem_init .
*/
fs_initcall ( assabet_leds_init ) ;
# endif
2005-04-17 02:20:36 +04:00
2016-08-31 10:49:45 +03:00
void __init assabet_init_irq ( void )
{
2016-08-31 10:49:47 +03:00
unsigned int assabet_gpio_base ;
2016-08-31 10:49:45 +03:00
u32 def_val ;
sa1100_init_irq ( ) ;
if ( machine_has_neponset ( ) )
def_val = ASSABET_BCR_DB1111 ;
else
def_val = ASSABET_BCR_DB1110 ;
/*
* Angel sets this , but other bootloaders may not .
*
* This must precede any driver calls to BCR_set ( ) or BCR_clear ( ) .
*/
2016-08-31 10:49:47 +03:00
assabet_gpio_base = assabet_init_gpio ( ( void * ) & ASSABET_BCR , def_val ) ;
assabet_cf_vcc_pdata . gpio = assabet_gpio_base + 0 ;
2016-08-31 10:49:45 +03:00
}
2005-04-17 02:20:36 +04:00
MACHINE_START ( ASSABET , " Intel-Assabet " )
2011-07-06 06:38:17 +04:00
. atag_offset = 0x100 ,
2005-07-03 20:38:58 +04:00
. fixup = fixup_assabet ,
. map_io = assabet_map_io ,
2012-02-24 03:06:51 +04:00
. nr_irqs = SA1100_NR_IRQS ,
2016-08-31 10:49:45 +03:00
. init_irq = assabet_init_irq ,
2012-11-08 23:40:59 +04:00
. init_time = sa1100_timer_init ,
2005-04-17 02:20:36 +04:00
. init_machine = assabet_init ,
2012-04-26 17:22:45 +04:00
. init_late = sa11x0_init_late ,
2011-07-06 06:28:09 +04:00
# ifdef CONFIG_SA1111
. dma_zone_size = SZ_1M ,
# endif
2011-11-05 14:28:50 +04:00
. restart = sa11x0_restart ,
2005-04-17 02:20:36 +04:00
MACHINE_END