diff options
Diffstat (limited to 'drivers')
-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 | ||