@ -20,18 +20,12 @@
# include <linux/mfd/88pm860x.h>
# include <linux/module.h>
# define LED_PWM_SHIFT (3)
# define LED_PWM_MASK (0x1F)
# define LED_CURRENT_MASK (0x07 << 5)
# define LED_BLINK_ON_MASK (0x07)
# define LED_BLINK_MASK (0x7F)
# define LED_BLINK_ON(x) ((x & 0x7) * 66 + 66)
# define LED_BLINK_ON_MIN LED_BLINK_ON(0)
# define LED_BLINK_ON_MAX LED_BLINK_ON(0x7)
# define LED_ON_CONTINUOUS (0x0F << 3)
# define LED_TO_ON(x) ((x - 66) / 66)
# define LED1_BLINK_EN (1 << 1)
# define LED2_BLINK_EN (1 << 2)
@ -49,85 +43,25 @@ struct pm860x_led {
unsigned char brightness ;
unsigned char current_brightness ;
int blink_data ;
int blink_time ;
int blink_on ;
int blink_off ;
int reg_control ;
int reg_blink ;
int blink_mask ;
} ;
/* return offset of color register */
static inline int __led_off ( int port )
{
int ret = - EINVAL ;
switch ( port ) {
case PM8606_LED1_RED :
case PM8606_LED1_GREEN :
case PM8606_LED1_BLUE :
ret = port - PM8606_LED1_RED + PM8606_RGB1B ;
break ;
case PM8606_LED2_RED :
case PM8606_LED2_GREEN :
case PM8606_LED2_BLUE :
ret = port - PM8606_LED2_RED + PM8606_RGB2B ;
break ;
}
return ret ;
}
/* return offset of blink register */
static inline int __blink_off ( int port )
{
int ret = - EINVAL ;
switch ( port ) {
case PM8606_LED1_RED :
case PM8606_LED1_GREEN :
case PM8606_LED1_BLUE :
ret = PM8606_RGB1A ;
break ;
case PM8606_LED2_RED :
case PM8606_LED2_GREEN :
case PM8606_LED2_BLUE :
ret = PM8606_RGB2A ;
break ;
}
return ret ;
}
static inline int __blink_ctl_mask ( int port )
{
int ret = - EINVAL ;
switch ( port ) {
case PM8606_LED1_RED :
case PM8606_LED1_GREEN :
case PM8606_LED1_BLUE :
ret = LED1_BLINK_EN ;
break ;
case PM8606_LED2_RED :
case PM8606_LED2_GREEN :
case PM8606_LED2_BLUE :
ret = LED2_BLINK_EN ;
break ;
}
return ret ;
}
static int led_power_set ( struct pm860x_chip * chip , int port , int on )
{
int ret = - EINVAL ;
switch ( port ) {
case PM8606_LED1_RED :
case PM8606_LED1_GREEN :
case PM8606_LED1_BLUE :
case 0 :
case 1 :
case 2 :
ret = on ? pm8606_osc_enable ( chip , RGB1_ENABLE ) :
pm8606_osc_disable ( chip , RGB1_ENABLE ) ;
break ;
case PM8606_LED2_RED :
case PM8606_LED2_GREEN :
case PM8606_LED2_BLUE :
case 3 :
case 4 :
case 5 :
ret = on ? pm8606_osc_enable ( chip , RGB2_ENABLE ) :
pm8606_osc_disable ( chip , RGB2_ENABLE ) ;
break ;
@ -141,7 +75,7 @@ static void pm860x_led_work(struct work_struct *work)
struct pm860x_led * led ;
struct pm860x_chip * chip ;
unsigned char buf [ 3 ] ;
int mask , ret ;
int ret ;
led = container_of ( work , struct pm860x_led , work ) ;
chip = led - > chip ;
@ -149,34 +83,34 @@ static void pm860x_led_work(struct work_struct *work)
if ( ( led - > current_brightness = = 0 ) & & led - > brightness ) {
led_power_set ( chip , led - > port , 1 ) ;
if ( led - > iset ) {
pm860x_set_bits ( led - > i2c , __led_off ( led - > port ) ,
pm860x_set_bits ( led - > i2c , led - > reg_control ,
LED_CURRENT_MASK , led - > iset ) ;
}
pm860x_set_bits ( led - > i2c , __blink_off ( led - > port ) ,
pm860x_set_bits ( led - > i2c , led - > reg_blink ,
LED_BLINK_MASK , LED_ON_CONTINUOUS ) ;
mask = __blink_ctl_mask ( led - > port ) ;
pm860x_set_bits ( led - > i2c , PM8606_WLED3B , mask , mask ) ;
pm860x_set_bits ( led - > i2c , PM8606_WLED3B , led - > blink_mask ,
led - > blink_ mask ) ;
}
pm860x_set_bits ( led - > i2c , __led_off ( led - > port ) , LED_PWM_MASK ,
pm860x_set_bits ( led - > i2c , led - > reg_control , LED_PWM_MASK ,
led - > brightness ) ;
if ( led - > brightness = = 0 ) {
pm860x_bulk_read ( led - > i2c , __led_off ( led - > port ) , 3 , buf ) ;
pm860x_bulk_read ( led - > i2c , led - > reg_control , 3 , buf ) ;
ret = buf [ 0 ] & LED_PWM_MASK ;
ret | = buf [ 1 ] & LED_PWM_MASK ;
ret | = buf [ 2 ] & LED_PWM_MASK ;
if ( ret = = 0 ) {
/* unset current since no led is lighting */
pm860x_set_bits ( led - > i2c , __led_off ( led - > port ) ,
pm860x_set_bits ( led - > i2c , led - > reg_control ,
LED_CURRENT_MASK , 0 ) ;
mask = __blink_ctl_mask ( led - > port ) ;
pm860x_set_bits ( led - > i2c , PM8606_WLED3B , mask , 0 ) ;
pm860x_set_bits ( led - > i2c , PM8606_WLED3B ,
led - > blink_ mask , 0 ) ;
led_power_set ( chip , led - > port , 0 ) ;
}
}
led - > current_brightness = led - > brightness ;
dev_dbg ( chip - > dev , " Update LED. (reg:%d, brightness:%d) \n " ,
__led_off ( led - > port ) , led - > brightness ) ;
led - > reg_control , led - > brightness ) ;
mutex_unlock ( & led - > lock ) ;
}
@ -192,36 +126,61 @@ static void pm860x_led_set(struct led_classdev *cdev,
static int pm860x_led_probe ( struct platform_device * pdev )
{
struct pm860x_chip * chip = dev_get_drvdata ( pdev - > dev . parent ) ;
struct pm860x_led_pdata * pdata ;
struct pm860x_led_pdata * pdata = pdev - > dev . platform_data ;
struct pm860x_led * data ;
struct resource * res ;
int ret ;
res = platform_get_resource ( pdev , IORESOURCE_REG , 0 ) ;
if ( res = = NULL ) {
dev_err ( & pdev - > dev , " No I/O resource! \n " ) ;
return - EINVAL ;
}
pdata = pdev - > dev . platform_data ;
if ( pdata = = NULL ) {
dev_err ( & pdev - > dev , " No platform data! \n " ) ;
return - EINVAL ;
}
int ret = 0 ;
data = devm_kzalloc ( & pdev - > dev , sizeof ( struct pm860x_led ) , GFP_KERNEL ) ;
if ( data = = NULL )
return - ENOMEM ;
strncpy ( data - > name , res - > name , MFD_NAME_SIZE - 1 ) ;
res = platform_get_resource_byname ( pdev , IORESOURCE_REG , " control " ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " No REG resource for control \n " ) ;
ret = - ENXIO ;
goto out ;
}
data - > reg_control = res - > start ;
res = platform_get_resource_byname ( pdev , IORESOURCE_REG , " blink " ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " No REG resource for blink \n " ) ;
ret = - ENXIO ;
goto out ;
}
data - > reg_blink = res - > start ;
memset ( data - > name , 0 , MFD_NAME_SIZE ) ;
switch ( pdev - > id ) {
case 0 :
data - > blink_mask = LED1_BLINK_EN ;
sprintf ( data - > name , " led0-red " ) ;
break ;
case 1 :
data - > blink_mask = LED1_BLINK_EN ;
sprintf ( data - > name , " led0-green " ) ;
break ;
case 2 :
data - > blink_mask = LED1_BLINK_EN ;
sprintf ( data - > name , " led0-blue " ) ;
break ;
case 3 :
data - > blink_mask = LED2_BLINK_EN ;
sprintf ( data - > name , " led1-red " ) ;
break ;
case 4 :
data - > blink_mask = LED2_BLINK_EN ;
sprintf ( data - > name , " led1-green " ) ;
break ;
case 5 :
data - > blink_mask = LED2_BLINK_EN ;
sprintf ( data - > name , " led1-blue " ) ;
break ;
}
dev_set_drvdata ( & pdev - > dev , data ) ;
data - > chip = chip ;
data - > i2c = ( chip - > id = = CHIP_PM8606 ) ? chip - > client : chip - > companion ;
data - > iset = pdata - > iset ;
data - > port = pdata - > flags ;
if ( data - > port < 0 ) {
dev_err ( & pdev - > dev , " check device failed \n " ) ;
return - EINVAL ;
}
data - > port = pdev - > id ;
if ( pdata & & pdata - > iset )
data - > iset = pdata - > iset ;
data - > current_brightness = 0 ;
data - > cdev . name = data - > name ;
@ -236,6 +195,9 @@ static int pm860x_led_probe(struct platform_device *pdev)
}
pm860x_led_set ( & data - > cdev , 0 ) ;
return 0 ;
out :
devm_kfree ( & pdev - > dev , data ) ;
return ret ;
}
static int pm860x_led_remove ( struct platform_device * pdev )