2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2011-09-21 01:00:12 +04:00
/*
* System Specific setup for PCEngines ALIX .
* At the moment this means setup of GPIO control of LEDs
* on Alix .2 / 3 / 6 boards .
*
* Copyright ( C ) 2008 Constantin Baranov < const @ mimas . ru >
* Copyright ( C ) 2011 Ed Wildgoose < kernel @ wildgooses . com >
2012-03-06 03:05:14 +04:00
* and Philip Prindeville < philipp @ redfish - solutions . com >
2011-09-21 01:00:12 +04:00
*
* TODO : There are large similarities with leds - net5501 . c
* by Alessandro Zummo < a . zummo @ towertech . it >
* In the future leds - net5501 . c should be migrated over to platform
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/string.h>
2016-02-15 02:09:55 +03:00
# include <linux/moduleparam.h>
2011-09-21 01:00:12 +04:00
# include <linux/leds.h>
# include <linux/platform_device.h>
# include <linux/gpio.h>
2012-03-06 03:05:14 +04:00
# include <linux/input.h>
# include <linux/gpio_keys.h>
# include <linux/dmi.h>
2011-09-21 01:00:12 +04:00
# include <asm/geode.h>
2012-03-06 03:05:14 +04:00
# define BIOS_SIGNATURE_TINYBIOS 0xf0000
# define BIOS_SIGNATURE_COREBOOT 0x500
# define BIOS_REGION_SIZE 0x10000
2016-02-15 02:09:55 +03:00
/*
* This driver is not modular , but to keep back compatibility
* with existing use cases , continuing with module_param is
* the easiest way forward .
*/
2012-01-13 03:02:18 +04:00
static bool force = 0 ;
2011-09-21 01:00:12 +04:00
module_param ( force , bool , 0444 ) ;
/* FIXME: Award bios is not automatically detected as Alix platform */
MODULE_PARM_DESC ( force , " Force detection as ALIX.2/ALIX.3 platform " ) ;
2012-03-06 03:05:14 +04:00
static struct gpio_keys_button alix_gpio_buttons [ ] = {
{
. code = KEY_RESTART ,
. gpio = 24 ,
. active_low = 1 ,
. desc = " Reset button " ,
. type = EV_KEY ,
. wakeup = 0 ,
. debounce_interval = 100 ,
. can_disable = 0 ,
}
} ;
static struct gpio_keys_platform_data alix_buttons_data = {
. buttons = alix_gpio_buttons ,
. nbuttons = ARRAY_SIZE ( alix_gpio_buttons ) ,
. poll_interval = 20 ,
} ;
static struct platform_device alix_buttons_dev = {
. name = " gpio-keys-polled " ,
. id = 1 ,
. dev = {
. platform_data = & alix_buttons_data ,
}
} ;
2011-09-21 01:00:12 +04:00
static struct gpio_led alix_leds [ ] = {
{
. name = " alix:1 " ,
. gpio = 6 ,
. default_trigger = " default-on " ,
. active_low = 1 ,
} ,
{
. name = " alix:2 " ,
. gpio = 25 ,
. default_trigger = " default-off " ,
. active_low = 1 ,
} ,
{
. name = " alix:3 " ,
. gpio = 27 ,
. default_trigger = " default-off " ,
. active_low = 1 ,
} ,
} ;
static struct gpio_led_platform_data alix_leds_data = {
. num_leds = ARRAY_SIZE ( alix_leds ) ,
. leds = alix_leds ,
} ;
static struct platform_device alix_leds_dev = {
. name = " leds-gpio " ,
. id = - 1 ,
. dev . platform_data = & alix_leds_data ,
} ;
2013-09-30 17:21:15 +04:00
static struct platform_device * alix_devs [ ] __initdata = {
2012-03-06 03:05:14 +04:00
& alix_buttons_dev ,
& alix_leds_dev ,
} ;
2011-09-21 01:00:12 +04:00
static void __init register_alix ( void )
{
/* Setup LED control through leds-gpio driver */
2012-03-06 03:05:14 +04:00
platform_add_devices ( alix_devs , ARRAY_SIZE ( alix_devs ) ) ;
2011-09-21 01:00:12 +04:00
}
2012-03-06 03:05:14 +04:00
static bool __init alix_present ( unsigned long bios_phys ,
2011-09-21 01:00:12 +04:00
const char * alix_sig ,
size_t alix_sig_len )
{
2012-03-06 03:05:14 +04:00
const size_t bios_len = BIOS_REGION_SIZE ;
2011-09-21 01:00:12 +04:00
const char * bios_virt ;
const char * scan_end ;
const char * p ;
char name [ 64 ] ;
if ( force ) {
printk ( KERN_NOTICE " %s: forced to skip BIOS test, "
" assume system is ALIX.2/ALIX.3 \n " ,
KBUILD_MODNAME ) ;
2012-03-06 03:05:14 +04:00
return true ;
2011-09-21 01:00:12 +04:00
}
bios_virt = phys_to_virt ( bios_phys ) ;
scan_end = bios_virt + bios_len - ( alix_sig_len + 2 ) ;
for ( p = bios_virt ; p < scan_end ; p + + ) {
const char * tail ;
char * a ;
if ( memcmp ( p , alix_sig , alix_sig_len ) ! = 0 )
continue ;
memcpy ( name , p , sizeof ( name ) ) ;
/* remove the first \0 character from string */
a = strchr ( name , ' \0 ' ) ;
if ( a )
* a = ' ' ;
/* cut the string at a newline */
a = strchr ( name , ' \r ' ) ;
if ( a )
* a = ' \0 ' ;
tail = p + alix_sig_len ;
2012-03-06 03:05:14 +04:00
if ( ( tail [ 0 ] = = ' 2 ' | | tail [ 0 ] = = ' 3 ' | | tail [ 0 ] = = ' 6 ' ) ) {
2011-09-21 01:00:12 +04:00
printk ( KERN_INFO
" %s: system is recognized as \" %s \" \n " ,
KBUILD_MODNAME , name ) ;
2012-03-06 03:05:14 +04:00
return true ;
2011-09-21 01:00:12 +04:00
}
}
2012-03-06 03:05:14 +04:00
return false ;
}
static bool __init alix_present_dmi ( void )
{
const char * vendor , * product ;
vendor = dmi_get_system_info ( DMI_SYS_VENDOR ) ;
if ( ! vendor | | strcmp ( vendor , " PC Engines " ) )
return false ;
product = dmi_get_system_info ( DMI_PRODUCT_NAME ) ;
if ( ! product | | ( strcmp ( product , " ALIX.2D " ) & & strcmp ( product , " ALIX.6 " ) ) )
return false ;
printk ( KERN_INFO " %s: system is recognized as \" %s %s \" \n " ,
KBUILD_MODNAME , vendor , product ) ;
return true ;
2011-09-21 01:00:12 +04:00
}
static int __init alix_init ( void )
{
const char tinybios_sig [ ] = " PC Engines ALIX. " ;
const char coreboot_sig [ ] = " PC Engines \0 ALIX. " ;
if ( ! is_geode ( ) )
return 0 ;
2012-03-06 03:05:14 +04:00
if ( alix_present ( BIOS_SIGNATURE_TINYBIOS , tinybios_sig , sizeof ( tinybios_sig ) - 1 ) | |
alix_present ( BIOS_SIGNATURE_COREBOOT , coreboot_sig , sizeof ( coreboot_sig ) - 1 ) | |
alix_present_dmi ( ) )
2011-09-21 01:00:12 +04:00
register_alix ( ) ;
return 0 ;
}
2016-02-15 02:09:55 +03:00
device_initcall ( alix_init ) ;