aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
authorAlexander Shiyan <shc_work@mail.ru>2014-02-01 01:36:28 -0500
committerBryan Wu <cooloney@gmail.com>2014-02-27 12:56:55 -0500
commita59ce6584d566847980f9dcad5343cd9856145c8 (patch)
tree5d940cf8bb5bc9489350243cb689375316997def /drivers/leds
parent8d82fef8bbee588d071372eb02439d2053b4bfe4 (diff)
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>
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig2
-rw-r--r--drivers/leds/leds-mc13783.c98
2 files changed, 49 insertions, 51 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 72156c123033..93466d215706 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -416,7 +416,7 @@ config LEDS_MC13783
416 depends on MFD_MC13XXX 416 depends on MFD_MC13XXX
417 help 417 help
418 This option enable support for on-chip LED drivers found 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
421config LEDS_NS2 421config LEDS_NS2
422 tristate "LED support for Network Space v2 GPIO LEDs" 422 tristate "LED support for Network Space v2 GPIO LEDs"
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c
index ca87a1b4a0db..68f2455c672f 100644
--- a/drivers/leds/leds-mc13783.c
+++ b/drivers/leds/leds-mc13783.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * LEDs driver for Freescale MC13783/MC13892 2 * LEDs driver for Freescale MC13783/MC13892/MC34708
3 * 3 *
4 * Copyright (C) 2010 Philippe Rétornaz 4 * Copyright (C) 2010 Philippe Rétornaz
5 * 5 *
@@ -23,23 +23,23 @@
23#include <linux/workqueue.h> 23#include <linux/workqueue.h>
24#include <linux/mfd/mc13xxx.h> 24#include <linux/mfd/mc13xxx.h>
25 25
26#define MC13XXX_REG_LED_CONTROL(x) (51 + (x))
27
28struct mc13xxx_led_devtype { 26struct mc13xxx_led_devtype {
29 int led_min; 27 int led_min;
30 int led_max; 28 int led_max;
31 int num_regs; 29 int num_regs;
30 u32 ledctrl_base;
32}; 31};
33 32
34struct mc13xxx_led { 33struct mc13xxx_led {
35 struct led_classdev cdev; 34 struct led_classdev cdev;
36 struct work_struct work; 35 struct work_struct work;
37 struct mc13xxx *master;
38 enum led_brightness new_brightness; 36 enum led_brightness new_brightness;
39 int id; 37 int id;
38 struct mc13xxx_leds *leds;
40}; 39};
41 40
42struct mc13xxx_leds { 41struct mc13xxx_leds {
42 struct mc13xxx *master;
43 struct mc13xxx_led_devtype *devtype; 43 struct mc13xxx_led_devtype *devtype;
44 int num_leds; 44 int num_leds;
45 struct mc13xxx_led led[0]; 45 struct mc13xxx_led led[0];
@@ -48,24 +48,15 @@ struct mc13xxx_leds {
48static void mc13xxx_led_work(struct work_struct *work) 48static void mc13xxx_led_work(struct work_struct *work)
49{ 49{
50 struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work); 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 switch (led->id) { 54 switch (led->id) {
54 case MC13783_LED_MD: 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 case MC13783_LED_AD: 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 case MC13783_LED_KP: 57 case MC13783_LED_KP:
67 reg = MC13XXX_REG_LED_CONTROL(2); 58 reg = 2;
68 shift = 17; 59 shift = 9 + (led->id - MC13783_LED_MD) * 4;
69 mask = 0x0f; 60 mask = 0x0f;
70 value = led->new_brightness >> 4; 61 value = led->new_brightness >> 4;
71 break; 62 break;
@@ -80,26 +71,16 @@ static void mc13xxx_led_work(struct work_struct *work)
80 case MC13783_LED_B3: 71 case MC13783_LED_B3:
81 off = led->id - MC13783_LED_R1; 72 off = led->id - MC13783_LED_R1;
82 bank = off / 3; 73 bank = off / 3;
83 reg = MC13XXX_REG_LED_CONTROL(3) + bank; 74 reg = 3 + bank;
84 shift = (off - bank * 3) * 5 + 6; 75 shift = (off - bank * 3) * 5 + 6;
85 value = led->new_brightness >> 3; 76 value = led->new_brightness >> 3;
86 mask = 0x1f; 77 mask = 0x1f;
87 break; 78 break;
88 case MC13892_LED_MD: 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 case MC13892_LED_AD: 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 case MC13892_LED_KP: 81 case MC13892_LED_KP:
101 reg = MC13XXX_REG_LED_CONTROL(1); 82 reg = (led->id - MC13892_LED_MD) / 2;
102 shift = 3; 83 shift = 3 + (led->id - MC13892_LED_MD) * 12;
103 mask = 0x3f; 84 mask = 0x3f;
104 value = led->new_brightness >> 2; 85 value = led->new_brightness >> 2;
105 break; 86 break;
@@ -108,16 +89,24 @@ static void mc13xxx_led_work(struct work_struct *work)
108 case MC13892_LED_B: 89 case MC13892_LED_B:
109 off = led->id - MC13892_LED_R; 90 off = led->id - MC13892_LED_R;
110 bank = off / 2; 91 bank = off / 2;
111 reg = MC13XXX_REG_LED_CONTROL(2) + bank; 92 reg = 2 + bank;
112 shift = (off - bank * 2) * 12 + 3; 93 shift = (off - bank * 2) * 12 + 3;
113 value = led->new_brightness >> 2; 94 value = led->new_brightness >> 2;
114 mask = 0x3f; 95 mask = 0x3f;
115 break; 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 default: 104 default:
117 BUG(); 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
123static void mc13xxx_led_set(struct led_classdev *led_cdev, 112static void mc13xxx_led_set(struct led_classdev *led_cdev,
@@ -132,16 +121,17 @@ static void mc13xxx_led_set(struct led_classdev *led_cdev,
132 121
133static int __init mc13xxx_led_probe(struct platform_device *pdev) 122static int __init mc13xxx_led_probe(struct platform_device *pdev)
134{ 123{
135 struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); 124 struct device *dev = &pdev->dev;
136 struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent); 125 struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(dev);
126 struct mc13xxx *mcdev = dev_get_drvdata(dev->parent);
137 struct mc13xxx_led_devtype *devtype = 127 struct mc13xxx_led_devtype *devtype =
138 (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data; 128 (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data;
139 struct mc13xxx_leds *leds; 129 struct mc13xxx_leds *leds;
140 int i, id, num_leds, ret = -ENODATA; 130 int i, id, num_leds, ret = -ENODATA;
141 u32 reg, init_led = 0; 131 u32 init_led = 0;
142 132
143 if (!pdata) { 133 if (!pdata) {
144 dev_err(&pdev->dev, "Missing platform data\n"); 134 dev_err(dev, "Missing platform data\n");
145 return -ENODEV; 135 return -ENODEV;
146 } 136 }
147 137
@@ -149,23 +139,23 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
149 139
150 if ((num_leds < 1) || 140 if ((num_leds < 1) ||
151 (num_leds > (devtype->led_max - devtype->led_min + 1))) { 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 return -EINVAL; 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 sizeof(struct mc13xxx_leds), GFP_KERNEL); 147 sizeof(struct mc13xxx_leds), GFP_KERNEL);
158 if (!leds) 148 if (!leds)
159 return -ENOMEM; 149 return -ENOMEM;
160 150
161 leds->devtype = devtype; 151 leds->devtype = devtype;
162 leds->num_leds = num_leds; 152 leds->num_leds = num_leds;
153 leds->master = mcdev;
163 platform_set_drvdata(pdev, leds); 154 platform_set_drvdata(pdev, leds);
164 155
165 for (i = 0; i < devtype->num_regs; i++) { 156 for (i = 0; i < devtype->num_regs; i++) {
166 reg = pdata->led_control[i]; 157 ret = mc13xxx_reg_write(mcdev, leds->devtype->ledctrl_base + i,
167 WARN_ON(reg >= (1 << 24)); 158 pdata->led_control[i]);
168 ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg);
169 if (ret) 159 if (ret)
170 return ret; 160 return ret;
171 } 161 }
@@ -180,19 +170,18 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
180 trig = pdata->led[i].default_trigger; 170 trig = pdata->led[i].default_trigger;
181 171
182 if ((id > devtype->led_max) || (id < devtype->led_min)) { 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 break; 174 break;
185 } 175 }
186 176
187 if (init_led & (1 << id)) { 177 if (init_led & (1 << id)) {
188 dev_warn(&pdev->dev, 178 dev_warn(dev, "LED %i already initialized\n", id);
189 "LED %i already initialized\n", id);
190 break; 179 break;
191 } 180 }
192 181
193 init_led |= 1 << id; 182 init_led |= 1 << id;
194 leds->led[i].id = id; 183 leds->led[i].id = id;
195 leds->led[i].master = mcdev; 184 leds->led[i].leds = leds;
196 leds->led[i].cdev.name = name; 185 leds->led[i].cdev.name = name;
197 leds->led[i].cdev.default_trigger = trig; 186 leds->led[i].cdev.default_trigger = trig;
198 leds->led[i].cdev.brightness_set = mc13xxx_led_set; 187 leds->led[i].cdev.brightness_set = mc13xxx_led_set;
@@ -200,10 +189,9 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
200 189
201 INIT_WORK(&leds->led[i].work, mc13xxx_led_work); 190 INIT_WORK(&leds->led[i].work, mc13xxx_led_work);
202 191
203 ret = led_classdev_register(pdev->dev.parent, 192 ret = led_classdev_register(dev->parent, &leds->led[i].cdev);
204 &leds->led[i].cdev);
205 if (ret) { 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 break; 195 break;
208 } 196 }
209 } 197 }
@@ -219,8 +207,8 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
219 207
220static int mc13xxx_led_remove(struct platform_device *pdev) 208static int mc13xxx_led_remove(struct platform_device *pdev)
221{ 209{
222 struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent);
223 struct mc13xxx_leds *leds = platform_get_drvdata(pdev); 210 struct mc13xxx_leds *leds = platform_get_drvdata(pdev);
211 struct mc13xxx *mcdev = leds->master;
224 int i; 212 int i;
225 213
226 for (i = 0; i < leds->num_leds; i++) { 214 for (i = 0; i < leds->num_leds; i++) {
@@ -229,7 +217,7 @@ static int mc13xxx_led_remove(struct platform_device *pdev)
229 } 217 }
230 218
231 for (i = 0; i < leds->devtype->num_regs; i++) 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 return 0; 222 return 0;
235} 223}
@@ -238,17 +226,27 @@ static const struct mc13xxx_led_devtype mc13783_led_devtype = {
238 .led_min = MC13783_LED_MD, 226 .led_min = MC13783_LED_MD,
239 .led_max = MC13783_LED_B3, 227 .led_max = MC13783_LED_B3,
240 .num_regs = 6, 228 .num_regs = 6,
229 .ledctrl_base = 51,
241}; 230};
242 231
243static const struct mc13xxx_led_devtype mc13892_led_devtype = { 232static const struct mc13xxx_led_devtype mc13892_led_devtype = {
244 .led_min = MC13892_LED_MD, 233 .led_min = MC13892_LED_MD,
245 .led_max = MC13892_LED_B, 234 .led_max = MC13892_LED_B,
246 .num_regs = 4, 235 .num_regs = 4,
236 .ledctrl_base = 51,
237};
238
239static 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,
247}; 244};
248 245
249static const struct platform_device_id mc13xxx_led_id_table[] = { 246static const struct platform_device_id mc13xxx_led_id_table[] = {
250 { "mc13783-led", (kernel_ulong_t)&mc13783_led_devtype, }, 247 { "mc13783-led", (kernel_ulong_t)&mc13783_led_devtype, },
251 { "mc13892-led", (kernel_ulong_t)&mc13892_led_devtype, }, 248 { "mc13892-led", (kernel_ulong_t)&mc13892_led_devtype, },
249 { "mc34708-led", (kernel_ulong_t)&mc34708_led_devtype, },
252 { } 250 { }
253}; 251};
254MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table); 252MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table);