2005-04-16 15:20:36 -07:00
/*
2012-03-14 01:50:00 +08:00
* Driver for the 4 user LEDs found on the Integrator AP / CP baseboard
* Based on Versatile and RealView machine LED code
2005-04-16 15:20:36 -07:00
*
2012-03-14 01:50:00 +08:00
* License terms : GNU General Public License ( GPL ) version 2
* Author : Bryan Wu < bryan . wu @ canonical . com >
2005-04-16 15:20:36 -07:00
*/
# include <linux/kernel.h>
# include <linux/init.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2012-03-14 01:50:00 +08:00
# include <linux/slab.h>
# include <linux/leds.h>
2005-04-16 15:20:36 -07:00
2014-02-13 21:26:24 +01:00
# include "hardware.h"
2013-06-16 02:44:27 +02:00
# include "cm.h"
2012-03-14 01:50:00 +08:00
# if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
# define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE)
# define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET)
2005-04-16 15:20:36 -07:00
2012-03-14 01:50:00 +08:00
struct integrator_led {
struct led_classdev cdev ;
u8 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 ;
} integrator_leds [ ] = {
{ " integrator:green0 " , " heartbeat " , } ,
{ " integrator:yellow " , } ,
{ " integrator:red " , } ,
{ " integrator:green1 " , } ,
{ " integrator:core_module " , " cpu0 " , } ,
} ;
static void integrator_led_set ( struct led_classdev * cdev ,
enum led_brightness b )
2005-04-16 15:20:36 -07:00
{
2012-03-14 01:50:00 +08:00
struct integrator_led * led = container_of ( cdev ,
struct integrator_led , cdev ) ;
u32 reg = __raw_readl ( LEDREG ) ;
2005-05-03 12:22:19 +01:00
2012-03-14 01:50:00 +08:00
if ( b ! = LED_OFF )
reg | = led - > mask ;
else
reg & = ~ led - > mask ;
2005-04-16 15:20:36 -07:00
2012-03-14 01:50:00 +08:00
while ( __raw_readl ( ALPHA_REG ) & 1 )
cpu_relax ( ) ;
2005-04-16 15:20:36 -07:00
2012-03-14 01:50:00 +08:00
__raw_writel ( reg , LEDREG ) ;
}
2005-04-16 15:20:36 -07:00
2012-03-14 01:50:00 +08:00
static enum led_brightness integrator_led_get ( struct led_classdev * cdev )
{
struct integrator_led * led = container_of ( cdev ,
struct integrator_led , cdev ) ;
u32 reg = __raw_readl ( LEDREG ) ;
2005-04-16 15:20:36 -07:00
2012-03-14 01:50:00 +08:00
return ( reg & led - > mask ) ? LED_FULL : LED_OFF ;
}
2005-04-16 15:20:36 -07:00
2012-03-14 01:50:00 +08:00
static void cm_led_set ( struct led_classdev * cdev ,
enum led_brightness b )
{
if ( b ! = LED_OFF )
cm_control ( CM_CTRL_LED , CM_CTRL_LED ) ;
else
cm_control ( CM_CTRL_LED , 0 ) ;
}
2005-04-16 15:20:36 -07:00
2012-03-14 01:50:00 +08:00
static enum led_brightness cm_led_get ( struct led_classdev * cdev )
{
2013-10-10 14:11:18 +02:00
u32 reg = cm_get ( ) ;
2005-04-16 15:20:36 -07:00
2012-03-14 01:50:00 +08:00
return ( reg & CM_CTRL_LED ) ? LED_FULL : LED_OFF ;
2005-04-16 15:20:36 -07:00
}
2012-03-14 01:50:00 +08:00
static int __init integrator_leds_init ( void )
2005-04-16 15:20:36 -07:00
{
2012-03-14 01:50:00 +08:00
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( integrator_leds ) ; i + + ) {
struct integrator_led * led ;
led = kzalloc ( sizeof ( * led ) , GFP_KERNEL ) ;
if ( ! led )
break ;
led - > cdev . name = integrator_leds [ i ] . name ;
if ( i = = 4 ) { /* Setting for LED in core module */
led - > cdev . brightness_set = cm_led_set ;
led - > cdev . brightness_get = cm_led_get ;
} else {
led - > cdev . brightness_set = integrator_led_set ;
led - > cdev . brightness_get = integrator_led_get ;
}
led - > cdev . default_trigger = integrator_leds [ i ] . trigger ;
led - > mask = BIT ( i ) ;
if ( led_classdev_register ( NULL , & led - > cdev ) < 0 ) {
kfree ( led ) ;
break ;
}
}
2005-04-16 15:20:36 -07:00
return 0 ;
}
2012-03-14 01:50:00 +08:00
/*
* Since we may have triggers on any subsystem , defer registration
* until after subsystem_init .
*/
fs_initcall ( integrator_leds_init ) ;
# endif