[x86] add rootwait option to the kernel command line (#6209)
[openwrt.git] / target / linux / s3c24xx / patches-2.6.31 / 057-pcf50633.patch
1 From 20fb4fd1e317dadaaaaeb9c153098b57d0fc86fe Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Tue, 21 Jul 2009 12:47:03 +0200
4 Subject: [PATCH] 056-pcf50633.patch
5
6 ---
7 drivers/mfd/pcf50633-core.c | 16 +++--
8 drivers/power/pcf50633-charger.c | 121 ++++++++++++++++++++++++++++---
9 drivers/regulator/pcf50633-regulator.c | 60 +++++++++++++---
10 drivers/rtc/rtc-pcf50633.c | 12 +++-
11 include/linux/mfd/pcf50633/core.h | 5 +-
12 5 files changed, 180 insertions(+), 34 deletions(-)
13
14 diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
15 index 8d3c38b..e81c967 100644
16 --- a/drivers/mfd/pcf50633-core.c
17 +++ b/drivers/mfd/pcf50633-core.c
18 @@ -15,6 +15,7 @@
19 #include <linux/kernel.h>
20 #include <linux/device.h>
21 #include <linux/sysfs.h>
22 +#include <linux/device.h>
23 #include <linux/module.h>
24 #include <linux/types.h>
25 #include <linux/interrupt.h>
26 @@ -345,6 +346,8 @@ static void pcf50633_irq_worker(struct work_struct *work)
27 goto out;
28 }
29
30 + pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN, 0x04 ); /* defeat 8s death from lowsys on A5 */
31 +
32 /* We immediately read the usb and adapter status. We thus make sure
33 * only of USBINS/USBREM IRQ handlers are called */
34 if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
35 @@ -482,13 +485,13 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
36 }
37
38 #ifdef CONFIG_PM
39 -static int pcf50633_suspend(struct device *dev, pm_message_t state)
40 +static int pcf50633_suspend(struct i2c_client *client, pm_message_t state)
41 {
42 struct pcf50633 *pcf;
43 int ret = 0, i;
44 u8 res[5];
45
46 - pcf = dev_get_drvdata(dev);
47 + pcf = i2c_get_clientdata(client);
48
49 /* Make sure our interrupt handlers are not called
50 * henceforth */
51 @@ -523,12 +526,12 @@ out:
52 return ret;
53 }
54
55 -static int pcf50633_resume(struct device *dev)
56 +static int pcf50633_resume(struct i2c_client *client)
57 {
58 struct pcf50633 *pcf;
59 int ret;
60
61 - pcf = dev_get_drvdata(dev);
62 + pcf = i2c_get_clientdata(client);
63
64 /* Write the saved mask registers */
65 ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
66 @@ -625,6 +628,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
67 }
68
69 if (client->irq) {
70 + set_irq_handler(client->irq, handle_level_irq);
71 ret = request_irq(client->irq, pcf50633_irq,
72 IRQF_TRIGGER_LOW, "pcf50633", pcf);
73
74 @@ -683,12 +687,12 @@ static struct i2c_device_id pcf50633_id_table[] = {
75 static struct i2c_driver pcf50633_driver = {
76 .driver = {
77 .name = "pcf50633",
78 - .suspend = pcf50633_suspend,
79 - .resume = pcf50633_resume,
80 },
81 .id_table = pcf50633_id_table,
82 .probe = pcf50633_probe,
83 .remove = __devexit_p(pcf50633_remove),
84 + .suspend = pcf50633_suspend,
85 + .resume = pcf50633_resume,
86 };
87
88 static int __init pcf50633_init(void)
89 diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c
90 index e8b278f..41fa421 100644
91 --- a/drivers/power/pcf50633-charger.c
92 +++ b/drivers/power/pcf50633-charger.c
93 @@ -36,6 +36,7 @@ struct pcf50633_mbc {
94
95 struct power_supply usb;
96 struct power_supply adapter;
97 + struct power_supply ac;
98
99 struct delayed_work charging_restart_work;
100 };
101 @@ -47,16 +48,21 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
102 u8 bits;
103 int charging_start = 1;
104 u8 mbcs2, chgmod;
105 + unsigned int mbcc5;
106
107 - if (ma >= 1000)
108 + if (ma >= 1000) {
109 bits = PCF50633_MBCC7_USB_1000mA;
110 - else if (ma >= 500)
111 + ma = 1000;
112 + } else if (ma >= 500) {
113 bits = PCF50633_MBCC7_USB_500mA;
114 - else if (ma >= 100)
115 + ma = 500;
116 + } else if (ma >= 100) {
117 bits = PCF50633_MBCC7_USB_100mA;
118 - else {
119 + ma = 100;
120 + } else {
121 bits = PCF50633_MBCC7_USB_SUSPEND;
122 charging_start = 0;
123 + ma = 0;
124 }
125
126 ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
127 @@ -66,7 +72,22 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
128 else
129 dev_info(pcf->dev, "usb curlim to %d mA\n", ma);
130
131 - /* Manual charging start */
132 + /*
133 + * We limit the charging current to be the USB current limit.
134 + * The reason is that on pcf50633, when it enters PMU Standby mode,
135 + * which it does when the device goes "off", the USB current limit
136 + * reverts to the variant default. In at least one common case, that
137 + * default is 500mA. By setting the charging current to be the same
138 + * as the USB limit we set here before PMU standby, we enforce it only
139 + * using the correct amount of current even when the USB current limit
140 + * gets reset to the wrong thing
141 + */
142 +
143 + mbcc5 = (ma << 8) / mbc->pcf->pdata->chg_ref_current_ma;
144 + if (mbcc5 > 255)
145 + mbcc5 = 255;
146 + pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
147 +
148 mbcs2 = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
149 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
150
151 @@ -81,7 +102,7 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
152 PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME);
153
154 mbc->usb_active = charging_start;
155 -
156 +
157 power_supply_changed(&mbc->usb);
158
159 return ret;
160 @@ -156,9 +177,44 @@ static ssize_t set_usblim(struct device *dev,
161
162 static DEVICE_ATTR(usb_curlim, S_IRUGO | S_IWUSR, show_usblim, set_usblim);
163
164 +static ssize_t
165 +show_chglim(struct device *dev, struct device_attribute *attr, char *buf)
166 +{
167 + struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
168 + u8 mbcc5 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC5);
169 + unsigned int ma;
170 +
171 + ma = (mbc->pcf->pdata->chg_ref_current_ma * mbcc5) >> 8;
172 +
173 + return sprintf(buf, "%u\n", ma);
174 +}
175 +
176 +static ssize_t set_chglim(struct device *dev,
177 + struct device_attribute *attr, const char *buf, size_t count)
178 +{
179 + struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
180 + unsigned long ma;
181 + unsigned int mbcc5;
182 + int ret;
183 +
184 + ret = strict_strtoul(buf, 10, &ma);
185 + if (ret)
186 + return -EINVAL;
187 +
188 + mbcc5 = (ma << 8) / mbc->pcf->pdata->chg_ref_current_ma;
189 + if (mbcc5 > 255)
190 + mbcc5 = 255;
191 + pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
192 +
193 + return count;
194 +}
195 +
196 +static DEVICE_ATTR(chg_curlim, S_IRUGO | S_IWUSR, show_chglim, set_chglim);
197 +
198 static struct attribute *pcf50633_mbc_sysfs_entries[] = {
199 &dev_attr_chgmode.attr,
200 &dev_attr_usb_curlim.attr,
201 + &dev_attr_chg_curlim.attr,
202 NULL,
203 };
204
205 @@ -239,6 +295,7 @@ pcf50633_mbc_irq_handler(int irq, void *data)
206
207 power_supply_changed(&mbc->usb);
208 power_supply_changed(&mbc->adapter);
209 + power_supply_changed(&mbc->ac);
210
211 if (mbc->pcf->pdata->mbc_event_callback)
212 mbc->pcf->pdata->mbc_event_callback(mbc->pcf, irq);
213 @@ -248,8 +305,7 @@ static int adapter_get_property(struct power_supply *psy,
214 enum power_supply_property psp,
215 union power_supply_propval *val)
216 {
217 - struct pcf50633_mbc *mbc = container_of(psy,
218 - struct pcf50633_mbc, adapter);
219 + struct pcf50633_mbc *mbc = container_of(psy, struct pcf50633_mbc, adapter);
220 int ret = 0;
221
222 switch (psp) {
223 @@ -269,10 +325,34 @@ static int usb_get_property(struct power_supply *psy,
224 {
225 struct pcf50633_mbc *mbc = container_of(psy, struct pcf50633_mbc, usb);
226 int ret = 0;
227 + u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
228 + PCF50633_MBCC7_USB_MASK;
229
230 switch (psp) {
231 case POWER_SUPPLY_PROP_ONLINE:
232 - val->intval = mbc->usb_online;
233 + val->intval = mbc->usb_online &&
234 + (usblim <= PCF50633_MBCC7_USB_500mA);
235 + break;
236 + default:
237 + ret = -EINVAL;
238 + break;
239 + }
240 + return ret;
241 +}
242 +
243 +static int ac_get_property(struct power_supply *psy,
244 + enum power_supply_property psp,
245 + union power_supply_propval *val)
246 +{
247 + struct pcf50633_mbc *mbc = container_of(psy, struct pcf50633_mbc, ac);
248 + int ret = 0;
249 + u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
250 + PCF50633_MBCC7_USB_MASK;
251 +
252 + switch (psp) {
253 + case POWER_SUPPLY_PROP_ONLINE:
254 + val->intval = mbc->usb_online &&
255 + (usblim == PCF50633_MBCC7_USB_1000mA);
256 break;
257 default:
258 ret = -EINVAL;
259 @@ -337,6 +417,17 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
260 mbc->usb.supplied_to = mbc->pcf->pdata->batteries;
261 mbc->usb.num_supplicants = mbc->pcf->pdata->num_batteries;
262
263 + mbc->ac.name = "ac";
264 + mbc->ac.type = POWER_SUPPLY_TYPE_MAINS;
265 + mbc->ac.properties = power_props;
266 + mbc->ac.num_properties = ARRAY_SIZE(power_props);
267 + mbc->ac.get_property = ac_get_property;
268 + mbc->ac.supplied_to = mbc->pcf->pdata->batteries;
269 + mbc->ac.num_supplicants = mbc->pcf->pdata->num_batteries;
270 +
271 + INIT_DELAYED_WORK(&mbc->charging_restart_work,
272 + pcf50633_mbc_charging_restart);
273 +
274 ret = power_supply_register(&pdev->dev, &mbc->adapter);
275 if (ret) {
276 dev_err(mbc->pcf->dev, "failed to register adapter\n");
277 @@ -352,9 +443,15 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
278 return ret;
279 }
280
281 - INIT_DELAYED_WORK(&mbc->charging_restart_work,
282 - pcf50633_mbc_charging_restart);
283 -
284 + ret = power_supply_register(&pdev->dev, &mbc->ac);
285 + if (ret) {
286 + dev_err(mbc->pcf->dev, "failed to register ac\n");
287 + power_supply_unregister(&mbc->adapter);
288 + power_supply_unregister(&mbc->usb);
289 + kfree(mbc);
290 + return ret;
291 + }
292 +
293 ret = sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group);
294 if (ret)
295 dev_err(mbc->pcf->dev, "failed to create sysfs entries\n");
296 diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
297 index 8e14900..4809789 100644
298 --- a/drivers/regulator/pcf50633-regulator.c
299 +++ b/drivers/regulator/pcf50633-regulator.c
300 @@ -24,11 +24,12 @@
301 #include <linux/mfd/pcf50633/core.h>
302 #include <linux/mfd/pcf50633/pmic.h>
303
304 -#define PCF50633_REGULATOR(_name, _id) \
305 +#define PCF50633_REGULATOR(_name, _id, _n) \
306 { \
307 .name = _name, \
308 .id = _id, \
309 .ops = &pcf50633_regulator_ops, \
310 + .n_voltages = _n, \
311 .type = REGULATOR_VOLTAGE, \
312 .owner = THIS_MODULE, \
313 }
314 @@ -193,6 +194,40 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
315 return millivolts * 1000;
316 }
317
318 +static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
319 + unsigned int index)
320 +{
321 + struct pcf50633 *pcf;
322 + int regulator_id, millivolts;
323 +
324 + pcf = rdev_get_drvdata(rdev);;
325 +
326 + regulator_id = rdev_get_id(rdev);
327 +
328 + switch (regulator_id) {
329 + case PCF50633_REGULATOR_AUTO:
330 + millivolts = auto_voltage_value(index + 0x2f);
331 + break;
332 + case PCF50633_REGULATOR_DOWN1:
333 + case PCF50633_REGULATOR_DOWN2:
334 + millivolts = down_voltage_value(index);
335 + break;
336 + case PCF50633_REGULATOR_LDO1:
337 + case PCF50633_REGULATOR_LDO2:
338 + case PCF50633_REGULATOR_LDO3:
339 + case PCF50633_REGULATOR_LDO4:
340 + case PCF50633_REGULATOR_LDO5:
341 + case PCF50633_REGULATOR_LDO6:
342 + case PCF50633_REGULATOR_HCLDO:
343 + millivolts = ldo_voltage_value(index);
344 + break;
345 + default:
346 + return -EINVAL;
347 + }
348 +
349 + return millivolts * 1000;
350 +}
351 +
352 static int pcf50633_regulator_enable(struct regulator_dev *rdev)
353 {
354 struct pcf50633 *pcf = rdev_get_drvdata(rdev);
355 @@ -246,6 +281,7 @@ static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev)
356 static struct regulator_ops pcf50633_regulator_ops = {
357 .set_voltage = pcf50633_regulator_set_voltage,
358 .get_voltage = pcf50633_regulator_get_voltage,
359 + .list_voltage = pcf50633_regulator_list_voltage,
360 .enable = pcf50633_regulator_enable,
361 .disable = pcf50633_regulator_disable,
362 .is_enabled = pcf50633_regulator_is_enabled,
363 @@ -253,27 +289,27 @@ static struct regulator_ops pcf50633_regulator_ops = {
364
365 static struct regulator_desc regulators[] = {
366 [PCF50633_REGULATOR_AUTO] =
367 - PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO),
368 + PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO, 80),
369 [PCF50633_REGULATOR_DOWN1] =
370 - PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1),
371 + PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1, 95),
372 [PCF50633_REGULATOR_DOWN2] =
373 - PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2),
374 + PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2, 95),
375 [PCF50633_REGULATOR_LDO1] =
376 - PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1),
377 + PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1, 27),
378 [PCF50633_REGULATOR_LDO2] =
379 - PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2),
380 + PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2, 27),
381 [PCF50633_REGULATOR_LDO3] =
382 - PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3),
383 + PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3, 27),
384 [PCF50633_REGULATOR_LDO4] =
385 - PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4),
386 + PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4, 27),
387 [PCF50633_REGULATOR_LDO5] =
388 - PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5),
389 + PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5, 27),
390 [PCF50633_REGULATOR_LDO6] =
391 - PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6),
392 + PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6, 27),
393 [PCF50633_REGULATOR_HCLDO] =
394 - PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO),
395 + PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO, 26),
396 [PCF50633_REGULATOR_MEMLDO] =
397 - PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO),
398 + PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO, 27),
399 };
400
401 static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
402 diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c
403 index f4dd87e..8669815 100644
404 --- a/drivers/rtc/rtc-pcf50633.c
405 +++ b/drivers/rtc/rtc-pcf50633.c
406 @@ -58,6 +58,7 @@ struct pcf50633_time {
407 struct pcf50633_rtc {
408 int alarm_enabled;
409 int second_enabled;
410 + int alarm_pending;
411
412 struct pcf50633 *pcf;
413 struct rtc_device *rtc_dev;
414 @@ -70,7 +71,7 @@ static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf)
415 rtc->tm_hour = bcd2bin(pcf->time[PCF50633_TI_HOUR]);
416 rtc->tm_wday = bcd2bin(pcf->time[PCF50633_TI_WKDAY]);
417 rtc->tm_mday = bcd2bin(pcf->time[PCF50633_TI_DAY]);
418 - rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]);
419 + rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]) - 1;
420 rtc->tm_year = bcd2bin(pcf->time[PCF50633_TI_YEAR]) + 100;
421 }
422
423 @@ -81,7 +82,7 @@ static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc)
424 pcf->time[PCF50633_TI_HOUR] = bin2bcd(rtc->tm_hour);
425 pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday);
426 pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday);
427 - pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon);
428 + pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon + 1);
429 pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100);
430 }
431
432 @@ -209,6 +210,7 @@ static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
433 rtc = dev_get_drvdata(dev);
434
435 alrm->enabled = rtc->alarm_enabled;
436 + alrm->pending = rtc->alarm_pending;
437
438 ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA,
439 PCF50633_TI_EXTENT, &pcf_tm.time[0]);
440 @@ -244,9 +246,12 @@ static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
441 /* Returns 0 on success */
442 ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA,
443 PCF50633_TI_EXTENT, &pcf_tm.time[0]);
444 + if (!alrm->enabled)
445 + rtc->alarm_pending = 0;
446
447 - if (!alarm_masked)
448 + if (!alarm_masked || alrm->enabled)
449 pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
450 + rtc->alarm_enabled = alrm->enabled;
451
452 return ret;
453 }
454 @@ -267,6 +272,7 @@ static void pcf50633_rtc_irq(int irq, void *data)
455 switch (irq) {
456 case PCF50633_IRQ_ALARM:
457 rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
458 + rtc->alarm_pending = 1;
459 break;
460 case PCF50633_IRQ_SECOND:
461 rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
462 diff --git a/include/linux/mfd/pcf50633/core.h b/include/linux/mfd/pcf50633/core.h
463 index c8f51c3..af67b4e 100644
464 --- a/include/linux/mfd/pcf50633/core.h
465 +++ b/include/linux/mfd/pcf50633/core.h
466 @@ -31,6 +31,8 @@ struct pcf50633_platform_data {
467
468 int charging_restart_interval;
469
470 + int chg_ref_current_ma;
471 +
472 /* Callbacks */
473 void (*probe_done)(struct pcf50633 *);
474 void (*mbc_event_callback)(struct pcf50633 *, int);
475 @@ -208,7 +210,8 @@ enum pcf50633_reg_int5 {
476 };
477
478 /* misc. registers */
479 -#define PCF50633_REG_OOCSHDWN 0x0c
480 +#define PCF50633_REG_OOCSHDWN 0x0c
481 +#define PCF50633_OOCSHDWN_GOSTDBY 0x01
482
483 /* LED registers */
484 #define PCF50633_REG_LEDOUT 0x28
485 --
486 1.5.6.5
487
This page took 0.064765 seconds and 5 git commands to generate.