diff options
Diffstat (limited to 'drivers/leds/leds-88pm860x.c')
| -rw-r--r-- | drivers/leds/leds-88pm860x.c | 119 |
1 files changed, 26 insertions, 93 deletions
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index b7677106cff8..e672b44ee172 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c | |||
| @@ -24,26 +24,17 @@ | |||
| 24 | #define LED_CURRENT_MASK (0x07 << 5) | 24 | #define LED_CURRENT_MASK (0x07 << 5) |
| 25 | 25 | ||
| 26 | #define LED_BLINK_ON_MASK (0x07) | 26 | #define LED_BLINK_ON_MASK (0x07) |
| 27 | #define LED_BLINK_PERIOD_MASK (0x0F << 3) | ||
| 28 | #define LED_BLINK_MASK (0x7F) | 27 | #define LED_BLINK_MASK (0x7F) |
| 29 | 28 | ||
| 30 | #define LED_BLINK_ON(x) ((x & 0x7) * 66 + 66) | 29 | #define LED_BLINK_ON(x) ((x & 0x7) * 66 + 66) |
| 31 | #define LED_BLINK_PERIOD(x) ((x & 0xF) * 530 + 930) | ||
| 32 | #define LED_BLINK_ON_MIN LED_BLINK_ON(0) | 30 | #define LED_BLINK_ON_MIN LED_BLINK_ON(0) |
| 33 | #define LED_BLINK_ON_MAX LED_BLINK_ON(0x7) | 31 | #define LED_BLINK_ON_MAX LED_BLINK_ON(0x7) |
| 34 | #define LED_BLINK_PERIOD_MIN LED_BLINK_PERIOD(0) | 32 | #define LED_ON_CONTINUOUS (0x0F << 3) |
| 35 | #define LED_BLINK_PERIOD_MAX LED_BLINK_PERIOD(0xE) | ||
| 36 | #define LED_TO_ON(x) ((x - 66) / 66) | 33 | #define LED_TO_ON(x) ((x - 66) / 66) |
| 37 | #define LED_TO_PERIOD(x) ((x - 930) / 530) | ||
| 38 | 34 | ||
| 39 | #define LED1_BLINK_EN (1 << 1) | 35 | #define LED1_BLINK_EN (1 << 1) |
| 40 | #define LED2_BLINK_EN (1 << 2) | 36 | #define LED2_BLINK_EN (1 << 2) |
| 41 | 37 | ||
| 42 | enum { | ||
| 43 | SET_BRIGHTNESS, | ||
| 44 | SET_BLINK, | ||
| 45 | }; | ||
| 46 | |||
| 47 | struct pm860x_led { | 38 | struct pm860x_led { |
| 48 | struct led_classdev cdev; | 39 | struct led_classdev cdev; |
| 49 | struct i2c_client *i2c; | 40 | struct i2c_client *i2c; |
| @@ -54,8 +45,6 @@ struct pm860x_led { | |||
| 54 | 45 | ||
| 55 | int port; | 46 | int port; |
| 56 | int iset; | 47 | int iset; |
| 57 | int command; | ||
| 58 | int offset; | ||
| 59 | unsigned char brightness; | 48 | unsigned char brightness; |
| 60 | unsigned char current_brightness; | 49 | unsigned char current_brightness; |
| 61 | 50 | ||
| @@ -95,10 +84,12 @@ static inline int __blink_off(int port) | |||
| 95 | case PM8606_LED1_GREEN: | 84 | case PM8606_LED1_GREEN: |
| 96 | case PM8606_LED1_BLUE: | 85 | case PM8606_LED1_BLUE: |
| 97 | ret = PM8606_RGB1A; | 86 | ret = PM8606_RGB1A; |
| 87 | break; | ||
| 98 | case PM8606_LED2_RED: | 88 | case PM8606_LED2_RED: |
| 99 | case PM8606_LED2_GREEN: | 89 | case PM8606_LED2_GREEN: |
| 100 | case PM8606_LED2_BLUE: | 90 | case PM8606_LED2_BLUE: |
| 101 | ret = PM8606_RGB2A; | 91 | ret = PM8606_RGB2A; |
| 92 | break; | ||
| 102 | } | 93 | } |
| 103 | return ret; | 94 | return ret; |
| 104 | } | 95 | } |
| @@ -122,60 +113,35 @@ static inline int __blink_ctl_mask(int port) | |||
| 122 | return ret; | 113 | return ret; |
| 123 | } | 114 | } |
| 124 | 115 | ||
| 125 | static int __led_set(struct pm860x_led *led, int command) | 116 | static void pm860x_led_work(struct work_struct *work) |
| 126 | { | 117 | { |
| 127 | struct pm860x_chip *chip = led->chip; | ||
| 128 | int mask, ret; | ||
| 129 | 118 | ||
| 119 | struct pm860x_led *led; | ||
| 120 | struct pm860x_chip *chip; | ||
| 121 | int mask; | ||
| 122 | |||
| 123 | led = container_of(work, struct pm860x_led, work); | ||
| 124 | chip = led->chip; | ||
| 130 | mutex_lock(&led->lock); | 125 | mutex_lock(&led->lock); |
| 131 | switch (command) { | 126 | if ((led->current_brightness == 0) && led->brightness) { |
| 132 | case SET_BRIGHTNESS: | 127 | if (led->iset) { |
| 133 | if ((led->current_brightness == 0) && led->brightness) { | 128 | pm860x_set_bits(led->i2c, __led_off(led->port), |
| 134 | if (led->iset) { | 129 | LED_CURRENT_MASK, led->iset); |
| 135 | ret = pm860x_set_bits(led->i2c, led->offset, | ||
| 136 | LED_CURRENT_MASK, led->iset); | ||
| 137 | if (ret < 0) | ||
| 138 | goto out; | ||
| 139 | } | ||
| 140 | } else if (led->brightness == 0) { | ||
| 141 | ret = pm860x_set_bits(led->i2c, led->offset, | ||
| 142 | LED_CURRENT_MASK, 0); | ||
| 143 | if (ret < 0) | ||
| 144 | goto out; | ||
| 145 | } | 130 | } |
| 146 | ret = pm860x_set_bits(led->i2c, led->offset, LED_PWM_MASK, | ||
| 147 | led->brightness); | ||
| 148 | if (ret < 0) | ||
| 149 | goto out; | ||
| 150 | led->current_brightness = led->brightness; | ||
| 151 | dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", | ||
| 152 | led->offset, led->brightness); | ||
| 153 | break; | ||
| 154 | case SET_BLINK: | ||
| 155 | ret = pm860x_set_bits(led->i2c, led->offset, | ||
| 156 | LED_BLINK_MASK, led->blink_data); | ||
| 157 | if (ret < 0) | ||
| 158 | goto out; | ||
| 159 | |||
| 160 | mask = __blink_ctl_mask(led->port); | 131 | mask = __blink_ctl_mask(led->port); |
| 161 | ret = pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); | 132 | pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); |
| 162 | if (ret < 0) | 133 | } else if (led->brightness == 0) { |
| 163 | goto out; | 134 | pm860x_set_bits(led->i2c, __led_off(led->port), |
| 164 | dev_dbg(chip->dev, "LED blink delay on:%dms, delay off:%dms\n", | 135 | LED_CURRENT_MASK, 0); |
| 165 | led->blink_on, led->blink_off); | 136 | mask = __blink_ctl_mask(led->port); |
| 166 | break; | 137 | pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0); |
| 167 | } | 138 | } |
| 168 | out: | 139 | pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK, |
| 140 | led->brightness); | ||
| 141 | led->current_brightness = led->brightness; | ||
| 142 | dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", | ||
| 143 | __led_off(led->port), led->brightness); | ||
| 169 | mutex_unlock(&led->lock); | 144 | mutex_unlock(&led->lock); |
| 170 | return 0; | ||
| 171 | } | ||
| 172 | |||
| 173 | static void pm860x_led_work(struct work_struct *work) | ||
| 174 | { | ||
| 175 | struct pm860x_led *led; | ||
| 176 | |||
| 177 | led = container_of(work, struct pm860x_led, work); | ||
| 178 | __led_set(led, led->command); | ||
| 179 | } | 145 | } |
| 180 | 146 | ||
| 181 | static void pm860x_led_set(struct led_classdev *cdev, | 147 | static void pm860x_led_set(struct led_classdev *cdev, |
| @@ -183,42 +149,10 @@ static void pm860x_led_set(struct led_classdev *cdev, | |||
| 183 | { | 149 | { |
| 184 | struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev); | 150 | struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev); |
| 185 | 151 | ||
| 186 | data->offset = __led_off(data->port); | ||
| 187 | data->brightness = value >> 3; | 152 | data->brightness = value >> 3; |
| 188 | data->command = SET_BRIGHTNESS; | ||
| 189 | schedule_work(&data->work); | 153 | schedule_work(&data->work); |
| 190 | } | 154 | } |
| 191 | 155 | ||
| 192 | static int pm860x_led_blink(struct led_classdev *cdev, | ||
| 193 | unsigned long *delay_on, | ||
| 194 | unsigned long *delay_off) | ||
| 195 | { | ||
| 196 | struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev); | ||
| 197 | int period, on; | ||
| 198 | |||
| 199 | on = *delay_on; | ||
| 200 | if ((on < LED_BLINK_ON_MIN) || (on > LED_BLINK_ON_MAX)) | ||
| 201 | return -EINVAL; | ||
| 202 | |||
| 203 | on = LED_TO_ON(on); | ||
| 204 | on = LED_BLINK_ON(on); | ||
| 205 | |||
| 206 | period = on + *delay_off; | ||
| 207 | if ((period < LED_BLINK_PERIOD_MIN) || (period > LED_BLINK_PERIOD_MAX)) | ||
| 208 | return -EINVAL; | ||
| 209 | period = LED_TO_PERIOD(period); | ||
| 210 | period = LED_BLINK_PERIOD(period); | ||
| 211 | |||
| 212 | data->offset = __blink_off(data->port); | ||
| 213 | data->blink_on = on; | ||
| 214 | data->blink_off = period - data->blink_on; | ||
| 215 | data->blink_data = (period << 3) | data->blink_on; | ||
| 216 | data->command = SET_BLINK; | ||
| 217 | schedule_work(&data->work); | ||
| 218 | |||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | |||
| 222 | static int __check_device(struct pm860x_led_pdata *pdata, char *name) | 156 | static int __check_device(struct pm860x_led_pdata *pdata, char *name) |
| 223 | { | 157 | { |
| 224 | struct pm860x_led_pdata *p = pdata; | 158 | struct pm860x_led_pdata *p = pdata; |
| @@ -257,7 +191,7 @@ static int pm860x_led_probe(struct platform_device *pdev) | |||
| 257 | pm860x_pdata = pdev->dev.parent->platform_data; | 191 | pm860x_pdata = pdev->dev.parent->platform_data; |
| 258 | pdata = pm860x_pdata->led; | 192 | pdata = pm860x_pdata->led; |
| 259 | } else { | 193 | } else { |
| 260 | dev_err(&pdev->dev, "missing platform data\n"); | 194 | dev_err(&pdev->dev, "No platform data!\n"); |
| 261 | return -EINVAL; | 195 | return -EINVAL; |
| 262 | } | 196 | } |
| 263 | 197 | ||
| @@ -279,7 +213,6 @@ static int pm860x_led_probe(struct platform_device *pdev) | |||
| 279 | data->current_brightness = 0; | 213 | data->current_brightness = 0; |
| 280 | data->cdev.name = data->name; | 214 | data->cdev.name = data->name; |
| 281 | data->cdev.brightness_set = pm860x_led_set; | 215 | data->cdev.brightness_set = pm860x_led_set; |
| 282 | data->cdev.blink_set = pm860x_led_blink; | ||
| 283 | mutex_init(&data->lock); | 216 | mutex_init(&data->lock); |
| 284 | INIT_WORK(&data->work, pm860x_led_work); | 217 | INIT_WORK(&data->work, pm860x_led_work); |
| 285 | 218 | ||
