2014-07-23 16:36:00 +04:00
/*
* 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 .
*
* h3xxx atmel micro companion support , notification LED subdevice
*
* Author : Linus Walleij < linus . walleij @ linaro . org >
*/
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/mfd/ipaq-micro.h>
# include <linux/leds.h>
# define LED_YELLOW 0x00
# define LED_GREEN 0x01
2015-09-07 19:28:29 +03:00
# define LED_EN (1 << 4) /* LED ON/OFF 0:off, 1:on */
# define LED_AUTOSTOP (1 << 5) /* LED ON/OFF auto stop set 0:disable, 1:enable */
# define LED_ALWAYS (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */
2014-07-23 16:36:00 +04:00
2015-11-20 18:47:51 +03:00
static int micro_leds_brightness_set ( struct led_classdev * led_cdev ,
2014-07-23 16:36:00 +04:00
enum led_brightness value )
{
struct ipaq_micro * micro = dev_get_drvdata ( led_cdev - > dev - > parent - > parent ) ;
/*
* In this message :
* Byte 0 = LED color : 0 = yellow , 1 = green
* yellow LED is always ~ 30 blinks per minute
* Byte 1 = duration ( flags ? ) appears to be ignored
* Byte 2 = green ontime in 1 / 10 sec ( deciseconds )
* 1 = 1 / 10 second
* 0 = 256 / 10 second
* Byte 3 = green offtime in 1 / 10 sec ( deciseconds )
* 1 = 1 / 10 second
* 0 = 256 / 10 seconds
*/
struct ipaq_micro_msg msg = {
. id = MSG_NOTIFY_LED ,
. tx_len = 4 ,
} ;
msg . tx_data [ 0 ] = LED_GREEN ;
msg . tx_data [ 1 ] = 0 ;
if ( value ) {
msg . tx_data [ 2 ] = 0 ; /* Duty cycle 256 */
msg . tx_data [ 3 ] = 1 ;
} else {
msg . tx_data [ 2 ] = 1 ;
msg . tx_data [ 3 ] = 0 ; /* Duty cycle 256 */
}
2015-11-20 18:47:51 +03:00
return ipaq_micro_tx_msg_sync ( micro , & msg ) ;
2014-07-23 16:36:00 +04:00
}
/* Maximum duty cycle in ms 256/10 sec = 25600 ms */
# define IPAQ_LED_MAX_DUTY 25600
static int micro_leds_blink_set ( struct led_classdev * led_cdev ,
unsigned long * delay_on ,
unsigned long * delay_off )
{
struct ipaq_micro * micro = dev_get_drvdata ( led_cdev - > dev - > parent - > parent ) ;
/*
* In this message :
* Byte 0 = LED color : 0 = yellow , 1 = green
* yellow LED is always ~ 30 blinks per minute
* Byte 1 = duration ( flags ? ) appears to be ignored
* Byte 2 = green ontime in 1 / 10 sec ( deciseconds )
* 1 = 1 / 10 second
* 0 = 256 / 10 second
* Byte 3 = green offtime in 1 / 10 sec ( deciseconds )
* 1 = 1 / 10 second
* 0 = 256 / 10 seconds
*/
struct ipaq_micro_msg msg = {
. id = MSG_NOTIFY_LED ,
. tx_len = 4 ,
} ;
msg . tx_data [ 0 ] = LED_GREEN ;
2015-09-07 19:28:29 +03:00
if ( * delay_on > IPAQ_LED_MAX_DUTY | |
2014-07-23 16:36:00 +04:00
* delay_off > IPAQ_LED_MAX_DUTY )
2015-09-07 19:28:29 +03:00
return - EINVAL ;
2014-07-23 16:36:00 +04:00
2015-09-07 19:28:29 +03:00
if ( * delay_on = = 0 & & * delay_off = = 0 ) {
* delay_on = 100 ;
* delay_off = 100 ;
}
2014-07-23 16:36:00 +04:00
msg . tx_data [ 1 ] = 0 ;
if ( * delay_on > = IPAQ_LED_MAX_DUTY )
msg . tx_data [ 2 ] = 0 ;
else
msg . tx_data [ 2 ] = ( u8 ) DIV_ROUND_CLOSEST ( * delay_on , 100 ) ;
if ( * delay_off > = IPAQ_LED_MAX_DUTY )
msg . tx_data [ 3 ] = 0 ;
else
msg . tx_data [ 3 ] = ( u8 ) DIV_ROUND_CLOSEST ( * delay_off , 100 ) ;
return ipaq_micro_tx_msg_sync ( micro , & msg ) ;
}
static struct led_classdev micro_led = {
. name = " led-ipaq-micro " ,
2015-11-20 18:47:51 +03:00
. brightness_set_blocking = micro_leds_brightness_set ,
2014-07-23 16:36:00 +04:00
. blink_set = micro_leds_blink_set ,
. flags = LED_CORE_SUSPENDRESUME ,
} ;
static int micro_leds_probe ( struct platform_device * pdev )
{
int ret ;
2015-09-07 17:13:23 +03:00
ret = devm_led_classdev_register ( & pdev - > dev , & micro_led ) ;
2014-07-23 16:36:00 +04:00
if ( ret ) {
dev_err ( & pdev - > dev , " registering led failed: %d \n " , ret ) ;
return ret ;
}
dev_info ( & pdev - > dev , " iPAQ micro notification LED driver \n " ) ;
return 0 ;
}
2014-07-28 17:15:24 +04:00
static struct platform_driver micro_leds_device_driver = {
2014-07-23 16:36:00 +04:00
. driver = {
. name = " ipaq-micro-leds " ,
} ,
. probe = micro_leds_probe ,
} ;
module_platform_driver ( micro_leds_device_driver ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " driver for iPAQ Atmel micro leds " ) ;
MODULE_ALIAS ( " platform:ipaq-micro-leds " ) ;