aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormerge <null@invalid>2008-12-08 22:50:52 +0000
committerAndy Green <agreen@pads.home.warmcat.com>2008-12-08 22:50:52 +0000
commitebb3f320edcc6c4665a71ea060ef2ce6a83402b0 (patch)
treebcc900f37c2f7ab72addce6555263bfe1dd85aca
parent31383993decd60a7cc783f402ad83ee8580008d3 (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>
-rw-r--r--arch/arm/mach-s3c2440/mach-gta02.c92
-rw-r--r--drivers/input/touchscreen/s3c2410_ts.c19
-rw-r--r--drivers/mfd/pcf50633-core.c74
-rw-r--r--drivers/power/pcf50633-charger.c81
-rw-r--r--include/linux/mfd/pcf50633/core.h7
-rw-r--r--include/linux/mfd/pcf50633/mbc.h13
-rw-r--r--include/linux/ts_filter.h2
7 files changed, 222 insertions, 66 deletions
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index e90f82bdfc3..d2556ed3a3a 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -557,6 +557,9 @@ static void gta02_charger_worker(struct work_struct *work)
#define GTA02_CHARGER_CONFIGURE_TIMEOUT ((3000 * HZ) / 1000)
static void gta02_pmu_event_callback(struct pcf50633 *pcf, int irq)
{
+ int ret;
+ int happy_with_power = 0;
+
if (irq == PCF50633_IRQ_USBINS) {
schedule_delayed_work(&gta02_charger_work,
GTA02_CHARGER_CONFIGURE_TIMEOUT);
@@ -564,6 +567,44 @@ static void gta02_pmu_event_callback(struct pcf50633 *pcf, int irq)
} else if (irq == PCF50633_IRQ_USBREM) {
cancel_delayed_work_sync(&gta02_charger_work);
gta02_usb_vbus_draw = 0;
+ } else if (irq == PCF50633_ABOUT_TO_INCREASE_POWER) {
+
+ /*
+ * we can't let this proceed until we are happy about
+ * power arrangements, because it is going to bring up
+ * the backlight and double our power consumption.
+ *
+ * With Qi/A6 anyway, until now we could boot just from
+ * USB 100mA limit and no or low battery. So we need
+ * to check for low battery and if so, spin here until
+ * USB enumerated power, or charger comes
+ */
+
+ while (!happy_with_power) {
+ ret = pcf50633_check_power_available(pcf);
+// dev_info(pcf->dev, "available power = %d\n", ret);
+ switch (ret) {
+ case PCF50633_PA_DEAD_BATTERY_ONLY:
+ /* turn ourselves off */
+ pcf50633_reg_write(pcf, PCF50633_REG_OOSHDWN,
+ 0x01);
+ break;
+ case PCF50633_PA_USB_100mA_AND_DEAD_BATTERY:
+ /*
+ * loop waiting for eg 500mA USB
+ * enumeration by host
+ */
+ break;
+ default:
+ /*
+ * one way or another we can afford to
+ * use more power
+ */
+ happy_with_power = 1;
+ continue;
+ }
+ msleep(1000);
+ }
}
}
@@ -628,6 +669,7 @@ static char *gta02_batteries[] = {
"battery",
};
+
struct pcf50633_platform_data gta02_pcf_pdata = {
.resumers = {
[0] = PCF50633_INT1_USBINS |
@@ -765,6 +807,7 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
.probe_done = gta02_pmu_attach_child_devices,
.regulator_registered = gta02_pmu_regulator_registered,
.mbc_event_callback = gta02_pmu_event_callback,
+ .good_main_battery_adc_threshold = 500
};
static void mangle_pmu_pdata_by_system_rev(void)
@@ -1004,6 +1047,8 @@ static void gta02_udc_vbus_draw(unsigned int ma)
return;
}
+ printk(KERN_ERR "******** UDC gta02_pcf_pdata.pcf ma = %d\n", ma);
+
gta02_usb_vbus_draw = ma;
schedule_delayed_work(&gta02_charger_work,
@@ -1608,20 +1653,7 @@ __setup("hardware_ecc=", hardware_ecc_setup);
/* these are the guys that don't need to be children of PMU */
static struct platform_device *gta02_devices[] __initdata = {
- &gta02_version_device,
- &s3c_device_usb,
- &s3c_device_wdt,
- &gta02_memconfig_device,
- &s3c_device_sdi,
&s3c_device_usbgadget,
- &s3c_device_nand,
- &gta02_nor_flash,
-
- &sc32440_fiq_device,
- &s3c24xx_pwm_device,
- &gta02_led_dev,
- &gta02_pm_wlan_dev, /* not dependent on PMU */
-
&s3c_device_iis,
&s3c_device_i2c0,
};
@@ -1629,6 +1661,15 @@ static struct platform_device *gta02_devices[] __initdata = {
/* these guys DO need to be children of PMU */
static struct platform_device *gta02_devices_pmu_children[] = {
+ &s3c_device_usb,
+ &sc32440_fiq_device,
+ &s3c24xx_pwm_device,
+ &s3c_device_nand,
+ &gta02_nor_flash,
+ &gta02_pm_wlan_dev, /* not dependent on PMU */
+ &gta02_version_device,
+ &s3c_device_wdt,
+ &gta02_memconfig_device,
&s3c_device_ts, /* input 1 */
&gta02_pm_gsm_dev,
&gta02_pm_usbhost_dev,
@@ -1636,6 +1677,8 @@ static struct platform_device *gta02_devices_pmu_children[] = {
&s3c_device_spi_acc2, /* input 3 */
&gta02_button_dev, /* input 4 */
&gta02_resume_reason_device,
+ &s3c_device_sdi,
+ &gta02_led_dev,
};
static void gta02_pmu_regulator_registered(struct pcf50633 *pcf, int id)
@@ -1645,23 +1688,24 @@ static void gta02_pmu_regulator_registered(struct pcf50633 *pcf, int id)
regulator = pcf->pmic.pdev[id];
switch(id) {
- case PCF50633_REGULATOR_LDO4:
- pdev = &gta01_pm_bt_dev;
- break;
- case PCF50633_REGULATOR_LDO5:
- pdev = &gta01_pm_gps_dev;
- break;
- case PCF50633_REGULATOR_HCLDO:
- pdev = &gta02_glamo_dev;
- break;
- default:
- return;
+ case PCF50633_REGULATOR_LDO4:
+ pdev = &gta01_pm_bt_dev;
+ break;
+ case PCF50633_REGULATOR_LDO5:
+ pdev = &gta01_pm_gps_dev;
+ break;
+ case PCF50633_REGULATOR_HCLDO:
+ pdev = &gta02_glamo_dev;
+ break;
+ default:
+ return;
}
pdev->dev.parent = &regulator->dev;
platform_device_register(pdev);
}
+
/* this is called when pc50633 is probed, unfortunately quite late in the
* day since it is an I2C bus device. Here we can belatedly define some
* platform devices with the advantage that we can mark the pcf50633 as the
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;
diff --git a/include/linux/mfd/pcf50633/core.h b/include/linux/mfd/pcf50633/core.h
index bf107d3794e..4ee3f527172 100644
--- a/include/linux/mfd/pcf50633/core.h
+++ b/include/linux/mfd/pcf50633/core.h
@@ -34,6 +34,8 @@ struct pcf50633_platform_data {
char **batteries;
int num_batteries;
+ int good_main_battery_adc_threshold;
+
/* Callbacks */
void (*probe_done)(struct pcf50633 *);
void (*mbc_event_callback)(struct pcf50633 *, int);
@@ -78,6 +80,7 @@ int pcf50633_reg_clear_bits(struct pcf50633 *pcf, u8 reg, u8 bits);
#define PCF50633_REG_INT3M 0x09
#define PCF50633_REG_INT4M 0x0a
#define PCF50633_REG_INT5M 0x0b
+#define PCF50633_REG_OOSHDWN 0x0c
enum {
/* Chip IRQs */
@@ -122,8 +125,10 @@ enum {
PCF50633_IRQ_HCLDOPWRFAIL,
PCF50633_IRQ_HCLDOOVL,
- /* Always last */
+ /* Always last of real IRQs */
PCF50633_NUM_IRQ,
+ /* fake IRQ */
+ PCF50633_ABOUT_TO_INCREASE_POWER
};
struct pcf50633 {
diff --git a/include/linux/mfd/pcf50633/mbc.h b/include/linux/mfd/pcf50633/mbc.h
index 9a7938ad132..a1cd44957ac 100644
--- a/include/linux/mfd/pcf50633/mbc.h
+++ b/include/linux/mfd/pcf50633/mbc.h
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
+#define PCF50633_REG_BVMCTL 0x19
#define PCF50633_REG_MBCC1 0x43
#define PCF50633_REG_MBCC2 0x44
#define PCF50633_REG_MBCC3 0x45
@@ -122,6 +123,18 @@ struct pcf50633;
void pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma);
+enum pcf50633_power_avail {
+ PCF50633_PA_DEAD_BATTERY_ONLY,
+ PCF50633_PA_LIVE_BATTERY_ONLY,
+ PCF50633_PA_ADAPTER,
+ PCF50633_PA_USB_100mA_AND_LIVE_BATTERY,
+ PCF50633_PA_USB_100mA_AND_DEAD_BATTERY,
+ PCF50633_PA_USB_500mA,
+ PCF50633_PA_USB_1A
+};
+
+enum pcf50633_power_avail pcf50633_check_power_available(struct pcf50633 *pcf);
+
struct pcf50633_mbc {
int adapter_active;
int adapter_online;
diff --git a/include/linux/ts_filter.h b/include/linux/ts_filter.h
index bfb8a221964..715f1badbf4 100644
--- a/include/linux/ts_filter.h
+++ b/include/linux/ts_filter.h
@@ -8,7 +8,7 @@
*/
#define MAX_TS_FILTER_CHAIN 4 /* max filters you can chain up */
-#define MAX_TS_FILTER_COORDS 3 /* Y, Y and Z (pressure) */
+#define MAX_TS_FILTER_COORDS 3 /* X, Y and Z (pressure) */
struct ts_filter;