Commit a59ce6584d566847980f9dcad5343cd9856145c8
Committed by
Bryan Wu
1 parent
8d82fef8bb
Exists in
master
and in
13 other branches
leds: leds-mc13783: Add MC34708 LED support
This patch adds support for two LEDs on MC34708 PMIC. Signed-off-by: Alexander Shiyan <shc_work@mail.ru> Signed-off-by: Bryan Wu <cooloney@gmail.com>
Showing 3 changed files with 55 additions and 51 deletions Side-by-side Diff
drivers/leds/Kconfig
... | ... | @@ -416,7 +416,7 @@ |
416 | 416 | depends on MFD_MC13XXX |
417 | 417 | help |
418 | 418 | This option enable support for on-chip LED drivers found |
419 | - on Freescale Semiconductor MC13783/MC13892 PMIC. | |
419 | + on Freescale Semiconductor MC13783/MC13892/MC34708 PMIC. | |
420 | 420 | |
421 | 421 | config LEDS_NS2 |
422 | 422 | tristate "LED support for Network Space v2 GPIO LEDs" |
drivers/leds/leds-mc13783.c
1 | 1 | /* |
2 | - * LEDs driver for Freescale MC13783/MC13892 | |
2 | + * LEDs driver for Freescale MC13783/MC13892/MC34708 | |
3 | 3 | * |
4 | 4 | * Copyright (C) 2010 Philippe Rétornaz |
5 | 5 | * |
6 | 6 | |
7 | 7 | |
8 | 8 | |
9 | 9 | |
... | ... | @@ -23,23 +23,23 @@ |
23 | 23 | #include <linux/workqueue.h> |
24 | 24 | #include <linux/mfd/mc13xxx.h> |
25 | 25 | |
26 | -#define MC13XXX_REG_LED_CONTROL(x) (51 + (x)) | |
27 | - | |
28 | 26 | struct mc13xxx_led_devtype { |
29 | 27 | int led_min; |
30 | 28 | int led_max; |
31 | 29 | int num_regs; |
30 | + u32 ledctrl_base; | |
32 | 31 | }; |
33 | 32 | |
34 | 33 | struct mc13xxx_led { |
35 | 34 | struct led_classdev cdev; |
36 | 35 | struct work_struct work; |
37 | - struct mc13xxx *master; | |
38 | 36 | enum led_brightness new_brightness; |
39 | 37 | int id; |
38 | + struct mc13xxx_leds *leds; | |
40 | 39 | }; |
41 | 40 | |
42 | 41 | struct mc13xxx_leds { |
42 | + struct mc13xxx *master; | |
43 | 43 | struct mc13xxx_led_devtype *devtype; |
44 | 44 | int num_leds; |
45 | 45 | struct mc13xxx_led led[0]; |
46 | 46 | |
47 | 47 | |
48 | 48 | |
... | ... | @@ -48,24 +48,15 @@ |
48 | 48 | static void mc13xxx_led_work(struct work_struct *work) |
49 | 49 | { |
50 | 50 | struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work); |
51 | - int reg, mask, value, bank, off, shift; | |
51 | + struct mc13xxx_leds *leds = led->leds; | |
52 | + unsigned int reg, mask, value, bank, off, shift; | |
52 | 53 | |
53 | 54 | switch (led->id) { |
54 | 55 | case MC13783_LED_MD: |
55 | - reg = MC13XXX_REG_LED_CONTROL(2); | |
56 | - shift = 9; | |
57 | - mask = 0x0f; | |
58 | - value = led->new_brightness >> 4; | |
59 | - break; | |
60 | 56 | case MC13783_LED_AD: |
61 | - reg = MC13XXX_REG_LED_CONTROL(2); | |
62 | - shift = 13; | |
63 | - mask = 0x0f; | |
64 | - value = led->new_brightness >> 4; | |
65 | - break; | |
66 | 57 | case MC13783_LED_KP: |
67 | - reg = MC13XXX_REG_LED_CONTROL(2); | |
68 | - shift = 17; | |
58 | + reg = 2; | |
59 | + shift = 9 + (led->id - MC13783_LED_MD) * 4; | |
69 | 60 | mask = 0x0f; |
70 | 61 | value = led->new_brightness >> 4; |
71 | 62 | break; |
72 | 63 | |
73 | 64 | |
74 | 65 | |
... | ... | @@ -80,26 +71,16 @@ |
80 | 71 | case MC13783_LED_B3: |
81 | 72 | off = led->id - MC13783_LED_R1; |
82 | 73 | bank = off / 3; |
83 | - reg = MC13XXX_REG_LED_CONTROL(3) + bank; | |
74 | + reg = 3 + bank; | |
84 | 75 | shift = (off - bank * 3) * 5 + 6; |
85 | 76 | value = led->new_brightness >> 3; |
86 | 77 | mask = 0x1f; |
87 | 78 | break; |
88 | 79 | case MC13892_LED_MD: |
89 | - reg = MC13XXX_REG_LED_CONTROL(0); | |
90 | - shift = 3; | |
91 | - mask = 0x3f; | |
92 | - value = led->new_brightness >> 2; | |
93 | - break; | |
94 | 80 | case MC13892_LED_AD: |
95 | - reg = MC13XXX_REG_LED_CONTROL(0); | |
96 | - shift = 15; | |
97 | - mask = 0x3f; | |
98 | - value = led->new_brightness >> 2; | |
99 | - break; | |
100 | 81 | case MC13892_LED_KP: |
101 | - reg = MC13XXX_REG_LED_CONTROL(1); | |
102 | - shift = 3; | |
82 | + reg = (led->id - MC13892_LED_MD) / 2; | |
83 | + shift = 3 + (led->id - MC13892_LED_MD) * 12; | |
103 | 84 | mask = 0x3f; |
104 | 85 | value = led->new_brightness >> 2; |
105 | 86 | break; |
106 | 87 | |
107 | 88 | |
... | ... | @@ -108,16 +89,24 @@ |
108 | 89 | case MC13892_LED_B: |
109 | 90 | off = led->id - MC13892_LED_R; |
110 | 91 | bank = off / 2; |
111 | - reg = MC13XXX_REG_LED_CONTROL(2) + bank; | |
92 | + reg = 2 + bank; | |
112 | 93 | shift = (off - bank * 2) * 12 + 3; |
113 | 94 | value = led->new_brightness >> 2; |
114 | 95 | mask = 0x3f; |
115 | 96 | break; |
97 | + case MC34708_LED_R: | |
98 | + case MC34708_LED_G: | |
99 | + reg = 0; | |
100 | + shift = 3 + (led->id - MC34708_LED_R) * 12; | |
101 | + value = led->new_brightness >> 2; | |
102 | + mask = 0x3f; | |
103 | + break; | |
116 | 104 | default: |
117 | 105 | BUG(); |
118 | 106 | } |
119 | 107 | |
120 | - mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift); | |
108 | + mc13xxx_reg_rmw(leds->master, leds->devtype->ledctrl_base + reg, | |
109 | + mask << shift, value << shift); | |
121 | 110 | } |
122 | 111 | |
123 | 112 | static void mc13xxx_led_set(struct led_classdev *led_cdev, |
124 | 113 | |
125 | 114 | |
... | ... | @@ -132,16 +121,17 @@ |
132 | 121 | |
133 | 122 | static int __init mc13xxx_led_probe(struct platform_device *pdev) |
134 | 123 | { |
135 | - struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); | |
136 | - struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent); | |
124 | + struct device *dev = &pdev->dev; | |
125 | + struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(dev); | |
126 | + struct mc13xxx *mcdev = dev_get_drvdata(dev->parent); | |
137 | 127 | struct mc13xxx_led_devtype *devtype = |
138 | 128 | (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data; |
139 | 129 | struct mc13xxx_leds *leds; |
140 | 130 | int i, id, num_leds, ret = -ENODATA; |
141 | - u32 reg, init_led = 0; | |
131 | + u32 init_led = 0; | |
142 | 132 | |
143 | 133 | if (!pdata) { |
144 | - dev_err(&pdev->dev, "Missing platform data\n"); | |
134 | + dev_err(dev, "Missing platform data\n"); | |
145 | 135 | return -ENODEV; |
146 | 136 | } |
147 | 137 | |
148 | 138 | |
149 | 139 | |
150 | 140 | |
... | ... | @@ -149,23 +139,23 @@ |
149 | 139 | |
150 | 140 | if ((num_leds < 1) || |
151 | 141 | (num_leds > (devtype->led_max - devtype->led_min + 1))) { |
152 | - dev_err(&pdev->dev, "Invalid LED count %d\n", num_leds); | |
142 | + dev_err(dev, "Invalid LED count %d\n", num_leds); | |
153 | 143 | return -EINVAL; |
154 | 144 | } |
155 | 145 | |
156 | - leds = devm_kzalloc(&pdev->dev, num_leds * sizeof(struct mc13xxx_led) + | |
146 | + leds = devm_kzalloc(dev, num_leds * sizeof(struct mc13xxx_led) + | |
157 | 147 | sizeof(struct mc13xxx_leds), GFP_KERNEL); |
158 | 148 | if (!leds) |
159 | 149 | return -ENOMEM; |
160 | 150 | |
161 | 151 | leds->devtype = devtype; |
162 | 152 | leds->num_leds = num_leds; |
153 | + leds->master = mcdev; | |
163 | 154 | platform_set_drvdata(pdev, leds); |
164 | 155 | |
165 | 156 | for (i = 0; i < devtype->num_regs; i++) { |
166 | - reg = pdata->led_control[i]; | |
167 | - WARN_ON(reg >= (1 << 24)); | |
168 | - ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg); | |
157 | + ret = mc13xxx_reg_write(mcdev, leds->devtype->ledctrl_base + i, | |
158 | + pdata->led_control[i]); | |
169 | 159 | if (ret) |
170 | 160 | return ret; |
171 | 161 | } |
172 | 162 | |
173 | 163 | |
... | ... | @@ -180,19 +170,18 @@ |
180 | 170 | trig = pdata->led[i].default_trigger; |
181 | 171 | |
182 | 172 | if ((id > devtype->led_max) || (id < devtype->led_min)) { |
183 | - dev_err(&pdev->dev, "Invalid ID %i\n", id); | |
173 | + dev_err(dev, "Invalid ID %i\n", id); | |
184 | 174 | break; |
185 | 175 | } |
186 | 176 | |
187 | 177 | if (init_led & (1 << id)) { |
188 | - dev_warn(&pdev->dev, | |
189 | - "LED %i already initialized\n", id); | |
178 | + dev_warn(dev, "LED %i already initialized\n", id); | |
190 | 179 | break; |
191 | 180 | } |
192 | 181 | |
193 | 182 | init_led |= 1 << id; |
194 | 183 | leds->led[i].id = id; |
195 | - leds->led[i].master = mcdev; | |
184 | + leds->led[i].leds = leds; | |
196 | 185 | leds->led[i].cdev.name = name; |
197 | 186 | leds->led[i].cdev.default_trigger = trig; |
198 | 187 | leds->led[i].cdev.brightness_set = mc13xxx_led_set; |
199 | 188 | |
... | ... | @@ -200,10 +189,9 @@ |
200 | 189 | |
201 | 190 | INIT_WORK(&leds->led[i].work, mc13xxx_led_work); |
202 | 191 | |
203 | - ret = led_classdev_register(pdev->dev.parent, | |
204 | - &leds->led[i].cdev); | |
192 | + ret = led_classdev_register(dev->parent, &leds->led[i].cdev); | |
205 | 193 | if (ret) { |
206 | - dev_err(&pdev->dev, "Failed to register LED %i\n", id); | |
194 | + dev_err(dev, "Failed to register LED %i\n", id); | |
207 | 195 | break; |
208 | 196 | } |
209 | 197 | } |
210 | 198 | |
... | ... | @@ -219,8 +207,8 @@ |
219 | 207 | |
220 | 208 | static int mc13xxx_led_remove(struct platform_device *pdev) |
221 | 209 | { |
222 | - struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent); | |
223 | 210 | struct mc13xxx_leds *leds = platform_get_drvdata(pdev); |
211 | + struct mc13xxx *mcdev = leds->master; | |
224 | 212 | int i; |
225 | 213 | |
226 | 214 | for (i = 0; i < leds->num_leds; i++) { |
... | ... | @@ -229,7 +217,7 @@ |
229 | 217 | } |
230 | 218 | |
231 | 219 | for (i = 0; i < leds->devtype->num_regs; i++) |
232 | - mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0); | |
220 | + mc13xxx_reg_write(mcdev, leds->devtype->ledctrl_base + i, 0); | |
233 | 221 | |
234 | 222 | return 0; |
235 | 223 | } |
236 | 224 | |
237 | 225 | |
238 | 226 | |
... | ... | @@ -238,17 +226,27 @@ |
238 | 226 | .led_min = MC13783_LED_MD, |
239 | 227 | .led_max = MC13783_LED_B3, |
240 | 228 | .num_regs = 6, |
229 | + .ledctrl_base = 51, | |
241 | 230 | }; |
242 | 231 | |
243 | 232 | static const struct mc13xxx_led_devtype mc13892_led_devtype = { |
244 | 233 | .led_min = MC13892_LED_MD, |
245 | 234 | .led_max = MC13892_LED_B, |
246 | 235 | .num_regs = 4, |
236 | + .ledctrl_base = 51, | |
247 | 237 | }; |
248 | 238 | |
239 | +static const struct mc13xxx_led_devtype mc34708_led_devtype = { | |
240 | + .led_min = MC34708_LED_R, | |
241 | + .led_max = MC34708_LED_G, | |
242 | + .num_regs = 1, | |
243 | + .ledctrl_base = 54, | |
244 | +}; | |
245 | + | |
249 | 246 | static const struct platform_device_id mc13xxx_led_id_table[] = { |
250 | 247 | { "mc13783-led", (kernel_ulong_t)&mc13783_led_devtype, }, |
251 | 248 | { "mc13892-led", (kernel_ulong_t)&mc13892_led_devtype, }, |
249 | + { "mc34708-led", (kernel_ulong_t)&mc34708_led_devtype, }, | |
252 | 250 | { } |
253 | 251 | }; |
254 | 252 | MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table); |
include/linux/mfd/mc13xxx.h
... | ... | @@ -104,6 +104,9 @@ |
104 | 104 | MC13892_LED_R, |
105 | 105 | MC13892_LED_G, |
106 | 106 | MC13892_LED_B, |
107 | + /* MC34708 LED IDs */ | |
108 | + MC34708_LED_R, | |
109 | + MC34708_LED_G, | |
107 | 110 | }; |
108 | 111 | |
109 | 112 | struct mc13xxx_led_platform_data { |
... | ... | @@ -163,6 +166,9 @@ |
163 | 166 | #define MC13892_LED_C2_CURRENT_G(x) (((x) & 0x7) << 21) |
164 | 167 | /* MC13892 LED Control 3 */ |
165 | 168 | #define MC13892_LED_C3_CURRENT_B(x) (((x) & 0x7) << 9) |
169 | +/* MC34708 LED Control 0 */ | |
170 | +#define MC34708_LED_C0_CURRENT_R(x) (((x) & 0x3) << 9) | |
171 | +#define MC34708_LED_C0_CURRENT_G(x) (((x) & 0x3) << 21) | |
166 | 172 | u32 led_control[MAX_LED_CONTROL_REGS]; |
167 | 173 | }; |
168 | 174 |