diff options
author | merge <null@invalid> | 2008-12-08 22:50:52 +0000 |
---|---|---|
committer | Andy Green <agreen@pads.home.warmcat.com> | 2008-12-08 22:50:52 +0000 |
commit | ebb3f320edcc6c4665a71ea060ef2ce6a83402b0 (patch) | |
tree | bcc900f37c2f7ab72addce6555263bfe1dd85aca /drivers | |
parent | 31383993decd60a7cc783f402ad83ee8580008d3 (diff) |
MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-fix-s3c2410_ts-fifo-allocation-1228776491
pending-tracking-hist top was MERGE-via-stable-tracking-fix-s3c2410_ts-fifo-allocation-1228776491 / a85a8a282939b4f6800081f67e1d568e0b97bd7a ... parent commitmessage:
From: merge <null@invalid>
MERGE-via-stable-tracking-hist-fix-s3c2410_ts-fifo-allocation
stable-tracking-hist top was fix-s3c2410_ts-fifo-allocation / 56a57ba0d4c1d60869250d5f89fae61544f01012 ... parent commitmessage:
From: Nelson Castillo <nelsoneci@gmail.com>
Fix s3c2410_ts FIFO allocation
When I added the FIFO improving the interrupts handlers I introduced a bug.
The FIFO is allocated after the interrupts are requested. This makes the kernel
crash if the touchscreen generates activity before the allocation takes place.
This patch fixes the bug. I reproduced it and tested the fix in a GTA02.
- Fix bug
- Fix a typo
Reported-by: Andy Green <andy@openmoko.com>
Signed-off-by: Nelson Castillo <nelsoneci@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/touchscreen/s3c2410_ts.c | 19 | ||||
-rw-r--r-- | drivers/mfd/pcf50633-core.c | 74 | ||||
-rw-r--r-- | drivers/power/pcf50633-charger.c | 81 |
3 files changed, 134 insertions, 40 deletions
diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index 8e6bc0a0371..4159adaec7c 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -427,6 +427,11 @@ static int __init s3c2410ts_probe(struct platform_device *pdev) ts.dev->id.product = 0xBEEF; ts.dev->id.version = S3C2410TSVERSION; ts.state = TS_STATE_STANDBY; + ts.event_fifo = kfifo_alloc(TS_EVENT_FIFO_SIZE, GFP_KERNEL, NULL); + if (IS_ERR(ts.event_fifo)) { + ret = -EIO; + goto bail2; + } /* create the filter chain set up for the 2 coordinates we produce */ ret = ts_filter_create_chain( @@ -459,26 +464,17 @@ static int __init s3c2410ts_probe(struct platform_device *pdev) goto bail4; } - ts.event_fifo = kfifo_alloc(TS_EVENT_FIFO_SIZE, GFP_KERNEL, NULL); - - if (IS_ERR(ts.event_fifo)) { - ret = -EIO; - goto bail5; - } - dev_info(&pdev->dev, "successfully loaded\n"); /* All went ok, so register to the input system */ rc = input_register_device(ts.dev); if (rc) { ret = -EIO; - goto bail6; + goto bail5; } return 0; -bail6: - kfifo_free(ts.event_fifo); bail5: free_irq(IRQ_TC, ts.dev); free_irq(IRQ_ADC, ts.dev); @@ -489,7 +485,8 @@ bail4: disable_irq(IRQ_ADC); bail3: ts_filter_destroy_chain(ts.tsf); - + kfifo_free(ts.event_fifo); +bail2: input_unregister_device(ts.dev); bail1: iounmap(base_addr); diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 6634558ea91..2079d303000 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -28,6 +28,7 @@ #include <linux/interrupt.h> #include <linux/workqueue.h> #include <linux/platform_device.h> +#include <linux/delay.h> #include <linux/mfd/pcf50633/core.h> @@ -292,10 +293,11 @@ static void pcf50633_irq_worker(struct work_struct *work) pcf_int[0] &= ~(1 << PCF50633_INT1_ADPINS); } +#if 0 dev_info(pcf->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x " "INT4=0x%02x INT5=0x%02x\n", pcf_int[0], pcf_int[1], pcf_int[2], pcf_int[3], pcf_int[4]); - +#endif /* Some revisions of the chip don't have a 8s standby mode on * ONKEY1S press. We try to manually do it in such cases. */ @@ -377,8 +379,6 @@ static irqreturn_t pcf50633_irq(int irq, void *data) { struct pcf50633 *pcf = data; - printk(KERN_ERR "pcf50633_irq\n"); - get_device(pcf->dev); disable_irq(pcf->irq); @@ -474,15 +474,17 @@ static int pcf50633_resume(struct device *dev) #define pcf50633_resume NULL #endif + static int pcf50633_probe(struct i2c_client *client, const struct i2c_device_id *ids) { struct pcf50633 *pcf; struct pcf50633_platform_data *pdata; - int i, ret = 0; - u8 mbcs1; + int ret = 0; int version; int variant; + u8 mbcs1; + int i; pdata = client->dev.platform_data; @@ -518,7 +520,7 @@ static int pcf50633_probe(struct i2c_client *client, dev_info(pcf->dev, "Probed device version %d variant %d\n", version, variant); - /* Enable all inteerupts except RTC SECOND */ + /* Enable all interrupts except RTC SECOND */ pcf->mask_regs[0] = 0x80; pcf50633_reg_write(pcf, PCF50633_REG_INT1M, 0x80); @@ -535,22 +537,15 @@ static int pcf50633_probe(struct i2c_client *client, &pcf->mbc.pdev); pcf50633_client_dev_register(pcf, "pcf50633-adc", &pcf->adc.pdev); - for (i = 0; i < PCF50633_NUM_REGULATORS; i++) { - struct platform_device *pdev; - pdev = platform_device_alloc("pcf50633-regltr", i); - if (!pdev) { - dev_err(pcf->dev, "Cannot create regulator\n"); - continue; - } + /* Cold Intialization */ + mbcs1 = pcf50633_reg_read(pcf, PCF50633_REG_MBCS1); - pdev->dev.parent = pcf->dev; - pdev->dev.platform_data = &pdata->reg_init_data[i]; - pdev->dev.driver_data = pcf; - pcf->pmic.pdev[i] = pdev; + if (mbcs1 & 0x01) + pcf50633_irq_call_handler(pcf, PCF50633_IRQ_USBINS); + if (mbcs1 & 0x04) + pcf50633_irq_call_handler(pcf, PCF50633_IRQ_ADPINS); - platform_device_add(pdev); - } pcf->irq = client->irq; @@ -571,20 +566,41 @@ static int pcf50633_probe(struct i2c_client *client, dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up " "source in this hardware revision\n", client->irq); - /* Cold Intialization */ - mbcs1 = pcf50633_reg_read(pcf, PCF50633_REG_MBCS1); - - if (mbcs1 & 0x01) - pcf50633_irq_call_handler(pcf, PCF50633_IRQ_USBINS); - if (mbcs1 & 0x04) - pcf50633_irq_call_handler(pcf, PCF50633_IRQ_ADPINS); - ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group); if (ret) dev_err(pcf->dev, "error creating sysfs entries\n"); - if (pdata->probe_done) - pdata->probe_done(pcf); + /* + * give the system a chance to spin until power situation becomes + * good enough to continue boot. USB-based systems are only allowed to + * pull 100mA until enumerated when they can have up to 500mA for + * example + */ + + if (pcf->pdata->mbc_event_callback) + pcf->pdata->mbc_event_callback(pcf, + PCF50633_ABOUT_TO_INCREASE_POWER); + + for (i = 0; i < PCF50633_NUM_REGULATORS; i++) { + struct platform_device *pdev; + + pdev = platform_device_alloc("pcf50633-regltr", i); + if (!pdev) { + dev_err(pcf->dev, "Cannot create regulator\n"); + continue; + } + + pdev->dev.parent = pcf->dev; + pdev->dev.platform_data = &pcf->pdata->reg_init_data[i]; + pdev->dev.driver_data = pcf; + pcf->pmic.pdev[i] = pdev; + + platform_device_add(pdev); + } + + if (pcf->pdata->probe_done) + pcf->pdata->probe_done(pcf); + return 0; diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c index 9bbfaac48a1..8e302c6c40e 100644 --- a/drivers/power/pcf50633-charger.c +++ b/drivers/power/pcf50633-charger.c @@ -23,9 +23,90 @@ * MA 02111-1307 USA */ +#include <linux/delay.h> #include <linux/mfd/pcf50633/core.h> #include <linux/mfd/pcf50633/mbc.h> +/* this tells us the answer to "how am I set for power?" */ + +enum pcf50633_power_avail pcf50633_check_power_available(struct pcf50633 *pcf) +{ + int ret; + int battery_ok; + int usb_present; + + /* first look for adapter and USB power status */ + + ret = pcf50633_reg_read(pcf, PCF50633_REG_MBCS1); + if (ret < 0) + return ret; + + if (ret & 8) /* adapter power present */ + return PCF50633_PA_ADAPTER; /* don't care about anything else */ + + usb_present = ret & 2; + + /* measure battery using PMU ADC */ + /* disable charging momentarily so we can measure battery */ + + ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1, 1, 0); + if (ret < 0) + return ret; + + ret = pcf50633_adc_sync_read(pcf, PCF50633_ADCC1_MUX_BATSNS_RES, + PCF50633_ADCC1_AVERAGE_16); + if (ret < 0) + return ret; + + battery_ok = (ret > pcf->pdata->good_main_battery_adc_threshold); + + /* enable charging again */ + + ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1, 1, 1); + if (ret < 0) + return ret; + + /* + * now we know battery and USB situation + * make the decision now if possible + */ + + if (!usb_present && !battery_ok) + return PCF50633_PA_DEAD_BATTERY_ONLY; + + if (!usb_present && battery_ok) + return PCF50633_PA_LIVE_BATTERY_ONLY; + + /* So USB is present... what current limit? */ + + ret = pcf50633_reg_read(pcf, PCF50633_REG_MBCC7); + if (ret < 0) + return ret; + + switch (ret & PCF50633_MBCC7_USB_MASK) { + + case PCF50633_MBCC7_USB_100mA: + if (battery_ok) + return PCF50633_PA_USB_100mA_AND_LIVE_BATTERY; + else + return PCF50633_PA_USB_100mA_AND_DEAD_BATTERY; + + case PCF50633_MBCC7_USB_500mA: + return PCF50633_PA_USB_500mA; + + case PCF50633_MBCC7_USB_1000mA: + return PCF50633_PA_USB_1A; + + default: + if (battery_ok) + return PCF50633_PA_LIVE_BATTERY_ONLY; + else + return PCF50633_PA_DEAD_BATTERY_ONLY; + } + + return PCF50633_PA_DEAD_BATTERY_ONLY; +} + void pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma) { int ret; |