Commit a59ce6584d566847980f9dcad5343cd9856145c8

Authored by Alexander Shiyan
Committed by Bryan Wu
1 parent 8d82fef8bb

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