2006-12-06 17:14:03 -08:00
/*
* linux / arch / arm / plat - omap / debug - leds . c
*
2012-03-14 02:14:39 +08:00
* Copyright 2011 by Bryan Wu < bryan . wu @ canonical . com >
2006-12-06 17:14:03 -08:00
* Copyright 2003 by Texas Instruments Incorporated
*
* 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 .
*/
2012-03-14 02:14:39 +08:00
# include <linux/kernel.h>
2006-12-06 17:14:03 -08:00
# include <linux/init.h>
# include <linux/platform_device.h>
# include <linux/leds.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2012-08-30 15:37:24 -07:00
# include <linux/platform_data/gpio-omap.h>
2012-03-14 02:14:39 +08:00
# include <linux/slab.h>
2006-12-06 17:14:03 -08:00
# include <asm/mach-types.h>
/* Many OMAP development platforms reuse the same "debug board"; these
* platforms include H2 , H3 , H4 , and Perseus2 . There are 16 LEDs on the
* debug board ( all green ) , accessed through FPGA registers .
*/
2012-10-31 14:02:46 -07:00
/* NOTE: most boards don't have a static mapping for the FPGA ... */
struct h2p2_dbg_fpga {
/* offset 0x00 */
u16 smc91x [ 8 ] ;
/* offset 0x10 */
u16 fpga_rev ;
u16 board_rev ;
u16 gpio_outputs ;
u16 leds ;
/* offset 0x18 */
u16 misc_inputs ;
u16 lan_status ;
u16 lan_reset ;
u16 reserved0 ;
/* offset 0x20 */
u16 ps2_data ;
u16 ps2_ctrl ;
/* plus also 4 rs232 ports ... */
} ;
2012-03-14 02:14:39 +08:00
static struct h2p2_dbg_fpga __iomem * fpga ;
2006-12-06 17:14:03 -08:00
2012-03-14 02:14:39 +08:00
static u16 fpga_led_state ;
2006-12-06 17:14:03 -08:00
struct dbg_led {
struct led_classdev cdev ;
u16 mask ;
} ;
2012-03-14 02:14:39 +08:00
static const struct {
const char * name ;
const char * trigger ;
} dbg_leds [ ] = {
{ " dbg:d4 " , " heartbeat " , } ,
{ " dbg:d5 " , " cpu0 " , } ,
{ " dbg:d6 " , " default-on " , } ,
{ " dbg:d7 " , } ,
{ " dbg:d8 " , } ,
{ " dbg:d9 " , } ,
{ " dbg:d10 " , } ,
{ " dbg:d11 " , } ,
{ " dbg:d12 " , } ,
{ " dbg:d13 " , } ,
{ " dbg:d14 " , } ,
{ " dbg:d15 " , } ,
{ " dbg:d16 " , } ,
{ " dbg:d17 " , } ,
{ " dbg:d18 " , } ,
{ " dbg:d19 " , } ,
2006-12-06 17:14:03 -08:00
} ;
2012-03-14 02:14:39 +08:00
/*
* The triggers lines up below will only be used if the
* LED triggers are compiled in .
*/
static void dbg_led_set ( struct led_classdev * cdev ,
enum led_brightness b )
2006-12-06 17:14:03 -08:00
{
2012-03-14 02:14:39 +08:00
struct dbg_led * led = container_of ( cdev , struct dbg_led , cdev ) ;
u16 reg ;
2006-12-06 17:14:03 -08:00
2012-03-14 02:14:39 +08:00
reg = __raw_readw ( & fpga - > leds ) ;
if ( b ! = LED_OFF )
reg | = led - > mask ;
2006-12-06 17:14:03 -08:00
else
2012-03-14 02:14:39 +08:00
reg & = ~ led - > mask ;
__raw_writew ( reg , & fpga - > leds ) ;
2006-12-06 17:14:03 -08:00
}
2012-03-14 02:14:39 +08:00
static enum led_brightness dbg_led_get ( struct led_classdev * cdev )
2006-12-06 17:14:03 -08:00
{
2012-03-14 02:14:39 +08:00
struct dbg_led * led = container_of ( cdev , struct dbg_led , cdev ) ;
u16 reg ;
2006-12-06 17:14:03 -08:00
2012-03-14 02:14:39 +08:00
reg = __raw_readw ( & fpga - > leds ) ;
return ( reg & led - > mask ) ? LED_FULL : LED_OFF ;
2006-12-06 17:14:03 -08:00
}
2012-03-14 02:14:39 +08:00
static int fpga_probe ( struct platform_device * pdev )
2006-12-06 17:14:03 -08:00
{
struct resource * iomem ;
2012-03-14 02:14:39 +08:00
int i ;
2006-12-06 17:14:03 -08:00
iomem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! iomem )
return - ENODEV ;
2012-11-12 11:44:03 +01:00
fpga = ioremap ( iomem - > start , resource_size ( iomem ) ) ;
2012-03-14 02:14:39 +08:00
__raw_writew ( 0xff , & fpga - > leds ) ;
for ( i = 0 ; i < ARRAY_SIZE ( dbg_leds ) ; i + + ) {
struct dbg_led * led ;
led = kzalloc ( sizeof ( * led ) , GFP_KERNEL ) ;
if ( ! led )
break ;
2006-12-06 17:14:03 -08:00
2012-03-14 02:14:39 +08:00
led - > cdev . name = dbg_leds [ i ] . name ;
led - > cdev . brightness_set = dbg_led_set ;
led - > cdev . brightness_get = dbg_led_get ;
led - > cdev . default_trigger = dbg_leds [ i ] . trigger ;
led - > mask = BIT ( i ) ;
2006-12-06 17:14:03 -08:00
2012-03-14 02:14:39 +08:00
if ( led_classdev_register ( NULL , & led - > cdev ) < 0 ) {
kfree ( led ) ;
break ;
}
2006-12-06 17:14:03 -08:00
}
return 0 ;
}
2009-07-08 13:22:04 +02:00
static int fpga_suspend_noirq ( struct device * dev )
2006-12-06 17:14:03 -08:00
{
2012-03-14 02:14:39 +08:00
fpga_led_state = __raw_readw ( & fpga - > leds ) ;
__raw_writew ( 0xff , & fpga - > leds ) ;
2006-12-06 17:14:03 -08:00
return 0 ;
}
2009-07-08 13:22:04 +02:00
static int fpga_resume_noirq ( struct device * dev )
2006-12-06 17:14:03 -08:00
{
2012-03-14 02:14:39 +08:00
__raw_writew ( ~ fpga_led_state , & fpga - > leds ) ;
2006-12-06 17:14:03 -08:00
return 0 ;
}
2009-12-14 18:00:08 -08:00
static const struct dev_pm_ops fpga_dev_pm_ops = {
2009-07-08 13:22:04 +02:00
. suspend_noirq = fpga_suspend_noirq ,
. resume_noirq = fpga_resume_noirq ,
} ;
2006-12-06 17:14:03 -08:00
static struct platform_driver led_driver = {
. driver . name = " omap_dbg_led " ,
2009-07-08 13:22:04 +02:00
. driver . pm = & fpga_dev_pm_ops ,
2006-12-06 17:14:03 -08:00
. probe = fpga_probe ,
} ;
static int __init fpga_init ( void )
{
if ( machine_is_omap_h4 ( )
| | machine_is_omap_h3 ( )
| | machine_is_omap_h2 ( )
| | machine_is_omap_perseus2 ( )
)
return platform_driver_register ( & led_driver ) ;
return 0 ;
}
fs_initcall ( fpga_init ) ;