2009-03-21 23:05:13 +01:00
/*
* Atheros AR9170 driver
*
* LED handling
*
* Copyright 2008 , Johannes Berg < johannes @ sipsolutions . net >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; see the file COPYING . If not , see
* http : //www.gnu.org/licenses/.
*
* This file incorporates work covered by the following copyright and
* permission notice :
* Copyright ( c ) 2007 - 2008 Atheros Communications , Inc .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*/
# include "ar9170.h"
# include "cmd.h"
int ar9170_set_leds_state ( struct ar9170 * ar , u32 led_state )
{
return ar9170_write_reg ( ar , AR9170_GPIO_REG_DATA , led_state ) ;
}
int ar9170_init_leds ( struct ar9170 * ar )
{
int err ;
/* disable LEDs */
/* GPIO [0/1 mode: output, 2/3: input] */
err = ar9170_write_reg ( ar , AR9170_GPIO_REG_PORT_TYPE , 3 ) ;
if ( err )
goto out ;
/* GPIO 0/1 value: off */
err = ar9170_set_leds_state ( ar , 0 ) ;
out :
return err ;
}
# ifdef CONFIG_AR9170_LEDS
static void ar9170_update_leds ( struct work_struct * work )
{
struct ar9170 * ar = container_of ( work , struct ar9170 , led_work . work ) ;
int i , tmp , blink_delay = 1000 ;
u32 led_val = 0 ;
bool rerun = false ;
if ( unlikely ( ! IS_ACCEPTING_CMD ( ar ) ) )
return ;
mutex_lock ( & ar - > mutex ) ;
for ( i = 0 ; i < AR9170_NUM_LEDS ; i + + )
2009-06-01 22:49:25 +02:00
if ( ar - > leds [ i ] . registered & & ar - > leds [ i ] . toggled ) {
2009-03-21 23:05:13 +01:00
led_val | = 1 < < i ;
tmp = 70 + 200 / ( ar - > leds [ i ] . toggled ) ;
if ( tmp < blink_delay )
blink_delay = tmp ;
if ( ar - > leds [ i ] . toggled > 1 )
ar - > leds [ i ] . toggled = 0 ;
rerun = true ;
}
ar9170_set_leds_state ( ar , led_val ) ;
mutex_unlock ( & ar - > mutex ) ;
2009-07-29 20:08:07 -04:00
if ( ! rerun )
return ;
ieee80211_queue_delayed_work ( ar - > hw ,
& ar - > led_work ,
msecs_to_jiffies ( blink_delay ) ) ;
2009-03-21 23:05:13 +01:00
}
static void ar9170_led_brightness_set ( struct led_classdev * led ,
enum led_brightness brightness )
{
struct ar9170_led * arl = container_of ( led , struct ar9170_led , l ) ;
struct ar9170 * ar = arl - > ar ;
2009-06-01 22:49:25 +02:00
if ( unlikely ( ! arl - > registered ) )
return ;
2009-05-25 21:51:19 +02:00
if ( arl - > last_state ! = ! ! brightness ) {
arl - > toggled + + ;
arl - > last_state = ! ! brightness ;
}
2009-03-21 23:05:13 +01:00
2009-05-25 21:51:19 +02:00
if ( likely ( IS_ACCEPTING_CMD ( ar ) & & arl - > toggled ) )
2009-07-29 20:08:07 -04:00
ieee80211_queue_delayed_work ( ar - > hw , & ar - > led_work , HZ / 10 ) ;
2009-03-21 23:05:13 +01:00
}
static int ar9170_register_led ( struct ar9170 * ar , int i , char * name ,
char * trigger )
{
int err ;
snprintf ( ar - > leds [ i ] . name , sizeof ( ar - > leds [ i ] . name ) ,
" ar9170-%s::%s " , wiphy_name ( ar - > hw - > wiphy ) , name ) ;
ar - > leds [ i ] . ar = ar ;
ar - > leds [ i ] . l . name = ar - > leds [ i ] . name ;
ar - > leds [ i ] . l . brightness_set = ar9170_led_brightness_set ;
ar - > leds [ i ] . l . brightness = 0 ;
ar - > leds [ i ] . l . default_trigger = trigger ;
err = led_classdev_register ( wiphy_dev ( ar - > hw - > wiphy ) ,
& ar - > leds [ i ] . l ) ;
if ( err )
2010-07-26 14:39:58 -07:00
wiphy_err ( ar - > hw - > wiphy , " failed to register %s LED (%d). \n " ,
ar - > leds [ i ] . name , err ) ;
2009-03-21 23:05:13 +01:00
else
ar - > leds [ i ] . registered = true ;
return err ;
}
void ar9170_unregister_leds ( struct ar9170 * ar )
{
int i ;
for ( i = 0 ; i < AR9170_NUM_LEDS ; i + + )
if ( ar - > leds [ i ] . registered ) {
led_classdev_unregister ( & ar - > leds [ i ] . l ) ;
ar - > leds [ i ] . registered = false ;
2009-06-01 22:49:25 +02:00
ar - > leds [ i ] . toggled = 0 ;
2009-03-21 23:05:13 +01:00
}
2009-06-01 22:49:25 +02:00
cancel_delayed_work_sync ( & ar - > led_work ) ;
2009-03-21 23:05:13 +01:00
}
int ar9170_register_leds ( struct ar9170 * ar )
{
int err ;
INIT_DELAYED_WORK ( & ar - > led_work , ar9170_update_leds ) ;
err = ar9170_register_led ( ar , 0 , " tx " ,
ieee80211_get_tx_led_name ( ar - > hw ) ) ;
if ( err )
goto fail ;
err = ar9170_register_led ( ar , 1 , " assoc " ,
ieee80211_get_assoc_led_name ( ar - > hw ) ) ;
if ( err )
goto fail ;
return 0 ;
fail :
ar9170_unregister_leds ( ar ) ;
return err ;
}
# endif /* CONFIG_AR9170_LEDS */