From 6fbbacd00b2e6e09583b0f88aed39a7a6cfb6c81 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Mon, 8 Jun 2009 23:46:53 +0400 Subject: GTA0[12]: make headset button report PLAY pressed on press As discussed on the ML, currently headset button reports "KEY_PAUSE released" on press and "pressed" on release. For "pause" semantics it makes sense but if someone thinks of that as of just another button, it'd be good to have "pressed/released" events consistent with button press/release. Luca Capello suggested to change the button event to KEY_PLAY and to invert the state to make it more consistent. This trivial patch inverts button events for GTA03 KEY_PLUS and KEY_MINUS, i'm not sure how undesirable that is. I can prepare an alternative that preserves current behaviour on GTA03 per request. Signed-off-by: Paul Fertser --- drivers/input/keyboard/neo1973kbd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/neo1973kbd.c b/drivers/input/keyboard/neo1973kbd.c index a95dd5806d2..8756ae60910 100644 --- a/drivers/input/keyboard/neo1973kbd.c +++ b/drivers/input/keyboard/neo1973kbd.c @@ -75,7 +75,7 @@ static struct neo1973kbd_key keys[] = { [NEO1973_KEY_HOLD] = { .name = "Neo1973 HOLD button", .isr = neo1973kbd_default_key_irq, - .input_key = KEY_PAUSE, + .input_key = KEY_PLAY, }, [NEO1973_KEY_JACK] = { .name = "Neo1973 Headphone jack", @@ -161,7 +161,7 @@ static irqreturn_t neo1973kbd_default_key_irq(int irq, void *dev_id) continue; input_report_key(kbd->input, keys[n].input_key, - gpio_get_value(kbd->pdev->resource[n].start)); + !gpio_get_value(kbd->pdev->resource[n].start)); input_sync(kbd->input); } @@ -346,7 +346,7 @@ static int neo1973kbd_probe(struct platform_device *pdev) input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_SW); set_bit(SW_HEADPHONE_INSERT, input_dev->swbit); set_bit(KEY_PHONE, input_dev->keybit); - set_bit(KEY_PAUSE, input_dev->keybit); + set_bit(KEY_PLAY, input_dev->keybit); rc = input_register_device(neo1973kbd->input); if (rc) -- cgit v1.2.3 From d7ac922b016626921887e5a1ee42cefce1d0d607 Mon Sep 17 00:00:00 2001 From: Luca Capello Date: Wed, 10 Jun 2009 01:23:59 +0200 Subject: CONFIG_BATTERY_BQ27000_HDQ selects CONFIG_HDQ_GPIO_BITBANG This is because of commit 1f06c28eaa6e77384a366c3d2ab1ccdbb8a807e0 The BQ27000 Battery requires HDQ. Otherwise the battery is not available at all. Signed-off-by: Luca Capello --- drivers/power/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index b5332f714cd..f88c5aab640 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -90,6 +90,7 @@ config CHARGER_PCF50633 config BATTERY_BQ27000_HDQ tristate "BQ27000 HDQ battery monitor driver" + select HDQ_GPIO_BITBANG help Say Y to enable support for the battery on the Neo Freerunner -- cgit v1.2.3 From 5a6ed99264c704e517ac312283c58204ee38fee5 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sat, 13 Jun 2009 02:04:18 +0400 Subject: gta02: move debugging messages to the appropriate levels Clean up debugging messages so that we don't see any output with loglevel=4 (default for Qi). This avoids slowing down suspend/resume by slow fb output. Checkpatch barks on this patch but i guess most of that debugging would have to be changed prior to upstream submission anyway. Signed-off-by: Paul Fertser --- drivers/mfd/glamo/glamo-fb.c | 4 ++-- drivers/mfd/glamo/glamo-mci.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/glamo/glamo-fb.c b/drivers/mfd/glamo/glamo-fb.c index 1ebb87d1276..44ab9a39787 100644 --- a/drivers/mfd/glamo/glamo-fb.c +++ b/drivers/mfd/glamo/glamo-fb.c @@ -1061,7 +1061,7 @@ static int __init glamofb_probe(struct platform_device *pdev) glamo_engine_enable(mach_info->glamo, GLAMO_ENGINE_LCD); glamo_engine_reset(mach_info->glamo, GLAMO_ENGINE_LCD); - dev_info(&pdev->dev, "spin_lock_init\n"); + dev_dbg(&pdev->dev, "spin_lock_init\n"); spin_lock_init(&glamofb->lock_cmd); glamofb_init_regs(glamofb); #ifdef CONFIG_MFD_GLAMO_HWACCEL @@ -1148,7 +1148,7 @@ static int glamofb_resume(struct platform_device *pdev) glamo_engine_enable(mach_info->glamo, GLAMO_ENGINE_LCD); glamo_engine_reset(mach_info->glamo, GLAMO_ENGINE_LCD); - printk(KERN_ERR"spin_lock_init\n"); + dev_dbg(&pdev->dev, "spin_lock_init\n"); spin_lock_init(&gfb->lock_cmd); glamofb_init_regs(gfb); #ifdef CONFIG_MFD_GLAMO_HWACCEL diff --git a/drivers/mfd/glamo/glamo-mci.c b/drivers/mfd/glamo/glamo-mci.c index bc3ed66d43c..acf16360cfd 100644 --- a/drivers/mfd/glamo/glamo-mci.c +++ b/drivers/mfd/glamo/glamo-mci.c @@ -616,7 +616,7 @@ static void glamo_mci_send_request(struct mmc_host *mmc) int insanity_timeout = 1000000; if (host->suspending) { - dev_err(&host->pdev->dev, "IGNORING glamo_mci_send_request while " + dev_dbg(&host->pdev->dev, "REFUSING glamo_mci_send_request while " "suspended\n"); cmd->error = -EIO; if (cmd->data) @@ -774,7 +774,7 @@ static void glamo_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) static void glamo_mci_reset(struct glamo_mci_host *host) { if (host->suspending) { - dev_err(&host->pdev->dev, "IGNORING glamo_mci_reset while " + dev_info(&host->pdev->dev, "IGNORING glamo_mci_reset while " "suspended\n"); return; } -- cgit v1.2.3 From 4e418ad2a6bae9681a7863ab8f376ce47da3e33a Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Thu, 11 Jun 2009 10:16:14 +0400 Subject: RNDIS: crude hack to fix oops on connecting to WXP SP2 F4t discovered that his freerunner panics on connect to his windows box. This crude hack workarounds the problem. Signed-off-by: Paul Fertser --- drivers/usb/gadget/rndis.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 8c26f5ea2b8..c719b1efcbc 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -294,9 +294,22 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_VENDOR_DESCRIPTION: pr_debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__); - length = strlen (rndis_per_dev_params [configNr].vendorDescr); - memcpy (outbuf, - rndis_per_dev_params [configNr].vendorDescr, length); + + if (rndis_per_dev_params[configNr].vendorDescr) { + length = strlen( + rndis_per_dev_params[configNr].vendorDescr); + memcpy(outbuf, + rndis_per_dev_params[configNr].vendorDescr, + length); + } else { + /* + * FIXME: Openmoko hack by Paul Fertser to avoid + * panic with Win XP SP2 when vendorDescr is NULL + * (always ATM). + */ + length = 5; + memcpy(outbuf, "dummy", length); + } retval = 0; break; -- cgit v1.2.3 From d5095005f091b71d4ad68d152465b52c91957eb8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2009 21:02:57 +0200 Subject: bq27000: Return -ENODEV in bq27000_battery_get_property if the battery is not If the battery is not present hdq_read will always return an error. If the drivers knows that the battery is not present the correct thing to do is to return -ENODEV instead of passing the error on. Do this for all properties except POWER_SUPPLY_PROP_PRESENT. The power supply sysfs expects us to do so, else it won't generate a proper uevent file. Signed-off-by: Lars-Peter Clausen --- drivers/power/bq27000_battery.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/power/bq27000_battery.c b/drivers/power/bq27000_battery.c index 593cbe6f752..f1dcda3297d 100644 --- a/drivers/power/bq27000_battery.c +++ b/drivers/power/bq27000_battery.c @@ -186,6 +186,9 @@ static int bq27000_battery_get_property(struct power_supply *psy, int n; struct bq27000_device_info *di = container_of(psy, struct bq27000_device_info, bat); + if (di->regs.rsoc < 0 && psp != POWER_SUPPLY_PROP_PRESENT) + return -ENODEV; + switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = POWER_SUPPLY_STATUS_UNKNOWN; -- cgit v1.2.3 From 5af71f726c58adeef22afafacc2242fd920f9882 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sun, 26 Jul 2009 17:56:54 +0400 Subject: gta01_battery: fix unloading bug Driver data must be properly registered after allocation Signed-off-by: Paul Fertser --- drivers/power/gta01_battery.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/gta01_battery.c b/drivers/power/gta01_battery.c index 81a0fe7387e..5b1a6c9b966 100644 --- a/drivers/power/gta01_battery.c +++ b/drivers/power/gta01_battery.c @@ -76,6 +76,7 @@ static int gta01_battery_probe(struct platform_device *pdev) gta01_bat->psy.external_power_changed = gta01_bat_ext_changed; gta01_bat->pdata = pdev->dev.platform_data; + platform_set_drvdata(pdev, gta01_bat); power_supply_register(&pdev->dev, >a01_bat->psy); return 0; -- cgit v1.2.3 From ec22388dfefaf8eda07d12284b8f946d3c6eb148 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sun, 26 Jul 2009 18:00:29 +0400 Subject: gta01_battery: generalise the driver, add capacity estimation Check if machine-specific hooks exist before calling, this allows to use this driver with gta02 or any other device that is able to provide battery voltage readings. Report an estimate of capacity percentage left, based on discharge curves. Strictly speaking, this is a violation of power_supply class specs but since this is the only driver for dumb batteries and userspace lacks any library to do the estimation itself, we have to stuff it here. Please keep in mind that this estimation is by no means accurate, usually cell phones have only 5 bars to represent charge status. Credit goes to Joerg Reisenweber and SpeedEvil for helping with gathering and analysing the data. Signed-off-by: Paul Fertser --- drivers/power/gta01_battery.c | 54 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/power/gta01_battery.c b/drivers/power/gta01_battery.c index 5b1a6c9b966..3c7c49777b0 100644 --- a/drivers/power/gta01_battery.c +++ b/drivers/power/gta01_battery.c @@ -23,8 +23,35 @@ static enum power_supply_property gta01_bat_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, }; +static int gta01_bat_voltscale(int volt) +{ + /* This table is suggested by SpeedEvil based on analysis of + * experimental data */ + static const int lut[][2] = { + { 4120, 100 }, + { 3900, 60 }, + { 3740, 25 }, + { 3600, 5 }, + { 3000, 0 } }; + int i, res = 0; + + if (volt > lut[0][0]) + res = lut[0][1]; + else + for (i = 0; lut[i][1]; i++) { + if (volt <= lut[i][0] && volt >= lut[i+1][0]) { + res = lut[i][1] - (lut[i][0]-volt)* + (lut[i][1]-lut[i+1][1])/ + (lut[i][0]-lut[i+1][0]); + break; + } + } + return res; +} + static int gta01_bat_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -33,20 +60,37 @@ static int gta01_bat_get_property(struct power_supply *psy, switch(psp) { case POWER_SUPPLY_PROP_STATUS: - if (bat->pdata->get_charging_status()) - val->intval = POWER_SUPPLY_STATUS_CHARGING; + if (bat->pdata->get_charging_status) + if (bat->pdata->get_charging_status()) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; else - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = bat->pdata->get_voltage(); + if (bat->pdata->get_voltage) + val->intval = bat->pdata->get_voltage(); + else + val->intval = 0; break; case POWER_SUPPLY_PROP_CURRENT_NOW: - val->intval = bat->pdata->get_current(); + if (bat->pdata->get_current) + val->intval = bat->pdata->get_current(); + else + val->intval = 0; break; case POWER_SUPPLY_PROP_PRESENT: val->intval = 1; /* You must never run GTA01 without battery. */ break; + case POWER_SUPPLY_PROP_CAPACITY: + if (bat->pdata->get_voltage) + val->intval = gta01_bat_voltscale( + bat->pdata->get_voltage()/1000); + else + val->intval = 0; + break; + default: return -EINVAL; } -- cgit v1.2.3 From 85c8727000a44c7932e534d63a28724bea4ab724 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Fri, 31 Jul 2009 00:47:41 +0400 Subject: gta01_battery: add charge_{now,full} properties Some userspace (notably Enlightment's batget) ignores "capacity" completely if there're no other properties. Expose a fake value (850mAh, typical for BL-5C) to make them happy. Signed-off-by: Paul Fertser --- drivers/power/gta01_battery.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/power/gta01_battery.c b/drivers/power/gta01_battery.c index 3c7c49777b0..2078b071b06 100644 --- a/drivers/power/gta01_battery.c +++ b/drivers/power/gta01_battery.c @@ -24,8 +24,13 @@ static enum power_supply_property gta01_bat_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, }; +/* Capacity of typical BL-5C dumb battery */ +#define GTA01_BAT_CHARGE_FULL 850000 + static int gta01_bat_voltscale(int volt) { /* This table is suggested by SpeedEvil based on analysis of @@ -83,6 +88,14 @@ static int gta01_bat_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_PRESENT: val->intval = 1; /* You must never run GTA01 without battery. */ break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + if (bat->pdata->get_voltage) { + int perc = gta01_bat_voltscale( + bat->pdata->get_voltage()/1000); + val->intval = perc * GTA01_BAT_CHARGE_FULL / 100; + } else + val->intval = 0; + break; case POWER_SUPPLY_PROP_CAPACITY: if (bat->pdata->get_voltage) val->intval = gta01_bat_voltscale( @@ -90,6 +103,9 @@ static int gta01_bat_get_property(struct power_supply *psy, else val->intval = 0; break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + val->intval = GTA01_BAT_CHARGE_FULL; + break; default: return -EINVAL; -- cgit v1.2.3 From 21658522b00d047212d7a78cb749648ff3bfeb04 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Tue, 28 Jul 2009 00:41:15 +0400 Subject: pcf50633: use a dedicated workqueue for irq processing Using the default kernel "events" workqueue causes problems with synchronous adc readings if initiated from some task on the same workqueue. I had a deadlock trying to use pcf50633_adc_sync_read from a power_supply class driver because the reading was initiated from the workqueue and it waited for the irq processing to complete (to get the result) and that was put on the same workqueue. Signed-off-by: Paul Fertser --- drivers/mfd/pcf50633-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 29c9395d65f..5006746ff5c 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -448,7 +448,7 @@ static irqreturn_t pcf50633_irq(int irq, void *data) get_device(pcf->dev); disable_irq(pcf->irq); - schedule_work(&pcf->irq_work); + queue_work(pcf->work_queue, &pcf->irq_work); return IRQ_HANDLED; } @@ -579,6 +579,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client, pcf->dev = &client->dev; pcf->i2c_client = client; pcf->irq = client->irq; + pcf->work_queue = create_singlethread_workqueue("pcf50633"); INIT_WORK(&pcf->irq_work, pcf50633_irq_worker); @@ -656,6 +657,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client, return 0; err: + destroy_workqueue(pcf->work_queue); kfree(pcf); return ret; } @@ -666,6 +668,7 @@ static int __devexit pcf50633_remove(struct i2c_client *client) int i; free_irq(pcf->irq, pcf); + destroy_workqueue(pcf->work_queue); platform_device_unregister(pcf->input_pdev); platform_device_unregister(pcf->rtc_pdev); -- cgit v1.2.3 From 1f0f8418cdbacc41ddf3adcce0b8552f075b26d7 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Tue, 28 Jul 2009 00:58:48 +0400 Subject: pcf50633: revise locking for ADC Current implementation is prone to races, this patch attempts to remove all but one (in pcf50633_adc_sync_read). The idea is that we need to guard the queue access only on inserting and removing items. If we insert and there're no more items in the queue it means that the last irq already happened and we need to trigger ADC manually. If not, then the next conversion will be triggered by the irq handler upon completion of the previous. Signed-off-by: Paul Fertser --- drivers/mfd/pcf50633-adc.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index c2d05becfa9..3d31e97d6a4 100644 --- a/drivers/mfd/pcf50633-adc.c +++ b/drivers/mfd/pcf50633-adc.c @@ -73,15 +73,10 @@ static void trigger_next_adc_job_if_any(struct pcf50633 *pcf) struct pcf50633_adc *adc = __to_adc(pcf); int head; - mutex_lock(&adc->queue_mutex); - head = adc->queue_head; - if (!adc->queue[head]) { - mutex_unlock(&adc->queue_mutex); + if (!adc->queue[head]) return; - } - mutex_unlock(&adc->queue_mutex); adc_setup(pcf, adc->queue[head]->mux, adc->queue[head]->avg); } @@ -99,16 +94,17 @@ adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req) if (adc->queue[tail]) { mutex_unlock(&adc->queue_mutex); + dev_err(pcf->dev, "ADC queue is full, dropping request\n"); return -EBUSY; } adc->queue[tail] = req; + if (head == tail) + trigger_next_adc_job_if_any(pcf); adc->queue_tail = (tail + 1) & (PCF50633_MAX_ADC_FIFO_DEPTH - 1); mutex_unlock(&adc->queue_mutex); - trigger_next_adc_job_if_any(pcf); - return 0; } @@ -124,6 +120,7 @@ pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result) int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg) { struct pcf50633_adc_request *req; + int err; /* req is freed when the result is ready, in interrupt handler */ req = kzalloc(sizeof(*req), GFP_KERNEL); @@ -136,9 +133,13 @@ int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg) req->callback_param = req; init_completion(&req->completion); - adc_enqueue_request(pcf, req); + err = adc_enqueue_request(pcf, req); + if (err) + return err; + wait_for_completion(&req->completion); + /* FIXME by this time req might be already freed */ return req->result; } EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read); @@ -159,9 +160,7 @@ int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg, req->callback = callback; req->callback_param = callback_param; - adc_enqueue_request(pcf, req); - - return 0; + return adc_enqueue_request(pcf, req); } EXPORT_SYMBOL_GPL(pcf50633_adc_async_read); @@ -184,7 +183,7 @@ static void pcf50633_adc_irq(int irq, void *data) struct pcf50633_adc *adc = data; struct pcf50633 *pcf = adc->pcf; struct pcf50633_adc_request *req; - int head; + int head, res; mutex_lock(&adc->queue_mutex); head = adc->queue_head; @@ -199,12 +198,13 @@ static void pcf50633_adc_irq(int irq, void *data) adc->queue_head = (head + 1) & (PCF50633_MAX_ADC_FIFO_DEPTH - 1); + res = adc_result(pcf); + trigger_next_adc_job_if_any(pcf); + mutex_unlock(&adc->queue_mutex); - req->callback(pcf, req->callback_param, adc_result(pcf)); + req->callback(pcf, req->callback_param, res); kfree(req); - - trigger_next_adc_job_if_any(pcf); } static int __devinit pcf50633_adc_probe(struct platform_device *pdev) -- cgit v1.2.3 From c31a0fec70c7ab1f9d0a5846abb31b80274e6914 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Wed, 29 Jul 2009 17:39:52 +0400 Subject: pcf50633: get rid of charging restart software auto-triggering After reaching Battery Full condition MBC state machine switches back into charging mode when the battery voltage falls below 96% of a battery float voltage. The voltage drop in Li-Ion batteries is marginal (1-2%) till about 80% of its capacity - which means, after a BATFULL, charging won't be restarted until 75-80%. That is a desired behaviour recommended by battery manufacturers, don't mess with it. Signed-off-by: Paul Fertser --- drivers/power/pcf50633-charger.c | 46 ---------------------------------------- 1 file changed, 46 deletions(-) (limited to 'drivers') diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c index 1bdb9906201..cda0c6792dd 100644 --- a/drivers/power/pcf50633-charger.c +++ b/drivers/power/pcf50633-charger.c @@ -37,8 +37,6 @@ struct pcf50633_mbc { struct power_supply usb; struct power_supply adapter; struct power_supply ac; - - struct delayed_work charging_restart_work; }; int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma) @@ -226,44 +224,10 @@ static struct attribute_group mbc_attr_group = { .attrs = pcf50633_mbc_sysfs_entries, }; -/* MBC state machine switches into charging mode when the battery voltage - * falls below 96% of a battery float voltage. But the voltage drop in Li-ion - * batteries is marginal(1~2 %) till about 80% of its capacity - which means, - * after a BATFULL, charging won't be restarted until 80%. - * - * This work_struct function restarts charging every few seconds and makes - * sure we don't discharge too much - */ - -static void pcf50633_mbc_charging_restart(struct work_struct *work) -{ - struct pcf50633_mbc *mbc; - u8 mbcs2, chgmod; - - mbc = container_of(work, struct pcf50633_mbc, - charging_restart_work.work); - - mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2); - chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK); - - if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL) - return; - - /* Restart charging */ - pcf50633_reg_set_bit_mask(mbc->pcf, PCF50633_REG_MBCC1, - PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME); - mbc->usb_active = 1; - power_supply_changed(&mbc->usb); - - dev_info(mbc->pcf->dev, "Charging restarted\n"); -} - static void pcf50633_mbc_irq_handler(int irq, void *data) { struct pcf50633_mbc *mbc = data; - int chg_restart_interval = - mbc->pcf->pdata->charging_restart_interval; /* USB */ if (irq == PCF50633_IRQ_USBINS) { @@ -272,7 +236,6 @@ pcf50633_mbc_irq_handler(int irq, void *data) mbc->usb_online = 0; mbc->usb_active = 0; pcf50633_mbc_usb_curlim_set(mbc->pcf, 0); - cancel_delayed_work_sync(&mbc->charging_restart_work); } /* Adapter */ @@ -287,10 +250,6 @@ pcf50633_mbc_irq_handler(int irq, void *data) if (irq == PCF50633_IRQ_BATFULL) { mbc->usb_active = 0; mbc->adapter_active = 0; - - if (chg_restart_interval > 0) - schedule_delayed_work(&mbc->charging_restart_work, - chg_restart_interval); } else if (irq == PCF50633_IRQ_USBLIMON) mbc->usb_active = 0; else if (irq == PCF50633_IRQ_USBLIMOFF) @@ -428,9 +387,6 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev) mbc->ac.supplied_to = mbc->pcf->pdata->batteries; mbc->ac.num_supplicants = mbc->pcf->pdata->num_batteries; - INIT_DELAYED_WORK(&mbc->charging_restart_work, - pcf50633_mbc_charging_restart); - ret = power_supply_register(&pdev->dev, &mbc->adapter); if (ret) { dev_err(mbc->pcf->dev, "failed to register adapter\n"); @@ -480,8 +436,6 @@ static int __devexit pcf50633_mbc_remove(struct platform_device *pdev) power_supply_unregister(&mbc->usb); power_supply_unregister(&mbc->adapter); - cancel_delayed_work_sync(&mbc->charging_restart_work); - kfree(mbc); return 0; -- cgit v1.2.3 From 37deadd5c1aca22e1be6793cbe09532485c1d43b Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Wed, 29 Jul 2009 18:09:20 +0400 Subject: pcf50633: properly reenable charging when the supply conditions change If chgmod == BATFULL, setting chgena has no effect. Datasheet says we need to set resume instead but when autoresume is used resume doesn't work. Clear and set chgena instead. This enables a user to force charging by re-plugging USB even when the charger entered Battery Full mode, might be handy before a long trip. Signed-off-by: Paul Fertser --- drivers/power/pcf50633-charger.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c index cda0c6792dd..5b5fe805fd9 100644 --- a/drivers/power/pcf50633-charger.c +++ b/drivers/power/pcf50633-charger.c @@ -90,14 +90,18 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma) chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK); /* If chgmod == BATFULL, setting chgena has no effect. - * We need to set resume instead. + * Datasheet says we need to set resume instead but when autoresume is + * used resume doesn't work. Clear and set chgena instead. */ if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL) pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1, PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA); - else + else { + pcf50633_reg_clear_bits(pcf, PCF50633_REG_MBCC1, + PCF50633_MBCC1_CHGENA); pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1, - PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME); + PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA); + } mbc->usb_active = charging_start; -- cgit v1.2.3 From 53bbb82febf74555ee737998d761b7d8e6b1317e Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Wed, 29 Jul 2009 18:24:39 +0400 Subject: pcf50633: query charger status directly Current scheme is fragile and is likely to go off sync, especially on batfull->adapter charging automatic MBC transition. Query the status bit every time we need it instead. We need to export another function to query for USB presence because we can't read anything from PCF50633 (via I2C) inside irq context and that is needed by usb gadgets. Signed-off-by: Paul Fertser --- drivers/power/pcf50633-charger.c | 45 ++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c index 5b5fe805fd9..6fbe26eb756 100644 --- a/drivers/power/pcf50633-charger.c +++ b/drivers/power/pcf50633-charger.c @@ -29,9 +29,7 @@ struct pcf50633_mbc { struct pcf50633 *pcf; - int adapter_active; int adapter_online; - int usb_active; int usb_online; struct power_supply usb; @@ -103,8 +101,6 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma) PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA); } - mbc->usb_active = charging_start; - power_supply_changed(&mbc->usb); return ret; @@ -115,23 +111,44 @@ int pcf50633_mbc_get_status(struct pcf50633 *pcf) { struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev); int status = 0; + u8 chgmod; if (!mbc) return 0; + chgmod = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2) + & PCF50633_MBCS2_MBC_MASK; + if (mbc->usb_online) status |= PCF50633_MBC_USB_ONLINE; - if (mbc->usb_active) + if (chgmod == PCF50633_MBCS2_MBC_USB_PRE || + chgmod == PCF50633_MBCS2_MBC_USB_PRE_WAIT || + chgmod == PCF50633_MBCS2_MBC_USB_FAST || + chgmod == PCF50633_MBCS2_MBC_USB_FAST_WAIT) status |= PCF50633_MBC_USB_ACTIVE; if (mbc->adapter_online) status |= PCF50633_MBC_ADAPTER_ONLINE; - if (mbc->adapter_active) + if (chgmod == PCF50633_MBCS2_MBC_ADP_PRE || + chgmod == PCF50633_MBCS2_MBC_ADP_PRE_WAIT || + chgmod == PCF50633_MBCS2_MBC_ADP_FAST || + chgmod == PCF50633_MBCS2_MBC_ADP_FAST_WAIT) status |= PCF50633_MBC_ADAPTER_ACTIVE; return status; } EXPORT_SYMBOL_GPL(pcf50633_mbc_get_status); +int pcf50633_mbc_get_usb_online_status(struct pcf50633 *pcf) +{ + struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev); + + if (!mbc) + return 0; + + return mbc->usb_online; +} +EXPORT_SYMBOL_GPL(pcf50633_mbc_get_usb_online_status); + static ssize_t show_chgmode(struct device *dev, struct device_attribute *attr, char *buf) { @@ -238,26 +255,14 @@ pcf50633_mbc_irq_handler(int irq, void *data) mbc->usb_online = 1; } else if (irq == PCF50633_IRQ_USBREM) { mbc->usb_online = 0; - mbc->usb_active = 0; pcf50633_mbc_usb_curlim_set(mbc->pcf, 0); } /* Adapter */ - if (irq == PCF50633_IRQ_ADPINS) { + if (irq == PCF50633_IRQ_ADPINS) mbc->adapter_online = 1; - mbc->adapter_active = 1; - } else if (irq == PCF50633_IRQ_ADPREM) { + else if (irq == PCF50633_IRQ_ADPREM) mbc->adapter_online = 0; - mbc->adapter_active = 0; - } - - if (irq == PCF50633_IRQ_BATFULL) { - mbc->usb_active = 0; - mbc->adapter_active = 0; - } else if (irq == PCF50633_IRQ_USBLIMON) - mbc->usb_active = 0; - else if (irq == PCF50633_IRQ_USBLIMOFF) - mbc->usb_active = 1; power_supply_changed(&mbc->usb); power_supply_changed(&mbc->adapter); -- cgit v1.2.3 From 8851834038aec76c07454f3620fa9fb1506e7217 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sun, 30 Aug 2009 11:55:48 +0400 Subject: Revert "AR6000: move low-level cleanup from ar6000_destroy to ar6000_close" This reverts commit 9c4451ff31b937a478f3d3eabef30b71cbe12b12. This commit made wifi unusable after ifconfig down and sometimes after unbinding. --- drivers/ar6000/ar6000/ar6000_drv.c | 150 ++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/ar6000/ar6000/ar6000_drv.c b/drivers/ar6000/ar6000/ar6000_drv.c index b790670ece8..21504f221dd 100644 --- a/drivers/ar6000/ar6000/ar6000_drv.c +++ b/drivers/ar6000/ar6000/ar6000_drv.c @@ -974,17 +974,86 @@ ar6000_destroy(struct net_device *dev, unsigned int unregister) return; } + /* Stop the transmit queues */ + netif_stop_queue(dev); + + /* Disable the target and the interrupts associated with it */ + if (ar->arWmiReady == TRUE) + { + if (!bypasswmi) + { + if (ar->arConnected == TRUE || ar->arConnectPending == TRUE) + { + AR_DEBUG_PRINTF("%s(): Disconnect\n", __func__); + AR6000_SPIN_LOCK(&ar->arLock, 0); + ar6000_init_profile_info(ar); + AR6000_SPIN_UNLOCK(&ar->arLock, 0); + wmi_disconnect_cmd(ar->arWmi); + } + + ar6000_dbglog_get_debug_logs(ar); + ar->arWmiReady = FALSE; + ar->arConnected = FALSE; + ar->arConnectPending = FALSE; + wmi_shutdown(ar->arWmi); + ar->arWmiEnabled = FALSE; + ar->arWmi = NULL; + ar->arWlanState = WLAN_ENABLED; +#ifdef USER_KEYS + ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_INIT; + ar->user_key_ctrl = 0; +#endif + } + + AR_DEBUG_PRINTF("%s(): WMI stopped\n", __func__); + } + else + { + AR_DEBUG_PRINTF("%s(): WMI not ready 0x%08x 0x%08x\n", + __func__, (unsigned int) ar, (unsigned int) ar->arWmi); + + /* Shut down WMI if we have started it */ + if(ar->arWmiEnabled == TRUE) + { + AR_DEBUG_PRINTF("%s(): Shut down WMI\n", __func__); + wmi_shutdown(ar->arWmi); + ar->arWmiEnabled = FALSE; + ar->arWmi = NULL; + } + } + + /* stop HTC */ + HTCStop(ar->arHtcTarget); + + /* set the instance to NULL so we do not get called back on remove incase we + * we're explicity destroyed by module unload */ + HTCSetInstance(ar->arHtcTarget, NULL); + + if (resetok) { + /* try to reset the device if we can + * The driver may have been configure NOT to reset the target during + * a debug session */ + AR_DEBUG_PRINTF(" Attempting to reset target on instance destroy.... \n"); + ar6000_reset_device(ar->arHifDevice, ar->arTargetType); + } else { + AR_DEBUG_PRINTF(" Host does not want target reset. \n"); + } + + /* Done with cookies */ + ar6000_cookie_cleanup(ar); + + /* Cleanup BMI */ + BMIInit(); + /* Clear the tx counters */ memset(tx_attempt, 0, sizeof(tx_attempt)); memset(tx_post, 0, sizeof(tx_post)); memset(tx_complete, 0, sizeof(tx_complete)); + /* Free up the device data structure */ - if (unregister) { - unregister_netdev(dev); - } else { - ar6000_close(dev); - } + if (unregister) + unregister_netdev(dev); free_raw_buffers(ar); @@ -1090,79 +1159,8 @@ ar6000_open(struct net_device *dev) static int ar6000_close(struct net_device *dev) { - AR_SOFTC_T *ar = netdev_priv(dev); - - /* Stop the transmit queues */ netif_stop_queue(dev); - /* Disable the target and the interrupts associated with it */ - if (ar->arWmiReady == TRUE) - { - if (!bypasswmi) - { - if (ar->arConnected == TRUE || ar->arConnectPending == TRUE) - { - AR_DEBUG_PRINTF("%s(): Disconnect\n", __func__); - AR6000_SPIN_LOCK(&ar->arLock, 0); - ar6000_init_profile_info(ar); - AR6000_SPIN_UNLOCK(&ar->arLock, 0); - wmi_disconnect_cmd(ar->arWmi); - } - - ar6000_dbglog_get_debug_logs(ar); - ar->arWmiReady = FALSE; - ar->arConnected = FALSE; - ar->arConnectPending = FALSE; - wmi_shutdown(ar->arWmi); - ar->arWmiEnabled = FALSE; - ar->arWmi = NULL; - ar->arWlanState = WLAN_ENABLED; -#ifdef USER_KEYS - ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_INIT; - ar->user_key_ctrl = 0; -#endif - } - - AR_DEBUG_PRINTF("%s(): WMI stopped\n", __func__); - } - else - { - AR_DEBUG_PRINTF("%s(): WMI not ready 0x%08x 0x%08x\n", - __func__, (unsigned int) ar, (unsigned int) ar->arWmi); - - /* Shut down WMI if we have started it */ - if(ar->arWmiEnabled == TRUE) - { - AR_DEBUG_PRINTF("%s(): Shut down WMI\n", __func__); - wmi_shutdown(ar->arWmi); - ar->arWmiEnabled = FALSE; - ar->arWmi = NULL; - } - } - - /* stop HTC */ - HTCStop(ar->arHtcTarget); - - /* set the instance to NULL so we do not get called back on remove incase we - * we're explicity destroyed by module unload */ - HTCSetInstance(ar->arHtcTarget, NULL); - - if (resetok) { - /* try to reset the device if we can - * The driver may have been configure NOT to reset the target during - * a debug session */ - AR_DEBUG_PRINTF(" Attempting to reset target on instance destroy.... \n"); - ar6000_reset_device(ar->arHifDevice, ar->arTargetType); - } else { - AR_DEBUG_PRINTF(" Host does not want target reset. \n"); - } - - /* Done with cookies */ - ar6000_cookie_cleanup(ar); - - /* Cleanup BMI */ - BMIInit(); - return 0; } -- cgit v1.2.3 From 05d6078079f605ea8740b9e7d87e421d1662222e Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Thu, 27 Aug 2009 11:37:49 +0400 Subject: pcf50606: move messages to appropriate log levels Signed-off-by: Arnaud Patard Signed-off-by: Paul Fertser --- drivers/mfd/pcf50606-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/pcf50606-core.c b/drivers/mfd/pcf50606-core.c index 7c4fb42b460..09ce70b9b79 100644 --- a/drivers/mfd/pcf50606-core.c +++ b/drivers/mfd/pcf50606-core.c @@ -282,7 +282,7 @@ out: int pcf50606_irq_mask(struct pcf50606 *pcf, int irq) { - dev_info(pcf->dev, "Masking IRQ %d\n", irq); + dev_dbg(pcf->dev, "Masking IRQ %d\n", irq); return __pcf50606_irq_mask_set(pcf, irq, 1); } @@ -290,7 +290,7 @@ EXPORT_SYMBOL_GPL(pcf50606_irq_mask); int pcf50606_irq_unmask(struct pcf50606 *pcf, int irq) { - dev_info(pcf->dev, "Unmasking IRQ %d\n", irq); + dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq); return __pcf50606_irq_mask_set(pcf, irq, 0); } @@ -330,7 +330,7 @@ static void pcf50606_irq_worker(struct work_struct *work) ret = pcf50606_read_block(pcf, PCF50606_REG_INT1, ARRAY_SIZE(pcf_int), pcf_int); if (ret != ARRAY_SIZE(pcf_int)) { - dev_info(pcf->dev, "Error reading INT registers\n"); + dev_err(pcf->dev, "Error reading INT registers\n"); /* * If this doesn't ACK the interrupt to the chip, we'll be -- cgit v1.2.3 From 4616eea5f3b3a603a03f31721de3eeb42dbd7711 Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Thu, 27 Aug 2009 11:39:33 +0400 Subject: pcf50633: move messages to appropriate log levels Signed-off-by: Arnaud Patard Signed-off-by: Paul Fertser --- drivers/mfd/pcf50633-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 5006746ff5c..b3c96015600 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -291,7 +291,7 @@ out: int pcf50633_irq_mask(struct pcf50633 *pcf, int irq) { - dev_info(pcf->dev, "Masking IRQ %d\n", irq); + dev_dbg(pcf->dev, "Masking IRQ %d\n", irq); return __pcf50633_irq_mask_set(pcf, irq, 1); } @@ -299,7 +299,7 @@ EXPORT_SYMBOL_GPL(pcf50633_irq_mask); int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq) { - dev_info(pcf->dev, "Unmasking IRQ %d\n", irq); + dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq); return __pcf50633_irq_mask_set(pcf, irq, 0); } -- cgit v1.2.3 From 65329e6e3de2b2fd07e524a3c10958f2acb7bcb0 Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Thu, 27 Aug 2009 11:46:41 +0400 Subject: pcf50606: fix RTC alarm This makes wake up on RTC alarm work properly, ported from rtc-pcf50633 commits 4caf79de95c26495e7cdc8204023d97598f887d2 and c3e4e22fb0c3e1d82f66e67f6592949e48f3995a. Signed-off-by: Arnaud Patard Signed-off-by: Paul Fertser --- drivers/rtc/rtc-pcf50606.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-pcf50606.c b/drivers/rtc/rtc-pcf50606.c index 434cfc1dca4..6bd93b0b672 100644 --- a/drivers/rtc/rtc-pcf50606.c +++ b/drivers/rtc/rtc-pcf50606.c @@ -58,6 +58,7 @@ struct pcf50606_time { struct pcf50606_rtc { int alarm_enabled; int second_enabled; + int alarm_pending; struct pcf50606 *pcf; struct rtc_device *rtc_dev; @@ -198,6 +199,7 @@ static int pcf50606_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) rtc = dev_get_drvdata(dev); alrm->enabled = rtc->alarm_enabled; + alrm->pending = rtc->alarm_pending; ret = pcf50606_read_block(rtc->pcf, PCF50606_REG_RTCSCA, PCF50606_TI_EXTENT, &pcf_tm.time[0]); @@ -234,8 +236,12 @@ static int pcf50606_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ret = pcf50606_write_block(rtc->pcf, PCF50606_REG_RTCSCA, PCF50606_TI_EXTENT, &pcf_tm.time[0]); - if (!alarm_masked) + if (!alrm->enabled) + rtc->alarm_pending = 0; + + if (!alarm_masked || alrm->enabled) pcf50606_irq_unmask(rtc->pcf, PCF50606_IRQ_ALARM); + rtc->alarm_enabled = alrm->enabled; return ret; } @@ -255,6 +261,7 @@ static void pcf50606_rtc_irq(int irq, void *data) switch (irq) { case PCF50606_IRQ_ALARM: rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); + rtc->alarm_pending = 1; break; case PCF50606_IRQ_SECOND: rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); -- cgit v1.2.3