[RESEND PATCH v3] drivers/tty: Folding Android's keyreset driver in sysRQ
From: Mathieu J. Poirier mathieu.poir...@linaro.org The last version of this patch was sent a week ago but did not generate comments or an acknowledgement. It is being resent after a rebase on 3.6-rc7. This patch adds keyreset functionality to the sysrq driver. It allows certain button/key combinations to be used in order to trigger device resets. The first time the key-combo is detected a work function that syncs the filesystems is scheduled and the kernel rebooted. If all the keys are released and then pressed again, it calls panic. Reboot on panic should be set for this to work. A platform device that specify a reset key-combo should be added to the board file to trigger the feature. Alternatively keys can be passed to the driver via the /sys/module/sysrq interface. This functionality comes from the keyreset driver submitted by Arve Hjønnevåg in the Android kernel. Cc: a...@android.com Cc: kernel-t...@android.com Cc: dmitry.torok...@gmail.com Cc: john.stu...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/tty/sysrq.c | 308 + include/linux/sysrq.h |8 ++ 2 files changed, 316 insertions(+), 0 deletions(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 05728894..c44056f 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -41,14 +41,30 @@ #include linux/slab.h #include linux/input.h #include linux/uaccess.h +#include linux/platform_device.h +#include linux/syscalls.h +#include linux/atomic.h +#include linux/moduleparam.h +#include linux/mutex.h #include asm/ptrace.h #include asm/irq_regs.h +#define KEY_DOWN_MAX 20 /* how many is enough ? */ +int keyreset_param[KEY_DOWN_MAX]; +struct mutex sysrq_mutex; +static struct sysrq_state *sysrq_handle; + /* Whether we react on sysrq keys or just ignore them */ static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; static bool __read_mostly sysrq_always_enabled; +static struct input_handler sysrq_handler; + +/* Keep track of what has been called */ +static atomic_t restart_requested; + + static bool sysrq_on(void) { return sysrq_enabled || sysrq_always_enabled; @@ -570,6 +586,15 @@ struct sysrq_state { struct input_handle handle; struct work_struct reinject_work; unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; + unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long key[BITS_TO_LONGS(KEY_CNT)]; + int (*reset_fn)(void); + int key_down_target; + int key_down_ctn; + int key_up_ctn; + int keyreset_data; + int restart_disabled; unsigned int alt; unsigned int alt_use; bool active; @@ -603,6 +628,101 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work) } } + +static int sysrq_probe(struct platform_device *pdev) +{ + struct keyreset_platform_data *pdata = pdev-dev.platform_data; + + /* +* No sequence of keys to trigger on, +* assuming default sysRQ behavior. +*/ + if (pdata) { + atomic_set(restart_requested, 0); + sysrq_handler.private = pdata; + } else + sysrq_handler.private = NULL; + + /* FETCH DT INFO HERE */ + + return 0; + +} + +static void deferred_restart(struct work_struct *dummy) +{ + atomic_inc(restart_requested); + sys_sync(); + atomic_inc(restart_requested); + kernel_restart(NULL); +} +static DECLARE_WORK(restart_work, deferred_restart); + +static int do_keyreset_event(struct sysrq_state *state, +unsigned int code, int value) +{ + int ret; + int processed = 0; + + mutex_lock(sysrq_mutex); + + /* Is the code of interest to us */ + if (!test_bit(code, state-keybit)) { + mutex_unlock(sysrq_mutex); + return processed; + } + + /* No need to take care of key up events */ + if (!test_bit(code, state-key) == !value) { + mutex_unlock(sysrq_mutex); + return processed; + } + + /* Record new entry */ + __change_bit(code, state-key); + + processed = 1; + + if (test_bit(code, state-upbit)) { + if (value) { + state-restart_disabled = 1; + state-key_up_ctn++; + } else + state-key_up_ctn--; + } else { + if (value) + state-key_down_ctn++; + else + state-key_down_ctn--; + } + + if (state-key_down_ctn == 0 state-key_up_ctn == 0) + state-restart_disabled = 0; + + if (value !state-restart_disabled + state-key_down_ctn == state-key_down_target) { + state-restart_disabled = 1; + if (atomic_read
[PATCH 01/57] power: ab8500_bm: Charger current step-up/down
From: Johan Bjornstedt johan.bjornst...@stericsson.com There is no state machine in the AB to step up/down the charger current to avoid dips and spikes on VBUS and VBAT when charging is started. Instead this is implemented in SW Signed-off-by: Johan Bjornstedt johan.bjornst...@stericsson.com Signed-off-by: Mattias Wallin mattias.wal...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Karl KOMIEROWSKI karl.komierow...@stericsson.com --- drivers/power/ab8500_charger.c | 172 +++- 1 files changed, 133 insertions(+), 39 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index d4f0c98..3ceb788 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -77,6 +77,9 @@ /* Lowest charger voltage is 3.39V - 0x4E */ #define LOW_VOLT_REG 0x4E +/* Step up/down delay in us */ +#define STEP_UDELAY1000 + /* UsbLineStatus register - usb types */ enum ab8500_charger_link_status { USB_STAT_NOT_CONFIGURED, @@ -934,6 +937,88 @@ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) } /** + * ab8500_charger_set_current() - set charger current + * @di:pointer to the ab8500_charger structure + * @ich: charger current, in mA + * @reg: select what charger register to set + * + * Set charger current. + * There is no state machine in the AB to step up/down the charger + * current to avoid dips and spikes on MAIN, VBUS and VBAT when + * charging is started. Instead we need to implement + * this charger current step-up/down here. + * Returns error code in case of failure else 0(on success) + */ +static int ab8500_charger_set_current(struct ab8500_charger *di, + int ich, int reg) +{ + int ret, i; + int curr_index, prev_curr_index, shift_value; + u8 reg_value; + + switch (reg) { + case AB8500_MCH_IPT_CURLVL_REG: + shift_value = MAIN_CH_INPUT_CURR_SHIFT; + curr_index = ab8500_current_to_regval(ich); + break; + case AB8500_USBCH_IPT_CRNTLVL_REG: + shift_value = VBUS_IN_CURR_LIM_SHIFT; + curr_index = ab8500_vbus_in_curr_to_regval(ich); + break; + case AB8500_CH_OPT_CRNTLVL_REG: + shift_value = 0; + curr_index = ab8500_current_to_regval(ich); + break; + default: + dev_err(di-dev, %s current register not valid\n, __func__); + return -ENXIO; + } + + if (curr_index 0) { + dev_err(di-dev, requested current limit out-of-range\n); + return -ENXIO; + } + + ret = abx500_get_register_interruptible(di-dev, AB8500_CHARGER, + reg, reg_value); + if (ret 0) { + dev_err(di-dev, %s read failed\n, __func__); + return ret; + } + prev_curr_index = (reg_value shift_value); + + /* only update current if it's been changed */ + if (prev_curr_index == curr_index) + return 0; + + dev_dbg(di-dev, %s set charger current: %d mA for reg: 0x%02x\n, + __func__, ich, reg); + + if (prev_curr_index curr_index) { + for (i = prev_curr_index - 1; i = curr_index; i--) { + ret = abx500_set_register_interruptible(di-dev, + AB8500_CHARGER, reg, (u8) i shift_value); + if (ret) { + dev_err(di-dev, %s write failed\n, __func__); + return ret; + } + usleep_range(STEP_UDELAY, STEP_UDELAY * 2); + } + } else { + for (i = prev_curr_index + 1; i = curr_index; i++) { + ret = abx500_set_register_interruptible(di-dev, + AB8500_CHARGER, reg, (u8) i shift_value); + if (ret) { + dev_err(di-dev, %s write failed\n, __func__); + return ret; + } + usleep_range(STEP_UDELAY, STEP_UDELAY * 2); + } + } + return ret; +} + +/** * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit * @di:pointer to the ab8500_charger structure * @ich_in:charger input current limit @@ -944,8 +1029,6 @@ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, int ich_in) { - int ret; - int input_curr_index; int min_value; /* We should always use to lowest current limit */ @@ -964,19 +1047,38 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, break; } - input_curr_index
[PATCH 04/57] power: ab8500: bm: movimg back to ab8500 platform data managment
From: Philippe Langlais philippe.langl...@linaro.org Signed-off-by: Philippe Langlais philippe.langl...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/power/ab8500_btemp.c |8 ++-- drivers/power/ab8500_charger.c|9 +++-- drivers/power/ab8500_fg.c |8 ++-- drivers/power/abx500_chargalg.c |7 --- include/linux/mfd/abx500/ab8500.h |7 ++- 5 files changed, 17 insertions(+), 22 deletions(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index 94a3ee8..41a8ce4 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -973,14 +973,9 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) { int irq, i, ret = 0; u8 val; - struct abx500_bm_plat_data *plat_data = pdev-dev.platform_data; + struct ab8500_platform_data *plat_data; struct ab8500_btemp *di; - if (!plat_data) { - dev_err(pdev-dev, No platform data\n); - return -EINVAL; - } - di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) return -ENOMEM; @@ -993,6 +988,7 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) di-initialized = false; /* get btemp specific platform data */ + plat_data = dev_get_platdata(di-parent-dev); di-pdata = plat_data-btemp; if (!di-pdata) { dev_err(di-dev, no btemp platform data supplied\n); diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 3ceb788..22076f5 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2628,14 +2628,9 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev) static int __devinit ab8500_charger_probe(struct platform_device *pdev) { int irq, i, charger_status, ret = 0; - struct abx500_bm_plat_data *plat_data = pdev-dev.platform_data; + struct ab8500_platform_data *plat_data; struct ab8500_charger *di; - if (!plat_data) { - dev_err(pdev-dev, No platform data\n); - return -EINVAL; - } - di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) return -ENOMEM; @@ -2649,6 +2644,8 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) spin_lock_init(di-usb_state.usb_lock); /* get charger specific platform data */ + plat_data = dev_get_platdata(di-parent-dev); + di-pdata = plat_data-charger; if (!di-pdata) { dev_err(di-dev, no charger platform data supplied\n); diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index af792a8..c098ddd 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2446,14 +2446,9 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) { int i, irq; int ret = 0; - struct abx500_bm_plat_data *plat_data = pdev-dev.platform_data; + struct ab8500_platform_data *plat_data; struct ab8500_fg *di; - if (!plat_data) { - dev_err(pdev-dev, No platform data\n); - return -EINVAL; - } - di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) return -ENOMEM; @@ -2466,6 +2461,7 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) di-gpadc = ab8500_gpadc_get(ab8500-gpadc.0); /* get fg specific platform data */ + plat_data = dev_get_platdata(di-parent-dev); di-pdata = plat_data-fg; if (!di-pdata) { dev_err(di-dev, no fg platform data supplied\n); diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 804b88c..032b27d 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -220,6 +220,7 @@ enum maxim_ret { */ struct abx500_chargalg { struct device *dev; + struct ab8500 *parent; int charge_status; int eoc_cnt; int rch_cnt; @@ -1802,7 +1803,7 @@ static int __devexit abx500_chargalg_remove(struct platform_device *pdev) static int __devinit abx500_chargalg_probe(struct platform_device *pdev) { - struct abx500_bm_plat_data *plat_data; + struct ab8500_platform_data *plat_data; int ret = 0; struct abx500_chargalg *di = @@ -1812,8 +1813,8 @@ static int __devinit abx500_chargalg_probe(struct platform_device *pdev) /* get device struct */ di-dev = pdev-dev; - - plat_data = pdev-dev.platform_data; + di-parent = dev_get_drvdata(pdev-dev.parent); + plat_data = dev_get_platdata(di-parent-dev); di-pdata = plat_data-chargalg; di-bat = plat_data-battery; diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h index 3764cb6..db8a1e3 100644 --- a/include/linux/mfd/abx500/ab8500.h +++ b/include/linux/mfd
[PATCH 09/57] power: ab8500_fg: usleep_range instead of short msleep
From: Jonas Aaberg jonas.ab...@stericsson.com Signed-off-by: Jonas ABERG jonas.ab...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Johan BJORNSTEDT johan.bjornst...@stericsson.com --- drivers/power/ab8500_fg.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 1e02b00..0db17c7 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -957,7 +957,7 @@ static int ab8500_fg_load_comp_volt_to_capacity(struct ab8500_fg *di) do { vbat += ab8500_fg_bat_voltage(di); i++; - msleep(5); + usleep_range(5000, 5001); } while (!ab8500_fg_inst_curr_done(di)); ab8500_fg_inst_curr_finalize(di, di-inst_curr); -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 18/57] power: Add sysfs interfaces for capacity
From: Daniel WILLERUD daniel.wille...@stericsson.com Switchable depending on whether capacity scaling is enabled Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Daniel WILLERUD daniel.wille...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_fg.c | 57 - 1 files changed, 56 insertions(+), 1 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 8507254..46010ec 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -266,7 +266,6 @@ static enum power_supply_property ab8500_fg_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_NOW, - POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_LEVEL, }; @@ -2543,6 +2542,54 @@ static int ab8500_fg_sysfs_init(struct ab8500_fg *di) return ret; } + +static ssize_t ab8500_show_capacity(struct device *dev, +struct device_attribute *attr, +char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct ab8500_fg *di; + int capacity; + + di = to_ab8500_fg_device_info(psy); + + if (di-bat-capacity_scaling) + capacity = di-bat_cap.cap_scale.scaled_cap; + else + capacity = DIV_ROUND_CLOSEST(di-bat_cap.permille, 10); + + return scnprintf(buf, PAGE_SIZE, %d\n, capacity); +} + +static struct device_attribute ab8500_fg_sysfs_psy_attrs[] = { + __ATTR(capacity, S_IRUGO, ab8500_show_capacity, NULL), +}; + +static int ab8500_fg_sysfs_psy_create_attrs(struct device *dev) +{ + unsigned int i; + + for (i = 0; i ARRAY_SIZE(ab8500_fg_sysfs_psy_attrs); i++) + if (device_create_file(dev, ab8500_fg_sysfs_psy_attrs[i])) + goto sysfs_psy_create_attrs_failed; + + return 0; + +sysfs_psy_create_attrs_failed: + dev_err(dev, Failed creating sysfs psy attrs.\n); + while (i--) + device_remove_file(dev, ab8500_fg_sysfs_psy_attrs[i]); + + return -EIO; +} + +static void ab8500_fg_sysfs_psy_remove_attrs(struct device *dev) +{ + unsigned int i; + + for (i = 0; i ARRAY_SIZE(ab8500_fg_sysfs_psy_attrs); i++) + (void)device_remove_file(dev, ab8500_fg_sysfs_psy_attrs[i]); +} /* Exposure to the sysfs interface END */ #if defined(CONFIG_PM) @@ -2599,6 +2646,7 @@ static int __devexit ab8500_fg_remove(struct platform_device *pdev) ab8500_fg_sysfs_exit(di); flush_scheduled_work(); + ab8500_fg_sysfs_psy_remove_attrs(di-fg_psy.dev); power_supply_unregister(di-fg_psy); platform_set_drvdata(pdev, NULL); kfree(di); @@ -2754,6 +2802,13 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) goto free_irq; } + ret = ab8500_fg_sysfs_psy_create_attrs(di-fg_psy.dev); + if (ret) { + dev_err(di-dev, failed to create FG psy\n); + ab8500_fg_sysfs_exit(di); + goto free_irq; + } + /* Calibrate the fg first time */ di-flags.calibrate = true; di-calib_state = AB8500_FG_CALIB_INIT; -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 24/57] power: ab8500_fg: Adjust for RF bursts voltage drops.
From: Hakan Berg hakan.b...@stericsson.com Changed conditions for restarting low battery measurements counter and adjusted the interval between measurements to avoid RF burst induced voltage drops, and to shorten time to decide to shut down. Signed-off-by: Hakan Berg hakan.b...@stericsson.com Signed-off-by: Martin Bergstrom martin.bergst...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com --- drivers/power/ab8500_fg.c | 44 ++-- 1 files changed, 30 insertions(+), 14 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 7c42150..861927d 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -42,7 +42,7 @@ #define NBR_AVG_SAMPLES20 -#define LOW_BAT_CHECK_INTERVAL (2 * HZ) +#define LOW_BAT_CHECK_INTERVAL (HZ / 16) /* 62.5 ms */ #define VALID_CAPACITY_SEC (45 * 60) /* 45 minutes */ #define BATT_OK_MIN2360 /* mV */ @@ -168,6 +168,7 @@ struct inst_curr_result_list { * @recovery_cnt: Counter for recovery mode * @high_curr_cnt: Counter for high current mode * @init_cnt: Counter for init mode + * @low_bat_cntCounter for number of consecutive low battery measures * @nbr_cceoc_irq_cnt Counter for number of CCEOC irqs received since enabled * @recovery_needed: Indicate if recovery is needed * @high_curr_mode:Indicate if we're in high current mode @@ -210,6 +211,7 @@ struct ab8500_fg { int recovery_cnt; int high_curr_cnt; int init_cnt; + int low_bat_cnt; int nbr_cceoc_irq_cnt; bool recovery_needed; bool high_curr_mode; @@ -1882,25 +1884,29 @@ static void ab8500_fg_low_bat_work(struct work_struct *work) /* Check if LOW_BAT still fulfilled */ if (vbat di-bat-fg_params-lowbat_threshold) { - di-flags.low_bat = true; - dev_warn(di-dev, Battery voltage still LOW\n); - - /* -* We need to re-schedule this check to be able to detect -* if the voltage increases again during charging -*/ - queue_delayed_work(di-fg_wq, di-fg_low_bat_work, - round_jiffies(LOW_BAT_CHECK_INTERVAL)); + /* Is it time to shut down? */ + if (di-low_bat_cnt 1) { + di-flags.low_bat = true; + dev_warn(di-dev, Shut down pending...\n); + } else { + /* + * Else we need to re-schedule this check to be able + * to detect if the voltage increases again during + * charging or due to decreasing load. + */ + di-low_bat_cnt--; + dev_warn(di-dev, Battery voltage still LOW\n); + queue_delayed_work(di-fg_wq, di-fg_low_bat_work, + round_jiffies(LOW_BAT_CHECK_INTERVAL)); + } } else { - di-flags.low_bat = false; + di-flags.low_bat_delay = false; + di-low_bat_cnt = 10; dev_warn(di-dev, Battery voltage OK again\n); } /* This is needed to dispatch LOW_BAT */ ab8500_fg_check_capacity_limits(di, false); - - /* Set this flag to check if LOW_BAT IRQ still occurs */ - di-flags.low_bat_delay = false; } /** @@ -2059,6 +2065,10 @@ static irqreturn_t ab8500_fg_lowbatf_handler(int irq, void *_di) { struct ab8500_fg *di = _di; + /* +* Initiate handling in ab8500_fg_low_bat_work() if not already +* initiated. +*/ if (!di-flags.low_bat_delay) { dev_warn(di-dev, Battery voltage is below LOW threshold\n); di-flags.low_bat_delay = true; @@ -2748,6 +2758,12 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) INIT_DELAYED_WORK_DEFERRABLE(di-fg_check_hw_failure_work, ab8500_fg_check_hw_failure_work); + /* Reset battery low voltage flag */ + di-flags.low_bat = false; + + /* Initialize low battery counter */ + di-low_bat_cnt = 10; + /* Initialize OVV, and other registers */ ret = ab8500_fg_init_hw_registers(di); if (ret) { -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 31/57] power: ab8500_fg: fix to use correct battery charge full design
From: Rajkumar Kasirajan rajkumar.kasira...@stericsson.com If battery is not identified while fg probe, mah_max_design gets initialized with unknown battery's charge full design. Reinitialize mah_max_design if battery is identified after fg probe. Signed-off-by: Rajkumar Kasirajan rajkumar.kasira...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com Reviewed-by: Vijaya Kumar K-1 vijay.kil...@stericsson.com Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Olivier CLERGEAUD olivier.clerge...@stericsson.com Reviewed-by: Arun MURTHY arun.mur...@stericsson.com Reviewed-by: Rupesh KUMAR rupesh.ku...@stericsson.com Reviewed-by: Rabin VINCENT rabin.vinc...@stericsson.com --- drivers/power/ab8500_fg.c |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 0e71e7e..5e4a46b 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2258,9 +2258,9 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) case POWER_SUPPLY_PROP_TECHNOLOGY: switch (ext-type) { case POWER_SUPPLY_TYPE_BATTERY: - if (!di-flags.batt_id_received) { + if (!di-flags.batt_id_received + di-bat-batt_id != BATTERY_UNKNOWN) { const struct abx500_battery_type *b; - b = (di-bat-bat_type[di-bat-batt_id]); di-flags.batt_id_received = true; -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 34/57] power: ab8500_fg: add power cut feature for ab8505
From: Rikard Olsson rikard.p.ols...@stericsson.com Add support for a power cut feature which allows user to configure when ab8505 should shut down system due to low battery. Signed-off-by: Rikard Olsson rikard.p.ols...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Martin SJOBLOM martin.w.sjob...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_fg.c| 488 +- include/linux/mfd/abx500.h | 10 + include/linux/mfd/abx500/ab8500-bm.h |8 + 3 files changed, 502 insertions(+), 4 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 5e4a46b..fde189a 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2351,6 +2351,64 @@ static int ab8500_fg_init_hw_registers(struct ab8500_fg *di) dev_err(di-dev, BattOk init write failed.\n); goto out; } + + if ((is_ab8505(di-parent) || is_ab9540(di-parent)) + abx500_get_chip_id(di-dev) = AB8500_CUT2P0) { + ret = abx500_set_register_interruptible(di-dev, AB8500_RTC, + AB8505_RTC_PCUT_MAX_TIME_REG, +di-bat-fg_params-pcut_max_time); + + if (ret) { + dev_err(di-dev, + %s write failed AB8505_RTC_PCUT_MAX_TIME_REG\n, +__func__); + goto out; + }; + + ret = abx500_set_register_interruptible(di-dev, AB8500_RTC, + AB8505_RTC_PCUT_FLAG_TIME_REG, +di-bat-fg_params-pcut_flag_time); + + if (ret) { + dev_err(di-dev, + %s write failed AB8505_RTC_PCUT_FLAG_TIME_REG\n, +__func__); + goto out; + }; + + ret = abx500_set_register_interruptible(di-dev, AB8500_RTC, + AB8505_RTC_PCUT_RESTART_REG, + di-bat-fg_params-pcut_max_restart); + + if (ret) { + dev_err(di-dev, + %s write failed AB8505_RTC_PCUT_RESTART_REG\n, +__func__); + goto out; + }; + + ret = abx500_set_register_interruptible(di-dev, AB8500_RTC, + AB8505_RTC_PCUT_DEBOUNCE_REG, +di-bat-fg_params-pcut_debunce_time); + + if (ret) { + dev_err(di-dev, + %s write failed AB8505_RTC_PCUT_DEBOUNCE_REG\n, +__func__); + goto out; + }; + + ret = abx500_set_register_interruptible(di-dev, AB8500_RTC, + AB8505_RTC_PCUT_CTL_STATUS_REG, +di-bat-fg_params-pcut_enable); + + if (ret) { + dev_err(di-dev, + %s write failed AB8505_RTC_PCUT_CTL_STATUS_REG\n, +__func__); + goto out; + }; + } out: return ret; } @@ -2572,22 +2630,433 @@ static ssize_t ab8500_show_capacity(struct device *dev, return scnprintf(buf, PAGE_SIZE, %d\n, capacity); } +static ssize_t ab8505_powercut_flagtime_read(struct device *dev, +struct device_attribute *attr, +char *buf) +{ + int ret; + u8 reg_value; + struct power_supply *psy = dev_get_drvdata(dev); + struct ab8500_fg *di; + + di = to_ab8500_fg_device_info(psy); + + ret = abx500_get_register_interruptible(di-dev, AB8500_RTC, + AB8505_RTC_PCUT_FLAG_TIME_REG, reg_value); + + if (ret 0) { + dev_err(dev, Failed to read AB8505_RTC_PCUT_FLAG_TIME_REG\n); + goto fail; + } + + return scnprintf(buf, PAGE_SIZE, %d\n, (reg_value 0x7F)); + +fail: + return ret; +} + +static ssize_t ab8505_powercut_flagtime_write(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + long unsigned reg_value; + struct power_supply *psy = dev_get_drvdata(dev); + struct ab8500_fg *di; + + di = to_ab8500_fg_device_info(psy); + + if (kstrtoul(buf, 10, reg_value) != 0) + goto fail; + + if (reg_value 0x7F) { + dev_err(dev, Incorrect parameter, echo 0 (1.98s) - 127 (15.625ms) for flagtime\n); + goto fail; + } + + ret = abx500_set_register_interruptible(di-dev, AB8500_RTC, + AB8505_RTC_PCUT_FLAG_TIME_REG, (u8)reg_value); + + if (ret 0
[PATCH 51/57] power: ab8500: Re-alignment with internal developement.
From: Mathieu J. Poirier mathieu.poir...@linaro.org A lot of developement happened internally since the first mainlining of the battery managmenent driver. Most of the new code can be historically accounted for but some of it can't. This patch is a gathering of the code for which history was lost but still relevant to the well being of the driver. Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/power/ab8500_charger.c |2 +- drivers/power/abx500_chargalg.c | 66 +++ 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 1290470..3a97012 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -720,7 +720,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, di-is_aca_rid = 0; break; case USB_STAT_ACA_RID_C_HS_CHIRP: - case USB_STAT_ACA_RID_C_NM: + case USB_STAT_ACA_RID_C_NM: di-max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P5; di-is_aca_rid = 1; break; diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 1df238f..636d970 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -27,7 +27,7 @@ #include linux/notifier.h /* Watchdog kick interval */ -#define CHG_WD_INTERVAL(6 * HZ) +#define CHG_WD_INTERVAL(60 * HZ) /* End-of-charge criteria counter */ #define EOC_COND_CNT 10 @@ -513,7 +513,7 @@ static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di) static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable, int vset, int iset) { - static int ab8500_chargalg_ex_ac_enable_toggle; + static int abx500_chargalg_ex_ac_enable_toggle; if (!di-ac_chg || !di-ac_chg-ops.enable) return -ENXIO; @@ -529,10 +529,10 @@ static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable, /*enable external charger*/ if (enable di-ac_chg-external - !ab8500_chargalg_ex_ac_enable_toggle) { + !abx500_chargalg_ex_ac_enable_toggle) { blocking_notifier_call_chain(charger_notifier_list, 0, di-dev); - ab8500_chargalg_ex_ac_enable_toggle++; + abx500_chargalg_ex_ac_enable_toggle++; } return di-ac_chg-ops.enable(di-ac_chg, enable, vset, iset); @@ -899,6 +899,27 @@ static void handle_maxim_chg_curr(struct abx500_chargalg *di) } } +static void abx500_chargalg_check_safety_timer(struct abx500_chargalg *di) +{ + /* +* The safety timer will not be started until the capacity reported +* from the FG algorithm is 100%. Then we know that the amount of +* charge that's gone into the battery is enough for the battery +* to be full. If it has not reached end-of-charge before the safety +* timer has expired then we know that the battery is overcharged +* and charging will be stopped to protect the battery. +*/ + if (di-batt_data.percent == 100 + !timer_pending(di-safety_timer)) { + abx500_chargalg_start_safety_timer(di); + dev_dbg(di-dev, start safety timer\n); + } else if (di-batt_data.percent != 100 + timer_pending(di-safety_timer)) { + abx500_chargalg_stop_safety_timer(di); + dev_dbg(di-dev, stop safety timer\n); + } +} + static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) { struct power_supply *psy; @@ -1125,6 +1146,10 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) switch (ext-type) { case POWER_SUPPLY_TYPE_BATTERY: di-batt_data.volt = ret.intval / 1000; + if (di-batt_data.volt = BATT_OVV_VALUE) + di-events.batt_ovv = true; + else + di-events.batt_ovv = false; break; case POWER_SUPPLY_TYPE_MAINS: di-chg_info.ac_volt = ret.intval / 1000; @@ -1214,7 +1239,6 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) } break; case POWER_SUPPLY_PROP_CAPACITY: - di-batt_data.percent = ret.intval; if (!capacity_updated) di-batt_data.percent = ret.intval; break; @@ -1465,12 +1489,12 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di
[PATCH 54/57] power: ab8500_charger: Use USBLink1Status Register
From: Marcus Cooper marcus.xm.coo...@stericsson.com The newer AB's such as the AB8505, AB9540 etc include a USBLink1 Status register which detects a larger range of external devices. This should be used instead of the USBLine Status register. Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Hakan BERG hakan.b...@stericsson.com Reviewed-by: Yang QU yang...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_charger.c | 22 -- 1 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 3a97012..7f8f362 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2258,8 +2258,13 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) * to start the charging process. but by jumping * thru a few hoops it can be forced to start. */ - ret = abx500_get_register_interruptible(di-dev, AB8500_USB, - AB8500_USB_LINE_STAT_REG, val); + if (is_ab8500(di-parent)) + ret = abx500_get_register_interruptible(di-dev, AB8500_USB, + AB8500_USB_LINE_STAT_REG, val); + else + ret = abx500_get_register_interruptible(di-dev, AB8500_USB, + AB8500_USB_LINK1_STAT_REG, val); + if (ret = 0) dev_dbg(di-dev, UsbLineStatus register = 0x%02x\n, val); else @@ -2299,10 +2304,15 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) AB8500_MCH_IPT_CURLVL_REG, 0x01, 0x00); /*Check link status*/ - ret = abx500_get_register_interruptible(di-dev, - AB8500_USB, - AB8500_USB_LINE_STAT_REG, - val); + if (is_ab8500(di-parent)) + ret = abx500_get_register_interruptible(di-dev, + AB8500_USB, AB8500_USB_LINE_STAT_REG, + val); + else + ret = abx500_get_register_interruptible(di-dev, + AB8500_USB, AB8500_USB_LINK1_STAT_REG, + val); + dev_dbg(di-dev, USB link status= 0x%02x\n, (val link_status) USB_LINK_STATUS_SHIFT); di-invalid_charger_detect_state = 2; -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 57/57] power: ab8500_charger: Limit USB charger current
From: Martin Bergstrom martin.bergst...@stericsson.com The USB charger current is limited according to information comming from the USB driver Signed-off-by: Martin Bergstrom martin.bergst...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_charger.c |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index afb4fda..3c6f11c 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -1248,6 +1248,9 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, if (di-max_usb_in_curr.set_max 0) min_value = min(di-max_usb_in_curr.set_max, min_value); + if (di-usb_state.usb_current = 0) + min_value = min(di-usb_state.usb_current, min_value); + switch (min_value) { case 100: if (di-vbat VBAT_TRESH_IP_CUR_RED) @@ -3413,6 +3416,7 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) di-usb_chg.wdt_refresh = CHG_WD_INTERVAL; di-usb_chg.enabled = di-pdata-usb_enabled; di-usb_chg.external = false; + di-usb_state.usb_current = -1; /* Create a work queue for the charger */ di-charger_wq = -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 56/57] power: abx500_chargalg: Fix quick re-attach charger issue.
From: Marcus Cooper marcus.xm.coo...@stericsson.com The patch for 426250 added a change to check for the quick re-attachment of the charger connection as an error in the AB8500 HW meant that a quick detach/attach wouldn't be detected. This patch isolates the original change so that newer AB's are not affected. Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Martin SJOBLOM martin.w.sjob...@stericsson.com Reviewed-by: Hakan BERG hakan.b...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/abx500_chargalg.c | 11 ++- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index c8849af..7a81e4e 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -1299,11 +1299,12 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) abx500_chargalg_check_charger_voltage(di); charger_status = abx500_chargalg_check_charger_connection(di); - ret = abx500_chargalg_check_charger_enable(di); - if (ret 0) - dev_err(di-dev, Checking charger if enabled error: %d line: %d\n, - ret, __LINE__); - + if (is_ab8500(di-parent)) { + ret = abx500_chargalg_check_charger_enable(di); + if (ret 0) + dev_err(di-dev, Checking charger is enabled error); + dev_err(di-dev, : Returned Value %d\n, ret); + } /* * First check if we have a charger connected. * Also we don't allow charging of unknown batteries if configured -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 44/57] power: ab8500: remove unecesary define flag
From: Marcus Cooper marcus.xm.coo...@stericsson.com Remove flag that serve no purpose from source code, Kconfig and Makefile. Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Hakan BERG hakan.b...@stericsson.com Reviewed-by: Mian Yousaf KAUKAB mian.yousaf.kau...@stericsson.com --- drivers/power/Kconfig |7 --- drivers/power/ab8500_charger.c |2 +- 2 files changed, 1 insertions(+), 8 deletions(-) diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index c1892f3..f7c13ae 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -303,13 +303,6 @@ config AB8500_BM depends on AB8500_CORE AB8500_GPADC help Say Y to include support for AB8500 battery management. - -config AB8500_BATTERY_THERM_ON_BATCTRL - bool Thermistor connected on BATCTRL ADC - depends on AB8500_BM - help - Say Y to enable battery temperature measurements using - thermistor connected on BATCTRL ADC. endif # POWER_SUPPLY source drivers/power/avs/Kconfig diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 9449a33..d90fe9f 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -3369,7 +3369,7 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev) flush_scheduled_work(); if (di-usb_chg.enabled) power_supply_unregister(di-usb_chg.psy); - if (di-ac_chg.enabled) + if (di-ac_chg.enabled !di-ac_chg.external) power_supply_unregister(di-ac_chg.psy); platform_set_drvdata(pdev, NULL); -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 46/57] power: chargealg: Realign with upstream version
From: Loic Pallardy loic.palla...@stericsson.com Upstream version of AB charge algo has been reverted during kernel 3.4 port. This patch restore state by: - renaming ab8500_chargal.c in abx500_chargal.c - renaming function from ab8500 to abx500 - moving generic structure in include/mfd/abx500.h Goal is to ease next code reversion and realignment with mainline Signed-off-by: Loic Pallardy loic.palla...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Philippe LANGLAIS philippe.langl...@stericsson.com --- drivers/power/ab8500_charger.c | 166 +++--- include/linux/mfd/abx500.h | 10 ++- include/linux/mfd/abx500/ab8500-bm.h |5 +- 3 files changed, 65 insertions(+), 116 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index d90fe9f..68a4128 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -79,6 +79,7 @@ #define AB8500_USB_LINK_STATUS 0x78 #define AB8505_USB_LINK_STATUS 0xF8 #define AB8500_STD_HOST_SUSP 0x18 +#define USB_LINK_STATUS_SHIFT 3 /* Watchdog timeout constant */ #define WD_TIMER 0x30 /* 4min */ @@ -743,8 +744,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, dev_err(di-dev, VBUS has collapsed\n); ret = -ENXIO; break; - } - if (is_ab9540(di-parent) || is_ab8505(di-parent)) { + } else { dev_dbg(di-dev, USB Type - Charging not allowed\n); di-max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05; @@ -799,30 +799,22 @@ static int ab8500_charger_read_usb_type(struct ab8500_charger *di) dev_err(di-dev, %s ab8500 read failed\n, __func__); return ret; } - if (is_ab8500(di-parent)) { + if (is_ab8500(di-parent)) ret = abx500_get_register_interruptible(di-dev, AB8500_USB, - AB8500_USB_LINE_STAT_REG, val); - } else if (is_ab9540(di-parent) || is_ab8505(di-parent)) { - ret = abx500_get_register_interruptible(di-dev, - AB8500_USB, AB8500_USB_LINK1_STAT_REG, val); - } else { - dev_err(di-dev, %s unsupported analog baseband\n, __func__); - return -ENXIO; - } + AB8500_USB_LINE_STAT_REG, val); + else + ret = abx500_get_register_interruptible(di-dev, + AB8500_USB, AB8500_USB_LINK1_STAT_REG, val); if (ret 0) { dev_err(di-dev, %s ab8500 read failed\n, __func__); return ret; } /* get the USB type */ - if (is_ab8500(di-parent)) { - val = (val AB8500_USB_LINK_STATUS) 3; - } else if (is_ab9540(di-parent) || is_ab8505(di-parent)) { - val = (val AB8505_USB_LINK_STATUS) 3; - } else { - dev_err(di-dev, %s unsupported analog baseband\n, __func__); - return -ENXIO; - } + if (is_ab8500(di-parent)) + val = (val AB8500_USB_LINK_STATUS) USB_LINK_STATUS_SHIFT; + else + val = (val AB8505_USB_LINK_STATUS) USB_LINK_STATUS_SHIFT; ret = ab8500_charger_max_usb_curr(di, (enum ab8500_charger_link_status) val); @@ -858,17 +850,12 @@ static int ab8500_charger_detect_usb_type(struct ab8500_charger *di) return ret; } - if (is_ab8500(di-parent)) { + if (is_ab8500(di-parent)) ret = abx500_get_register_interruptible(di-dev, AB8500_USB, AB8500_USB_LINE_STAT_REG, val); - } else if (is_ab9540(di-parent) || is_ab8505(di-parent)) { + else ret = abx500_get_register_interruptible(di-dev, AB8500_USB, AB8500_USB_LINK1_STAT_REG, val); - } else { - dev_err(di-dev, -%s unsupported analog baseband\n, __func__); - return -ENXIO; - } if (ret 0) { dev_err(di-dev, %s ab8500 read failed\n, __func__); return ret; @@ -882,15 +869,12 @@ static int ab8500_charger_detect_usb_type(struct ab8500_charger *di) */ /* get the USB type */ - if (is_ab8500(di-parent)) { - val = (val AB8500_USB_LINK_STATUS) 3; - } else if (is_ab9540(di-parent) || is_ab8505(di-parent)) { - val = (val AB8505_USB_LINK_STATUS) 3; - } else { - dev_err(di-dev
[PATCH 52/57] power: abx500_chargalg: Use hrtimer
From: Hakan Berg hakan.b...@stericsson.com Timers used for charging safety and maintenance must work even when CPU is power collapsed. By using hrtimers with realtime clock, system is able to trigger an alarm that wakes the CPU up and make it possible to handle the event. Allow a little slack of 5 minutes to the hrtimers to allow CPU to be waked up in a more optimal power saving way. A 5 minute delay to time out timers on hours does not impact on safety. Signed-off-by: Hakan Berg hakan.b...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Mian Yousaf KAUKAB mian.yousaf.kau...@stericsson.com --- drivers/power/abx500_chargalg.c | 94 ++- 1 files changed, 53 insertions(+), 41 deletions(-) diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 636d970..c8849af 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -1,5 +1,6 @@ /* * Copyright (C) ST-Ericsson SA 2012 + * Copyright (c) 2012 Sony Mobile Communications AB * * Charging algorithm driver for abx500 variants * @@ -8,11 +9,13 @@ * Johan Palsson johan.pals...@stericsson.com * Karl Komierowski karl.komierow...@stericsson.com * Arun R Murthy arun.mur...@stericsson.com + * Imre Sunyi imre.su...@sonymobile.com */ #include linux/init.h #include linux/module.h #include linux/device.h +#include linux/hrtimer.h #include linux/interrupt.h #include linux/delay.h #include linux/slab.h @@ -32,6 +35,12 @@ /* End-of-charge criteria counter */ #define EOC_COND_CNT 10 +/* One hour expressed in seconds */ +#define ONE_HOUR_IN_SECONDS3600 + +/* Five minutes expressed in seconds */ +#define FIVE_MINUTES_IN_SECONDS300 + #define to_abx500_chargalg_device_info(x) container_of((x), \ struct abx500_chargalg, chargalg_psy); @@ -245,8 +254,8 @@ struct abx500_chargalg { struct delayed_work chargalg_periodic_work; struct delayed_work chargalg_wd_work; struct work_struct chargalg_work; - struct timer_list safety_timer; - struct timer_list maintenance_timer; + struct hrtimer safety_timer; + struct hrtimer maintenance_timer; struct kobject chargalg_kobject; }; @@ -261,38 +270,47 @@ BLOCKING_NOTIFIER_HEAD(charger_notifier_list); /** * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer - * @data: pointer to the abx500_chargalg structure + * @timer: pointer to the hrtimer structure * * This function gets called when the safety timer for the charger * expires */ -static void abx500_chargalg_safety_timer_expired(unsigned long data) +static enum hrtimer_restart +abx500_chargalg_safety_timer_expired(struct hrtimer *timer) { - struct abx500_chargalg *di = (struct abx500_chargalg *) data; + struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg, + safety_timer); dev_err(di-dev, Safety timer expired\n); di-events.safety_timer_expired = true; /* Trigger execution of the algorithm instantly */ queue_work(di-chargalg_wq, di-chargalg_work); + + return HRTIMER_NORESTART; } /** * abx500_chargalg_maintenance_timer_expired() - Expiration of * the maintenance timer - * @i: pointer to the abx500_chargalg structure + * @timer: pointer to the timer structure * * This function gets called when the maintenence timer * expires */ -static void abx500_chargalg_maintenance_timer_expired(unsigned long data) +static enum hrtimer_restart +abx500_chargalg_maintenance_timer_expired(struct hrtimer *timer) + { - struct abx500_chargalg *di = (struct abx500_chargalg *) data; + struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg, + maintenance_timer); dev_dbg(di-dev, Maintenance timer expired\n); di-events.maintenance_timer_expired = true; /* Trigger execution of the algorithm instantly */ queue_work(di-chargalg_wq, di-chargalg_work); + + return HRTIMER_NORESTART; } /** @@ -392,19 +410,16 @@ static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di) */ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di) { - unsigned long timer_expiration = 0; + /* Charger-dependent expiration time in hours*/ + int timer_expiration = 0; switch (di-chg_info.charger_type) { case AC_CHG: - timer_expiration = - round_jiffies(jiffies + - (di-bat-main_safety_tmr_h * 3600 * HZ)); + timer_expiration = di-bat-main_safety_tmr_h; break; case USB_CHG: - timer_expiration = - round_jiffies(jiffies + - (di-bat
[PATCH 55/57] power: ab8500_charger: Add UsbLineCtrl2 reference
From: Marcus Cooper marcus.xm.coo...@stericsson.com When the state of USB Charge detection is changed then the calls use a define for another register in other bank. This change creates a new define for the correct register and removes the magic numbers that are present. Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Hakan BERG hakan.b...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com Conflicts: drivers/power/ab8500_charger.c --- drivers/power/ab8500_charger.c | 11 +-- include/linux/mfd/abx500/ab8500-bm.h |1 + 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 7f8f362..afb4fda 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -51,6 +51,7 @@ #define VBUS_DET_DBNC1 0x01 #define OTP_ENABLE_WD 0x01 #define DROP_COUNT_RESET 0x01 +#define USB_CH_DET 0x01 #define MAIN_CH_INPUT_CURR_SHIFT 4 #define VBUS_IN_CURR_LIM_SHIFT 4 @@ -2287,9 +2288,8 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) USB_CH_ENA, USB_CH_ENA); /*Enable charger detection*/ abx500_mask_and_set_register_interruptible(di-dev, - AB8500_USB, - AB8500_MCH_IPT_CURLVL_REG, - 0x01, 0x01); + AB8500_USB, AB8500_USB_LINE_CTRL2_REG, + USB_CH_DET, USB_CH_DET); di-invalid_charger_detect_state = 1; /*exit and wait for new link status interrupt.*/ return; @@ -2300,9 +2300,8 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) Invalid charger detected, state= 1\n); /*Stop charger detection*/ abx500_mask_and_set_register_interruptible(di-dev, - AB8500_USB, - AB8500_MCH_IPT_CURLVL_REG, - 0x01, 0x00); + AB8500_USB, AB8500_USB_LINE_CTRL2_REG, + USB_CH_DET, 0x00); /*Check link status*/ if (is_ab8500(di-parent)) ret = abx500_get_register_interruptible(di-dev, diff --git a/include/linux/mfd/abx500/ab8500-bm.h b/include/linux/mfd/abx500/ab8500-bm.h index 721bd6d..6b69ad5 100644 --- a/include/linux/mfd/abx500/ab8500-bm.h +++ b/include/linux/mfd/abx500/ab8500-bm.h @@ -23,6 +23,7 @@ * Bank : 0x5 */ #define AB8500_USB_LINE_STAT_REG 0x80 +#define AB8500_USB_LINE_CTRL2_REG 0x82 #define AB8500_USB_LINK1_STAT_REG 0x94 /* -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 53/57] power: ab8500_fg: Moving structure definitions to header file
From: Mathieu J. Poirier mathieu.poir...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/power/ab8500_fg.c | 196 +-- drivers/power/ab8500_fg.h | 201 + 2 files changed, 206 insertions(+), 191 deletions(-) create mode 100644 drivers/power/ab8500_fg.h diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 5b5c7ea..145c1f1 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -32,51 +32,7 @@ #include linux/time.h #include linux/completion.h #include linux/kernel.h - -#define MILLI_TO_MICRO 1000 -#define FG_LSB_IN_MA 1627 -#define QLSB_NANO_AMP_HOURS_X101129 -#define INS_CURR_TIMEOUT (3 * HZ) - -#define SEC_TO_SAMPLE(S) (S * 4) - -#define NBR_AVG_SAMPLES20 - -#define LOW_BAT_CHECK_INTERVAL (HZ / 16) /* 62.5 ms */ - -#define VALID_CAPACITY_SEC (45 * 60) /* 45 minutes */ -#define BATT_OK_MIN2360 /* mV */ -#define BATT_OK_INCREMENT 50 /* mV */ -#define BATT_OK_MAX_NR_INCREMENTS 0xE - -/* FG constants */ -#define BATT_OVV 0x01 - -#define interpolate(x, x1, y1, x2, y2) \ - ((y1) + y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1; - -#define to_ab8500_fg_device_info(x) container_of((x), \ - struct ab8500_fg, fg_psy); - -/** - * struct ab8500_fg_interrupts - ab8500 fg interupts - * @name: name of the interrupt - * @isrfunction pointer to the isr - */ -struct ab8500_fg_interrupts { - char *name; - irqreturn_t (*isr)(int irq, void *data); -}; - -enum ab8500_fg_discharge_state { - AB8500_FG_DISCHARGE_INIT, - AB8500_FG_DISCHARGE_INITMEASURING, - AB8500_FG_DISCHARGE_INIT_RECOVERY, - AB8500_FG_DISCHARGE_RECOVERY, - AB8500_FG_DISCHARGE_READOUT_INIT, - AB8500_FG_DISCHARGE_READOUT, - AB8500_FG_DISCHARGE_WAKEUP, -}; +#include ab8500_fg.h static char *discharge_state[] = { DISCHARGE_INIT, @@ -87,159 +43,17 @@ static char *discharge_state[] = { DISCHARGE_READOUT, DISCHARGE_WAKEUP, }; - -enum ab8500_fg_charge_state { - AB8500_FG_CHARGE_INIT, - AB8500_FG_CHARGE_READOUT, -}; - static char *charge_state[] = { CHARGE_INIT, CHARGE_READOUT, }; -enum ab8500_fg_calibration_state { - AB8500_FG_CALIB_INIT, - AB8500_FG_CALIB_WAIT, - AB8500_FG_CALIB_END, -}; - -struct ab8500_fg_avg_cap { - int avg; - int samples[NBR_AVG_SAMPLES]; - __kernel_time_t time_stamps[NBR_AVG_SAMPLES]; - int pos; - int nbr_samples; - int sum; -}; - -struct ab8500_fg_cap_scaling { - bool enable; - int cap_to_scale[2]; - int disable_cap_level; - int scaled_cap; -}; - -struct ab8500_fg_battery_capacity { - int max_mah_design; - int max_mah; - int mah; - int permille; - int level; - int prev_mah; - int prev_percent; - int prev_level; - int user_mah; - struct ab8500_fg_cap_scaling cap_scale; -}; - -struct ab8500_fg_flags { - bool fg_enabled; - bool conv_done; - bool charging; - bool fully_charged; - bool force_full; - bool low_bat_delay; - bool low_bat; - bool bat_ovv; - bool batt_unknown; - bool calibrate; - bool user_cap; - bool batt_id_received; -}; +#define interpolate(x, x1, y1, x2, y2) \ + ((y1) + y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1; -struct inst_curr_result_list { - struct list_head list; - int *result; -}; +#define to_ab8500_fg_device_info(x) container_of((x), \ + struct ab8500_fg, fg_psy); -/** - * struct ab8500_fg - ab8500 FG device information - * @dev: Pointer to the structure device - * @node: a list of AB8500 FGs, hence prepared for reentrance - * @irqholds the CCEOC interrupt number - * @vbat: Battery voltage in mV - * @vbat_nom: Nominal battery voltage in mV - * @inst_curr: Instantenous battery current in mA - * @avg_curr: Average battery current in mA - * @bat_temp battery temperature - * @fg_samples:Number of samples used in the FG accumulation - * @accu_charge: Accumulated charge from the last conversion - * @recovery_cnt: Counter for recovery mode - * @high_curr_cnt: Counter for high current mode - * @init_cnt: Counter for init mode - * @low_bat_cntCounter for number of consecutive low battery measures - * @nbr_cceoc_irq_cnt Counter for number of CCEOC irqs received since enabled - * @recovery_needed: Indicate if recovery is needed - * @high_curr_mode:Indicate if we're in high current mode - * @init_capacity: Indicate if initial capacity measuring should
[PATCH 50/57] power: ab8500-chargalg: update battery health on safety timer exp
From: Hakan Berg hakan.b...@stericsson.com When the charging safety timer is elapsed the battery health is shown as Good. This is misleading and also hard to distingiush problems reported on phone discharges although charger is attached. When safety timer elapses that is an indication of a fault in the battery of some kind. Hence report as POWER_SUPPLY_HEALTH_UNSPEC_FAILURE. Signed-off-by: Hakan Berg hakan.b...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Arun MURTHY arun.mur...@stericsson.com Reviewed-by: Karl KOMIEROWSKI karl.komierow...@stericsson.com --- drivers/power/abx500_chargalg.c |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 4db0ef0..1df238f 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -1711,6 +1711,10 @@ static int abx500_chargalg_get_property(struct power_supply *psy, val-intval = POWER_SUPPLY_HEALTH_COLD; else val-intval = POWER_SUPPLY_HEALTH_OVERHEAT; + } else if (di-charge_state == STATE_SAFETY_TIMER_EXPIRED || + di-charge_state == + STATE_SAFETY_TIMER_EXPIRED_INIT) { + val-intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; } else { val-intval = POWER_SUPPLY_HEALTH_GOOD; } -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 49/57] power: Cancelling status charging notification.
From: Mathieu J. Poirier mathieu.poir...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/power/abx500_chargalg.c |2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index ce58f20..4db0ef0 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -641,10 +641,8 @@ static void abx500_chargalg_hold_charging(struct abx500_chargalg *di) abx500_chargalg_usb_en(di, false, 0, 0); abx500_chargalg_stop_safety_timer(di); abx500_chargalg_stop_maintenance_timer(di); - di-charge_status = POWER_SUPPLY_STATUS_CHARGING; di-maintenance_chg = false; cancel_delayed_work(di-chargalg_wd_work); - power_supply_changed(di-chargalg_psy); } /** -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 48/57] power: ab8500 : quick re-attach for ext charger
From: Rupesh Kumar rupesh.ku...@stericsson.com Quick re-attach charging behaviour is not required for external ac charger. Internal AC/USB Charger removal detection problem is due to a bug in AB8500 ASICs. Signed-off-by: Rupesh Kumar rupesh.ku...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Hakan BERG hakan.b...@stericsson.com Reviewed-by: Philippe LANGLAIS philippe.langl...@stericsson.com --- drivers/power/abx500_chargalg.c |5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 180deab..ce58f20 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -330,12 +330,13 @@ static int abx500_chargalg_check_charger_enable(struct abx500_chargalg *di) return di-usb_chg-ops.check_enable(di-usb_chg, di-bat-bat_type[di-bat-batt_id].normal_vol_lvl, di-bat-bat_type[di-bat-batt_id].normal_cur_lvl); - } else if (di-chg_info.charger_type AC_CHG) { + } else if ((di-chg_info.charger_type AC_CHG) + !(di-ac_chg-external)) { return di-ac_chg-ops.check_enable(di-ac_chg, di-bat-bat_type[di-bat-batt_id].normal_vol_lvl, di-bat-bat_type[di-bat-batt_id].normal_cur_lvl); } - return -ENXIO; + return 0; } /** -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 47/57] power: Harmonising platform data declaration/handling
From: Mathieu J. Poirier mathieu.poir...@linaro.org Making platform data declaration and handling similar accross all ab8500_xyc.c battery management files. Also adding gards against NULL platform data. Signed-off-by: Philippe Langlais philippe.langl...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/power/ab8500_btemp.c| 17 + drivers/power/ab8500_charger.c | 18 +- drivers/power/ab8500_fg.c | 17 + drivers/power/abx500_chargalg.c | 25 - 4 files changed, 47 insertions(+), 30 deletions(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index 1f33122..cf4b653 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -1028,10 +1028,10 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) { int irq, i, ret = 0; u8 val; - struct ab8500_platform_data *plat_data; - struct ab8500_btemp *di; + struct ab8500_platform_data *plat; - di = kzalloc(sizeof(*di), GFP_KERNEL); + struct ab8500_btemp *di = + kzalloc(sizeof(struct ab8500_btemp), GFP_KERNEL); if (!di) return -ENOMEM; @@ -1042,22 +1042,23 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) di-initialized = false; + plat = dev_get_platdata(di-parent-dev); + /* get btemp specific platform data */ - plat_data = dev_get_platdata(di-parent-dev); - di-pdata = plat_data-btemp; - if (!di-pdata) { + if (!plat || !plat-btemp) { dev_err(di-dev, no btemp platform data supplied\n); ret = -EINVAL; goto free_device_info; } + di-pdata = plat-btemp; /* get battery specific platform data */ - di-bat = plat_data-battery; - if (!di-bat) { + if (!plat-battery) { dev_err(di-dev, no battery platform data supplied\n); ret = -EINVAL; goto free_device_info; } + di-bat = plat-battery; /* BTEMP supply */ di-btemp_psy.name = ab8500_btemp; diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 68a4128..1290470 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -3319,10 +3319,10 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev) static int __devinit ab8500_charger_probe(struct platform_device *pdev) { int irq, i, charger_status, ret = 0, ch_stat; - struct ab8500_platform_data *plat_data; - struct ab8500_charger *di; + struct ab8500_platform_data *plat; - di = kzalloc(sizeof(*di), GFP_KERNEL); + struct ab8500_charger *di = + kzalloc(sizeof(struct ab8500_charger), GFP_KERNEL); if (!di) return -ENOMEM; @@ -3335,24 +3335,24 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) spin_lock_init(di-usb_state.usb_lock); mutex_init(di-usb_ipt_crnt_lock); - /* get charger specific platform data */ - plat_data = dev_get_platdata(di-parent-dev); + plat = dev_get_platdata(di-parent-dev); - di-pdata = plat_data-charger; - if (!di-pdata) { + /* get charger specific platform data */ + if (!plat || !plat-charger) { dev_err(di-dev, no charger platform data supplied\n); ret = -EINVAL; goto free_device_info; } + di-pdata = plat-charger; /* get battery specific platform data */ - di-bat = plat_data-battery; - if (!di-bat) { + if (!plat-battery) { dev_err(di-dev, no battery platform data supplied\n); ret = -EINVAL; goto free_device_info; } + di-bat = plat-battery; di-autopower = false; di-invalid_charger_detect_state = 0; diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index cf6d2b5..5b5c7ea 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -3158,10 +3158,10 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) { int i, irq; int ret = 0; - struct ab8500_platform_data *plat_data; - struct ab8500_fg *di; + struct ab8500_platform_data *plat; - di = kzalloc(sizeof(*di), GFP_KERNEL); + struct ab8500_fg *di = + kzalloc(sizeof(struct ab8500_fg), GFP_KERNEL); if (!di) return -ENOMEM; @@ -3172,22 +3172,23 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) di-parent = dev_get_drvdata(pdev-dev.parent); di-gpadc = ab8500_gpadc_get(ab8500-gpadc.0); + plat = dev_get_platdata(di-parent-dev); + /* get fg specific platform data */ - plat_data = dev_get_platdata(di-parent-dev); - di
[PATCH 36/57] power: add backup battery charge voltages.
From: Yang QU yang...@stericsson.com Add 2.7v, 2.9v, 3.0v, 3.2v and 3.3v charging voltage for backup battery. Before that only 2.5v, 2.6v, 2.8v, 3.1v are available. Signed-off-by: Yang QU yang...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Maxime COQUELIN maxime.coque...@stericsson.com Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Xiao Mei ZHANG xiaomei.zh...@stericsson.com --- drivers/power/ab8500_charger.c |9 +++-- include/linux/mfd/abx500/ab8500-bm.h | 24 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index b3b8f77..8137ea5 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2834,6 +2834,7 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy, static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) { int ret = 0; + u8 bup_vch_range = 0, vbup33_vrtcn = 0; /* Setup maximum charger current and voltage for ABB cut2.0 */ if (!is_ab8500_1p1_or_earlier(di-parent)) { @@ -2935,11 +2936,15 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) } /* Backup battery voltage and current */ + if (di-bat-bkup_bat_v BUP_VCH_SEL_3P1V) + bup_vch_range = BUP_VCH_RANGE; + if (di-bat-bkup_bat_v == BUP_VCH_SEL_3P3V) + vbup33_vrtcn = VBUP33_VRTCN; + ret = abx500_set_register_interruptible(di-dev, AB8500_RTC, AB8500_RTC_BACKUP_CHG_REG, - di-bat-bkup_bat_v | - di-bat-bkup_bat_i); + (di-bat-bkup_bat_v 0x3) | di-bat-bkup_bat_i); if (ret) { dev_err(di-dev, failed to setup backup battery charging\n); goto out; diff --git a/include/linux/mfd/abx500/ab8500-bm.h b/include/linux/mfd/abx500/ab8500-bm.h index cd15ea3..5ae8a6f 100644 --- a/include/linux/mfd/abx500/ab8500-bm.h +++ b/include/linux/mfd/abx500/ab8500-bm.h @@ -105,6 +105,7 @@ #define AB8500_RTC_BACKUP_CHG_REG 0x0C #define AB8500_RTC_CC_CONF_REG 0x01 #define AB8500_RTC_CTRL_REG0x0B +#define AB8500_RTC_CTRL1_REG 0x11 /* * OTP register offsets @@ -179,10 +180,25 @@ #define BUP_ICH_SEL_300UA 0x08 #define BUP_ICH_SEL_700UA 0x0C -#define BUP_VCH_SEL_2P5V 0x00 -#define BUP_VCH_SEL_2P6V 0x01 -#define BUP_VCH_SEL_2P8V 0x02 -#define BUP_VCH_SEL_3P1V 0x03 +enum bup_vch_sel { + BUP_VCH_SEL_2P5V, + BUP_VCH_SEL_2P6V, + BUP_VCH_SEL_2P8V, + BUP_VCH_SEL_3P1V, + /* +* Note that the following 5 values 2.7v, 2.9v, 3.0v, 3.2v, 3.3v +* are only available on ab8540. You can't choose these 5 +* voltage on ab8500/ab8505/ab9540. +*/ + BUP_VCH_SEL_2P7V, + BUP_VCH_SEL_2P9V, + BUP_VCH_SEL_3P0V, + BUP_VCH_SEL_3P2V, + BUP_VCH_SEL_3P3V, +}; + +#define BUP_VCH_RANGE 0x02 +#define VBUP33_VRTCN 0x01 /* Battery OVV constants */ #define BATT_OVV_ENA 0x02 -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 45/57] power: ab8500: defer btemp filtering while init
From: Rupesh Kumar rupesh.ku...@stericsson.com Due to btemp filtering enabled during init, temp values reported to charge algorithm driver started from 0. As a result,charge algorithm was going into wrong state and charging was stopped. This patch defers btemp filtering till init is done. Signed-off-by: Rupesh Kumar rupesh.ku...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Martin SJOBLOM martin.w.sjob...@stericsson.com Reviewed-by: Philippe LANGLAIS philippe.langl...@stericsson.com --- drivers/power/ab8500_btemp.c |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index b24835f..1f33122 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -613,7 +613,6 @@ static void ab8500_btemp_periodic_work(struct work_struct *work) struct ab8500_btemp, btemp_periodic_work.work); if (!di-initialized) { - di-initialized = true; /* Identify the battery */ if (ab8500_btemp_id(di) 0) dev_warn(di-dev, failed to identify the battery\n); @@ -626,8 +625,9 @@ static void ab8500_btemp_periodic_work(struct work_struct *work) * same temperature. Else only allow 1 degree change from previous * reported value in the direction of the new measurement. */ - if (bat_temp == di-prev_bat_temp || !di-initialized) { - if (di-bat_temp != di-prev_bat_temp || !di-initialized) { + if ((bat_temp == di-prev_bat_temp) || !di-initialized) { + if ((di-bat_temp != di-prev_bat_temp) || !di-initialized) { + di-initialized = true; di-bat_temp = bat_temp; power_supply_changed(di-btemp_psy); } -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 27/57] power: sysfs interface update
From: Michel JAOUEN michel.jao...@stericsson.com Add new sysfs interface to get current charge status Signed-off-by: Michel JAOUEN michel.jao...@stericsson.com Signed-off-by: Loic Pallardy loic.palla...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Olivier CLERGEAUD olivier.clerge...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_charger.c |3 +++ drivers/power/abx500_chargalg.c | 24 +++- 2 files changed, 26 insertions(+), 1 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 4129599..0a781a0 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2759,6 +2759,9 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, enum ab8500_usb_state bm_usb_state; unsigned mA = *((unsigned *)power); + if (di == NULL) + return NOTIFY_DONE; + if (event != USB_EVENT_VBUS) { dev_dbg(di-dev, not a standard host, returning\n); return NOTIFY_DONE; diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index d3efc2a..4e3d20f 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -1679,6 +1679,27 @@ static int abx500_chargalg_get_property(struct power_supply *psy, return 0; } +/** + * abx500_chargalg_sysfs_show() - sysfs show operations + * @kobj: pointer to the struct kobject + * @attr: pointer to the struct attribute + * @buf: buffer that holds the parameter to send to userspace + * + * Returns a buffer to be displayed in user space + */ +static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct abx500_chargalg *di = container_of(kobj, + struct abx500_chargalg, chargalg_kobject); + + if ((di-susp_status.ac_suspended == true) + (di-susp_status.usb_suspended == true)) + return sprintf(buf, 0\n); + else + return sprintf(buf, 1\n); +} + /* Exposure to the sysfs interface */ /** @@ -1749,7 +1770,7 @@ static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj, static struct attribute abx500_chargalg_en_charger = \ { .name = chargalg, - .mode = S_IWUGO, + .mode = S_IRUGO | S_IWUSR, }; static struct attribute *abx500_chargalg_chg[] = { @@ -1758,6 +1779,7 @@ static struct attribute *abx500_chargalg_chg[] = { }; static const struct sysfs_ops abx500_chargalg_sysfs_ops = { + .show = abx500_chargalg_sysfs_show, .store = abx500_chargalg_sysfs_charger, }; -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 29/57] power: ab8500_fg: Goto INIT_RECOVERY when charger removed
From: Martin Bergström martin.bergst...@stericsson.com When the charger is removed we need to go to INIT_RECOVERY state instead of directly to RECOVERY state. Signed-off-by: Martin Bergstrom martin.bergst...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_fg.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 861927d..e7a0e1f 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -1644,7 +1644,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) if (di-recovery_needed) { ab8500_fg_discharge_state_to(di, - AB8500_FG_DISCHARGE_RECOVERY); + AB8500_FG_DISCHARGE_INIT_RECOVERY); queue_delayed_work(di-fg_wq, di-fg_periodic_work, 0); -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 37/57] power: ab8500_bm: Quick re-attach charging behaviour
From: Kalle Komierowski karl.komierow...@stericsson.com Due to a bug in some AB8500 ASICs charger removal cannot always be detected if the removal and reinsertion is done to close in time. This patch detects above described case and handles the situation so that charging will be kept turned on. Signed-off-by: Kalle Komierowski karl.komierow...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com Reviewed-by: Philippe LANGLAIS philippe.langl...@stericsson.com --- drivers/power/ab8500_charger.c| 105 - drivers/power/abx500_chargalg.c | 31 - include/linux/mfd/abx500/ux500_chargalg.h |1 + 3 files changed, 134 insertions(+), 3 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 8137ea5..70e7c5e 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -49,6 +49,7 @@ #define VBUS_DET_DBNC100 0x02 #define VBUS_DET_DBNC1 0x01 #define OTP_ENABLE_WD 0x01 +#define DROP_COUNT_RESET 0x01 #define MAIN_CH_INPUT_CURR_SHIFT 4 #define VBUS_IN_CURR_LIM_SHIFT 4 @@ -1672,6 +1673,105 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, } /** + * ab8500_charger_usb_check_enable() - enable usb charging + * @charger: pointer to the ux500_charger structure + * @vset: charging voltage + * @iset: charger output current + * + * Check if the VBUS charger has been disconnected and reconnected without + * AB8500 rising an interrupt. Returns 0 on success. + */ +static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, + int vset, int iset) +{ + u8 usbch_ctrl1 = 0; + int ret = 0; + + struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger); + + if (!di-usb.charger_connected) + return ret; + + ret = abx500_get_register_interruptible(di-dev, AB8500_CHARGER, + AB8500_USBCH_CTRL1_REG, usbch_ctrl1); + if (ret 0) { + dev_err(di-dev, ab8500 read failed %d\n, __LINE__); + return ret; + } + dev_dbg(di-dev, USB charger ctrl: 0x%02x\n, usbch_ctrl1); + + if (!(usbch_ctrl1 USB_CH_ENA)) { + dev_info(di-dev, Charging has been disabled abnormally and will be re-enabled\n); + + ret = abx500_mask_and_set_register_interruptible(di-dev, + AB8500_CHARGER, AB8500_CHARGER_CTRL, + DROP_COUNT_RESET, DROP_COUNT_RESET); + if (ret 0) { + dev_err(di-dev, ab8500 write failed %d\n, __LINE__); + return ret; + } + + ret = ab8500_charger_usb_en(di-usb_chg, true, vset, iset); + if (ret 0) { + dev_err(di-dev, Failed to enable VBUS charger %d\n, + __LINE__); + return ret; + } + } + return ret; +} + +/** + * ab8500_charger_ac_check_enable() - enable usb charging + * @charger: pointer to the ux500_charger structure + * @vset: charging voltage + * @iset: charger output current + * + * Check if the AC charger has been disconnected and reconnected without + * AB8500 rising an interrupt. Returns 0 on success. + */ +static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, + int vset, int iset) +{ + u8 mainch_ctrl1 = 0; + int ret = 0; + + struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger); + + if (!di-ac.charger_connected) + return ret; + + ret = abx500_get_register_interruptible(di-dev, AB8500_CHARGER, + AB8500_MCH_CTRL1, mainch_ctrl1); + if (ret 0) { + dev_err(di-dev, ab8500 read failed %d\n, __LINE__); + return ret; + } + dev_dbg(di-dev, AC charger ctrl: 0x%02x\n, mainch_ctrl1); + + if (!(mainch_ctrl1 MAIN_CH_ENA)) { + dev_info(di-dev, Charging has been disabled abnormally and will be re-enabled\n); + + ret = abx500_mask_and_set_register_interruptible(di-dev, + AB8500_CHARGER, AB8500_CHARGER_CTRL, + DROP_COUNT_RESET, DROP_COUNT_RESET); + + if (ret 0) { + dev_err(di-dev, ab8500 write failed %d\n, __LINE__); + return ret; + } + + ret = ab8500_charger_ac_en(di-usb_chg, true, vset, iset); + if (ret 0) { + dev_err(di-dev, failed to enable AC charger %d\n, + __LINE__); + return ret
[PATCH 43/57] power: charging: Add AB8505_USB_LINK_STATUS
From: Hakan Berg hakan.b...@stericsson.com The ab8505 does not have the same address for USB link-status as has ab8500. Add AB8505_USB_LINK_STATUS and code to switch to correct constant. Signed-off-by: Hakan Berg hakan.b...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Mian Yousaf KAUKAB mian.yousaf.kau...@stericsson.com Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Rabin VINCENT rabin.vinc...@stericsson.com --- drivers/power/ab8500_charger.c | 46 --- 1 files changed, 37 insertions(+), 9 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 18931e4..9449a33 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -77,6 +77,7 @@ /* UsbLineStatus register bit masks */ #define AB8500_USB_LINK_STATUS 0x78 +#define AB8505_USB_LINK_STATUS 0xF8 #define AB8500_STD_HOST_SUSP 0x18 /* Watchdog timeout constant */ @@ -801,10 +802,12 @@ static int ab8500_charger_read_usb_type(struct ab8500_charger *di) if (is_ab8500(di-parent)) { ret = abx500_get_register_interruptible(di-dev, AB8500_USB, AB8500_USB_LINE_STAT_REG, val); - } else { - if (is_ab9540(di-parent) || is_ab8505(di-parent)) + } else if (is_ab9540(di-parent) || is_ab8505(di-parent)) { ret = abx500_get_register_interruptible(di-dev, AB8500_USB, AB8500_USB_LINK1_STAT_REG, val); + } else { + dev_err(di-dev, %s unsupported analog baseband\n, __func__); + return -ENXIO; } if (ret 0) { dev_err(di-dev, %s ab8500 read failed\n, __func__); @@ -812,7 +815,14 @@ static int ab8500_charger_read_usb_type(struct ab8500_charger *di) } /* get the USB type */ - val = (val AB8500_USB_LINK_STATUS) 3; + if (is_ab8500(di-parent)) { + val = (val AB8500_USB_LINK_STATUS) 3; + } else if (is_ab9540(di-parent) || is_ab8505(di-parent)) { + val = (val AB8505_USB_LINK_STATUS) 3; + } else { + dev_err(di-dev, %s unsupported analog baseband\n, __func__); + return -ENXIO; + } ret = ab8500_charger_max_usb_curr(di, (enum ab8500_charger_link_status) val); @@ -848,12 +858,17 @@ static int ab8500_charger_detect_usb_type(struct ab8500_charger *di) return ret; } - if (is_ab8500(di-parent)) + if (is_ab8500(di-parent)) { ret = abx500_get_register_interruptible(di-dev, AB8500_USB, AB8500_USB_LINE_STAT_REG, val); - else + } else if (is_ab9540(di-parent) || is_ab8505(di-parent)) { ret = abx500_get_register_interruptible(di-dev, AB8500_USB, AB8500_USB_LINK1_STAT_REG, val); + } else { + dev_err(di-dev, +%s unsupported analog baseband\n, __func__); + return -ENXIO; + } if (ret 0) { dev_err(di-dev, %s ab8500 read failed\n, __func__); return ret; @@ -867,7 +882,15 @@ static int ab8500_charger_detect_usb_type(struct ab8500_charger *di) */ /* get the USB type */ - val = (val AB8500_USB_LINK_STATUS) 3; + if (is_ab8500(di-parent)) { + val = (val AB8500_USB_LINK_STATUS) 3; + } else if (is_ab9540(di-parent) || is_ab8505(di-parent)) { + val = (val AB8505_USB_LINK_STATUS) 3; + } else { + dev_err(di-dev, +%s unsupported analog baseband\n, __func__); + return -ENXIO; + } if (val) break; } @@ -2277,6 +2300,7 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) int detected_chargers; int ret; u8 val; + u8 link_status; struct ab8500_charger *di = container_of(work, struct ab8500_charger, usb_link_status_work); @@ -2303,9 +2327,13 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) else dev_dbg(di-dev, Error reading USB link status\n); + if (is_ab9540(di-parent) || is_ab8505(di-parent)) + link_status = AB8505_USB_LINK_STATUS; + else + link_status = AB8500_USB_LINK_STATUS; + if (detected_chargers USB_PW_CONN) { - if (((val AB8500_USB_LINK_STATUS) 3) == - USB_STAT_NOT_VALID_LINK
[PATCH 42/57] power: charging: Allow capacity to raise from 1%
From: Hakan Berg hakan.b...@stericsson.com When battery capacity was going below 1% fg in not supposed to report 0% unless we've got the LOW_BAT IRQ, no matter what the FG-algorithm says. This made fg get stuck at 1% if charger is connected when capacity is 1%. That problem is addressed with this patch. Signed-off-by: Hakan BERG hakan.b...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Srinidhi KASAGAR srinidhi.kasa...@stericsson.com --- drivers/power/ab8500_fg.c |6 ++ 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index c5732e7..cf6d2b5 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -1357,9 +1357,6 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) * algorithm says. */ di-bat_cap.prev_percent = 1; - di-bat_cap.permille = 1; - di-bat_cap.prev_mah = 1; - di-bat_cap.mah = 1; percent = 1; changed = true; @@ -1771,9 +1768,10 @@ static void ab8500_fg_algorithm(struct ab8500_fg *di) ab8500_fg_algorithm_discharging(di); } - dev_dbg(di-dev, [FG_DATA] %d %d %d %d %d %d %d %d %d + dev_dbg(di-dev, [FG_DATA] %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n, di-bat_cap.max_mah_design, + di-bat_cap.max_mah, di-bat_cap.mah, di-bat_cap.permille, di-bat_cap.level, -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 41/57] power: ab8500_btemp: Filter btemp readings
From: Hakan Berg hakan.b...@stericsson.com Battery tempreature readings sometimes fails and results in a value far from recent values. This patch adds a software filter that disposes such readings, by allowing direct updates on temperature only if two samples result in the same temperature. Else only allow 1 degree change from previous reported value in the direction of the new measurement. Signed-off-by: Hakan Berg hakan.b...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Martin SJOBLOM martin.w.sjob...@stericsson.com Reviewed-by: Rabin VINCENT rabin.vinc...@stericsson.com --- drivers/power/ab8500_btemp.c | 27 +-- 1 files changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index 56a3bb9..b24835f 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -74,8 +74,8 @@ struct ab8500_btemp_ranges { * @dev: Pointer to the structure device * @node: List of AB8500 BTEMPs, hence prepared for reentrance * @curr_source: What current source we use, in uA - * @bat_temp: Battery temperature in degree Celcius - * @prev_bat_temp Last dispatched battery temperature + * @bat_temp: Dispatched battery temperature in degree Celcius + * @prev_bat_temp Last measured battery temperature in degree Celcius * @parent:Pointer to the struct ab8500 * @gpadc: Pointer to the struct gpadc * @fg:Pointer to the struct fg @@ -608,6 +608,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) static void ab8500_btemp_periodic_work(struct work_struct *work) { int interval; + int bat_temp; struct ab8500_btemp *di = container_of(work, struct ab8500_btemp, btemp_periodic_work.work); @@ -618,12 +619,26 @@ static void ab8500_btemp_periodic_work(struct work_struct *work) dev_warn(di-dev, failed to identify the battery\n); } - di-bat_temp = ab8500_btemp_measure_temp(di); - - if (di-bat_temp != di-prev_bat_temp) { - di-prev_bat_temp = di-bat_temp; + bat_temp = ab8500_btemp_measure_temp(di); + /* +* Filter battery temperature. +* Allow direct updates on temperature only if two samples result in +* same temperature. Else only allow 1 degree change from previous +* reported value in the direction of the new measurement. +*/ + if (bat_temp == di-prev_bat_temp || !di-initialized) { + if (di-bat_temp != di-prev_bat_temp || !di-initialized) { + di-bat_temp = bat_temp; + power_supply_changed(di-btemp_psy); + } + } else if (bat_temp di-prev_bat_temp) { + di-bat_temp--; + power_supply_changed(di-btemp_psy); + } else if (bat_temp di-prev_bat_temp) { + di-bat_temp++; power_supply_changed(di-btemp_psy); } + di-prev_bat_temp = bat_temp; if (di-events.ac_conn || di-events.usb_conn) interval = di-bat-temp_interval_chg; -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 40/57] power: ab8500: ADC for battery thermistor
From: Marcus Cooper marcus.xm.coo...@stericsson.com When using ABx500_ADC_THERM_BATCTRL the battery ID resistor is combined with a NTC resistor to both identify the battery and to measure its temperature. Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Mian Yousaf KAUKAB mian.yousaf.kau...@stericsson.com Reviewed-by: Michel JAOUEN michel.jao...@stericsson.com Reviewed-by: Hakan BERG hakan.b...@stericsson.com Reviewed-by: Rabin VINCENT rabin.vinc...@stericsson.com --- drivers/power/ab8500_btemp.c |4 +++- include/linux/mfd/abx500.h |2 ++ 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index 506f124..56a3bb9 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -557,7 +557,9 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) /* BATTERY_UNKNOWN is defined on position 0, skip it! */ for (i = BATTERY_UNKNOWN + 1; i di-bat-n_btypes; i++) { if ((res = di-bat-bat_type[i].resis_high) - (res = di-bat-bat_type[i].resis_low)) { + (res = di-bat-bat_type[i].resis_low) + (di-bat-bat_type[i].adc_therm == + di-bat-adc_therm)) { dev_dbg(di-dev, Battery detected on %s low %d res %d high: %d index: %d\n, diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h index 97e918f..cb2b82a 100644 --- a/include/linux/mfd/abx500.h +++ b/include/linux/mfd/abx500.h @@ -270,6 +270,7 @@ struct abx500_maxim_parameters { * @low_high_cur_lvl: charger current in temp low/high state in mA * @low_high_vol_lvl: charger voltage in temp low/high state in mV' * @battery_resistance:battery inner resistance in mOhm. + * @adc_therm: battery uses controller or resistor for temp. * @n_r_t_tbl_elements:number of elements in r_to_t_tbl * @r_to_t_tbl:table containing resistance to temp points * @n_v_cap_tbl_elements: number of elements in v_to_cap_tbl @@ -297,6 +298,7 @@ struct abx500_battery_type { int low_high_cur_lvl; int low_high_vol_lvl; int battery_resistance; + enum abx500_adc_therm adc_therm; int n_temp_tbl_elements; struct abx500_res_to_temp *r_to_t_tbl; int n_v_cap_tbl_elements; -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 39/57] power: ab8500_charger: Prevent auto drop of VBUS
From: Martin Sjoblom martin.w.sjob...@stericsson.com Do not set higher current in stepping functionality if VBUS is dropping. After VBUS has dropped try to set current once again. If dropping again then we have found the maximum capability of the charger. Signed-off-by: Martin Sjoblom martin.w.sjob...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Per FORLIN per.for...@stericsson.com --- drivers/power/ab8500_charger.c | 166 1 files changed, 117 insertions(+), 49 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index ebeb068..18931e4 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -55,6 +55,7 @@ #define MAIN_CH_INPUT_CURR_SHIFT 4 #define VBUS_IN_CURR_LIM_SHIFT 4 #define AUTO_VBUS_IN_CURR_LIM_SHIFT4 +#define VBUS_IN_CURR_LIM_RETRY_SET_TIME30 /* seconds */ #define LED_INDICATOR_PWM_ENA 0x01 #define LED_INDICATOR_PWM_DIS 0x00 @@ -199,10 +200,15 @@ struct ab8500_charger_usb_state { spinlock_t usb_lock; }; +struct ab8500_charger_max_usb_in_curr { + int usb_type_max; + int set_max; + int calculated_max; +}; + /** * struct ab8500_charger - ab8500 Charger device information * @dev: Pointer to the structure device - * @max_usb_in_curr: Max USB charger input current * @vbus_detected: VBUS detected * @vbus_detected_start: * VBUS detected during startup @@ -227,6 +233,7 @@ struct ab8500_charger_usb_state { * @bat: Pointer to the abx500_bm platform data * @flags: Structure for information about events triggered * @usb_state: Structure for usb stack information + * @max_usb_in_curr: Max USB charger input current * @ac_chg:AC charger power supply * @usb_chg: USB charger power supply * @ac:Structure that holds the AC charger properties @@ -255,7 +262,6 @@ struct ab8500_charger_usb_state { */ struct ab8500_charger { struct device *dev; - int max_usb_in_curr; bool vbus_detected; bool vbus_detected_start; bool ac_conn; @@ -266,7 +272,6 @@ struct ab8500_charger { bool usb_device_is_unrecognised; bool autopower; int invalid_charger_detect_state; - bool is_usb_host; int is_aca_rid; atomic_t current_stepping_sessions; struct ab8500 *parent; @@ -275,6 +280,7 @@ struct ab8500_charger { struct abx500_bm_data *bat; struct ab8500_charger_event_flags flags; struct ab8500_charger_usb_state usb_state; + struct ab8500_charger_max_usb_in_curr max_usb_in_curr; struct ux500_charger ac_chg; struct ux500_charger usb_chg; struct ab8500_charger_info ac; @@ -416,6 +422,10 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di, if (connected != di-usb.charger_connected) { dev_dbg(di-dev, USB connected:%i\n, connected); di-usb.charger_connected = connected; + + if (!connected) + di-flags.vbus_drop_end = false; + sysfs_notify(di-usb_chg.psy.dev-kobj, NULL, present); if (connected) { @@ -665,23 +675,19 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, case USB_STAT_STD_HOST_C_S: dev_dbg(di-dev, USB Type - Standard host is ); dev_dbg(di-dev, detected through USB driver\n); - di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; - di-is_usb_host = true; + di-max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; di-is_aca_rid = 0; break; case USB_STAT_HOST_CHG_HS_CHIRP: - di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; - di-is_usb_host = true; + di-max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; di-is_aca_rid = 0; break; case USB_STAT_HOST_CHG_HS: - di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; - di-is_usb_host = true; + di-max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; di-is_aca_rid = 0; break; case USB_STAT_ACA_RID_C_HS: - di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P9; - di-is_usb_host = false; + di-max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P9; di-is_aca_rid = 0; break; case USB_STAT_ACA_RID_A: @@ -690,8 +696,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, * can consume (900mA). Closest level is 500mA */ dev_dbg(di-dev, USB_STAT_ACA_RID_A detected\n); - di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; - di-is_usb_host
[PATCH 38/57] power: l9540: Charge only mode fixes
From: Rupesh Kumar rupesh.ku...@stericsson.com Fix for: charging not getting enabled in charge only mode by external charger. Signed-off-by: Rupesh Kumar rupesh.ku...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Michel JAOUEN michel.jao...@stericsson.com Reviewed-by: Philippe LANGLAIS philippe.langl...@stericsson.com Reviewed-by: Philippe LANGLAIS philippe.langl...@stericsson.com --- drivers/power/ab8500_charger.c| 42 + drivers/power/abx500_chargalg.c | 14 + include/linux/mfd/abx500/ux500_chargalg.h |2 + 3 files changed, 58 insertions(+), 0 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 70e7c5e..ebeb068 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -15,6 +15,7 @@ #include linux/device.h #include linux/interrupt.h #include linux/delay.h +#include linux/notifier.h #include linux/slab.h #include linux/platform_device.h #include linux/power_supply.h @@ -94,6 +95,10 @@ #define AB8500_SW_CONTROL_FALLBACK 0x03 /* Wait for enumeration before charging in us */ #define WAIT_ACA_RID_ENUMERATION (5 * 1000) +/*External charger control*/ +#define AB8500_SYS_CHARGER_CONTROL_REG 0x52 +#define EXTERNAL_CHARGER_DISABLE_REG_VAL 0x03 +#define EXTERNAL_CHARGER_ENABLE_REG_VAL0x07 /* UsbLineStatus register - usb types */ enum ab8500_charger_link_status { @@ -1672,6 +1677,29 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, return ret; } +static int ab8500_external_charger_prepare(struct notifier_block *charger_nb, + unsigned long event, void *data) +{ + int ret; + struct device *dev = data; + /*Toggle External charger control pin*/ + ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK, + AB8500_SYS_CHARGER_CONTROL_REG, + EXTERNAL_CHARGER_DISABLE_REG_VAL); + if (ret 0) { + dev_err(dev, write reg failed %d\n, ret); + goto out; + } + ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK, + AB8500_SYS_CHARGER_CONTROL_REG, + EXTERNAL_CHARGER_ENABLE_REG_VAL); + if (ret 0) + dev_err(dev, Write reg failed %d\n, ret); + +out: + return ret; +} + /** * ab8500_charger_usb_check_enable() - enable usb charging * @charger: pointer to the ux500_charger structure @@ -3201,6 +3229,10 @@ static int ab8500_charger_suspend(struct platform_device *pdev, #define ab8500_charger_resume NULL #endif +static struct notifier_block charger_nb = { + .notifier_call = ab8500_external_charger_prepare, +}; + static int __devexit ab8500_charger_remove(struct platform_device *pdev) { struct ab8500_charger *di = platform_get_drvdata(pdev); @@ -3233,6 +3265,11 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev) /* Delete the work queue */ destroy_workqueue(di-charger_wq); + /*Unregister external charger enable notifier*/ + if (!di-ac_chg.enabled) + blocking_notifier_chain_unregister( + charger_notifier_list, charger_nb); + flush_scheduled_work(); if (di-usb_chg.enabled) power_supply_unregister(di-usb_chg.psy); @@ -3307,6 +3344,11 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) di-ac_chg.enabled = di-pdata-ac_enabled; di-ac_chg.external = false; + /*notifier for external charger enabling*/ + if (!di-ac_chg.enabled) + blocking_notifier_chain_register( + charger_notifier_list, charger_nb); + /* USB supply */ /* power_supply base class */ di-usb_chg.psy.name = ab8500_usb; diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 9568f63..3ca00dd 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -24,6 +24,7 @@ #include linux/mfd/abx500.h #include linux/mfd/abx500/ux500_chargalg.h #include linux/mfd/abx500/ab8500-bm.h +#include linux/notifier.h /* Watchdog kick interval */ #define CHG_WD_INTERVAL(6 * HZ) @@ -255,6 +256,9 @@ static enum power_supply_property abx500_chargalg_props[] = { POWER_SUPPLY_PROP_HEALTH, }; +/*External charger prepare notifier*/ +BLOCKING_NOTIFIER_HEAD(charger_notifier_list); + /** * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer * @data: pointer to the abx500_chargalg structure @@ -508,6 +512,8 @@ static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di) static int abx500_chargalg_ac_en(struct abx500_chargalg *di
[PATCH 35/57] power: ab8500_fg: Report unscaled capacity
From: Martin Bergstrom martin.bergst...@stericsson.com Unscaled capacity should be reported for POWER_SUPPLY_PROP_CAPACITY. Signed-off-by: Martin Bergstrom martin.bergst...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_fg.c |6 ++ 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index fde189a..c5732e7 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2159,9 +2159,7 @@ static int ab8500_fg_get_property(struct power_supply *psy, val-intval = di-bat_cap.prev_mah; break; case POWER_SUPPLY_PROP_CAPACITY: - if (di-bat-capacity_scaling) - val-intval = di-bat_cap.cap_scale.scaled_cap; - else if (di-flags.batt_unknown !di-bat-chg_unknown_bat + if (di-flags.batt_unknown !di-bat-chg_unknown_bat di-flags.batt_id_received) val-intval = 100; else @@ -2625,7 +2623,7 @@ static ssize_t ab8500_show_capacity(struct device *dev, if (di-bat-capacity_scaling) capacity = di-bat_cap.cap_scale.scaled_cap; else - capacity = DIV_ROUND_CLOSEST(di-bat_cap.permille, 10); + capacity = di-bat_cap.prev_percent; return scnprintf(buf, PAGE_SIZE, %d\n, capacity); } -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 33/57] power: u8500_charger: Delay for USB enumeration
From: Paer-Olof Haakansson par-olof.hakans...@stericsson.com If charging is started before USB enumeration of an Accessory Charger Adapter has finished, the AB8500 will generate a VBUS_ERROR. This in turn results in timeouts and delays the enumeration with around 15 seconds. This patch delays the charging and then ramps currents slowly to avoid VBUS errors. The delay allows the enumeration to have finished before charging is turned on. Signed-off-by: Martin Sjoblom martin.w.sjob...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/mfd/ab8500-core.c |6 + drivers/power/ab8500_charger.c | 435 +-- 2 files changed, 329 insertions(+), 112 deletions(-) diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 47adf80..ef13fe1 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -786,6 +786,12 @@ static struct resource __devinitdata ab8500_charger_resources[] = { .end = AB8500_INT_CH_WD_EXP, .flags = IORESOURCE_IRQ, }, + { + .name = VBUS_CH_DROP_END, + .start = AB8500_INT_VBUS_CH_DROP_END, + .end = AB8500_INT_VBUS_CH_DROP_END, + .flags = IORESOURCE_IRQ, + }, }; static struct resource __devinitdata ab8500_btemp_resources[] = { diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 2a323cf..b3b8f77 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -52,6 +52,7 @@ #define MAIN_CH_INPUT_CURR_SHIFT 4 #define VBUS_IN_CURR_LIM_SHIFT 4 +#define AUTO_VBUS_IN_CURR_LIM_SHIFT4 #define LED_INDICATOR_PWM_ENA 0x01 #define LED_INDICATOR_PWM_DIS 0x00 @@ -85,14 +86,13 @@ /* Step up/down delay in us */ #define STEP_UDELAY1000 -/* Wait for enumeration before charging in ms */ -#define WAIT_FOR_USB_ENUMERATION (5 * 1000) - #define CHARGER_STATUS_POLL 10 /* in ms */ #define CHG_WD_INTERVAL(60 * HZ) #define AB8500_SW_CONTROL_FALLBACK 0x03 +/* Wait for enumeration before charging in us */ +#define WAIT_ACA_RID_ENUMERATION (5 * 1000) /* UsbLineStatus register - usb types */ enum ab8500_charger_link_status { @@ -182,12 +182,14 @@ struct ab8500_charger_event_flags { bool usbchargernotok; bool chgwdexp; bool vbus_collapse; + bool vbus_drop_end; }; struct ab8500_charger_usb_state { - bool usb_changed; int usb_current; + int usb_current_tmp; enum ab8500_usb_state state; + enum ab8500_usb_state state_tmp; spinlock_t usb_lock; }; @@ -207,6 +209,11 @@ struct ab8500_charger_usb_state { * @old_vbat Previously measured battery voltage * @usb_device_is_unrecognised USB device is unrecognised by the hardware * @autopower Indicate if we should have automatic pwron after pwrloss + * @invalid_charger_detect_state: + State when forcing AB to use invalid charger + * @is_aca_rid:Incicate if accessory is ACA type + * @current_stepping_sessions: + * Counter for current stepping sessions * @invalid_charger_detect_state State when forcing AB to use invalid charger * @parent:Pointer to the struct ab8500 * @gpadc: Pointer to the struct gpadc @@ -225,7 +232,6 @@ struct ab8500_charger_usb_state { * @check_usbchgnotok_work:Work for checking USB charger not ok status * @kick_wd_work: Work for kicking the charger watchdog in case * of ABB rev 1.* due to the watchog logic bug - * @attach_work: Work for checking the usb enumeration * @ac_charger_attached_work: Work for checking if AC charger is still * connected * @usb_charger_attached_work: Work for checking if USB charger is still @@ -234,6 +240,8 @@ struct ab8500_charger_usb_state { * @detect_usb_type_work: Work for detecting the USB type connected * @usb_link_status_work: Work for checking the new USB link status * @usb_state_changed_work:Work for checking USB state + * @attach_work: Work for detecting USB type + * @vbus_drop_end_work:Work for detecting VBUS drop end * @check_main_thermal_prot_work: * Work for checking Main thermal status * @check_usb_thermal_prot_work: @@ -252,6 +260,9 @@ struct ab8500_charger { bool usb_device_is_unrecognised; bool autopower; int invalid_charger_detect_state; + bool is_usb_host; + int is_aca_rid; + atomic_t current_stepping_sessions; struct ab8500 *parent; struct ab8500_gpadc *gpadc; struct abx500_charger_platform_data *pdata; @@ -264,17 +275,19 @@ struct ab8500_charger
[PATCH 32/57] power: ab8500_charger: Do not touch VBUSOVV bits
From: Jonas Aaberg jonas.ab...@stericsson.com Do not touch the VBUSOVV in USBCHTRL2 when running on AB8505. Signed-off-by: Jonas Aaberg jonas.ab...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com --- drivers/power/ab8500_charger.c| 22 -- include/linux/mfd/abx500/ab8500.h | 10 ++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 071c7c2..2a323cf 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2667,13 +2667,23 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) } } - /* VBUS OVV set to 6.3V and enable automatic current limitiation */ - ret = abx500_set_register_interruptible(di-dev, - AB8500_CHARGER, - AB8500_USBCH_CTRL2_REG, - VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA); + if (is_ab9540_2p0(di-parent) || is_ab8505_2p0(di-parent)) + ret = abx500_mask_and_set_register_interruptible(di-dev, + AB8500_CHARGER, + AB8500_USBCH_CTRL2_REG, + VBUS_AUTO_IN_CURR_LIM_ENA, + VBUS_AUTO_IN_CURR_LIM_ENA); + else + /* +* VBUS OVV set to 6.3V and enable automatic current limitation +*/ + ret = abx500_set_register_interruptible(di-dev, + AB8500_CHARGER, + AB8500_USBCH_CTRL2_REG, + VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA); if (ret) { - dev_err(di-dev, failed to set VBUS OVV\n); + dev_err(di-dev, + failed to set automatic current limitation\n); goto out; } diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h index 087b445..5a4b186 100644 --- a/include/linux/mfd/abx500/ab8500.h +++ b/include/linux/mfd/abx500/ab8500.h @@ -351,6 +351,16 @@ static inline int is_ab8500_2p0(struct ab8500 *ab) return (is_ab8500(ab) (ab-chip_id == AB8500_CUT2P0)); } +static inline int is_ab8505_2p0(struct ab8500 *ab) +{ + return (is_ab8505(ab) (ab-chip_id == AB8500_CUT2P0)); +} + +static inline int is_ab9540_2p0(struct ab8500 *ab) +{ + return (is_ab9540(ab) (ab-chip_id == AB8500_CUT2P0)); +} + int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq); #endif /* MFD_AB8500_H */ -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 30/57] power: ab8500: Flush sync all works
From: Jonas Aaberg jonas.ab...@stericsson.com Flush and sync all workqueues at suspend to avoid that we suspend in the middle of a work. Signed-off-by: Jonas Aaberg jonas.ab...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com --- drivers/power/ab8500_charger.c | 11 +++ drivers/power/ab8500_fg.c |5 + 2 files changed, 16 insertions(+), 0 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index ee5ad7b..071c7c2 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2862,6 +2862,17 @@ static int ab8500_charger_suspend(struct platform_device *pdev, if (delayed_work_pending(di-check_hw_failure_work)) cancel_delayed_work(di-check_hw_failure_work); + flush_delayed_work_sync(di-attach_work); + flush_delayed_work_sync(di-usb_charger_attached_work); + flush_delayed_work_sync(di-ac_charger_attached_work); + flush_delayed_work_sync(di-check_usbchgnotok_work); + flush_delayed_work_sync(di-check_vbat_work); + flush_delayed_work_sync(di-kick_wd_work); + + flush_work_sync(di-usb_link_status_work); + flush_work_sync(di-ac_work); + flush_work_sync(di-detect_usb_type_work); + return 0; } #else diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index e7a0e1f..0e71e7e 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2626,6 +2626,11 @@ static int ab8500_fg_suspend(struct platform_device *pdev, struct ab8500_fg *di = platform_get_drvdata(pdev); flush_delayed_work_sync(di-fg_periodic_work); + flush_work_sync(di-fg_work); + flush_work_sync(di-fg_acc_cur_work); + flush_delayed_work_sync(di-fg_reinit_work); + flush_delayed_work_sync(di-fg_low_bat_work); + flush_delayed_work_sync(di-fg_check_hw_failure_work); /* * If the FG is enabled we will disable it before going to suspend -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 28/57] power: ab8500 - Accessing Autopower register fails
From: Nicolas Guion nicolas.gu...@stericsson.com The fallback software control register has moved in the ab8505 and ab9540. Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Mattias WALLIN mattias.wal...@stericsson.com Reviewed-by: Nicolas GUION nicolas.gu...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_charger.c | 53 +++- 1 files changed, 36 insertions(+), 17 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 0a781a0..ee5ad7b 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -92,6 +92,8 @@ #define CHG_WD_INTERVAL(60 * HZ) +#define AB8500_SW_CONTROL_FALLBACK 0x03 + /* UsbLineStatus register - usb types */ enum ab8500_charger_link_status { USB_STAT_NOT_CONFIGURED, @@ -307,42 +309,59 @@ static enum power_supply_property ab8500_charger_usb_props[] = { static void ab8500_enable_disable_sw_fallback(struct ab8500_charger *di, bool fallback) { + u8 val; u8 reg; + u8 bank; + u8 bit; int ret; dev_dbg(di-dev, SW Fallback: %d\n, fallback); + if (is_ab8500(di-parent)) { + bank = 0x15; + reg = 0x0; + bit = 3; + } else { + bank = AB8500_SYS_CTRL1_BLOCK; + reg = AB8500_SW_CONTROL_FALLBACK; + bit = 0; + } + /* read the register containing fallback bit */ - ret = abx500_get_register_interruptible(di-dev, 0x15, 0x00, reg); - if (ret) { - dev_err(di-dev, %d write failed\n, __LINE__); + ret = abx500_get_register_interruptible(di-dev, bank, reg, val); + if (ret 0) { + dev_err(di-dev, %d read failed\n, __LINE__); return; } - /* enable the OPT emulation registers */ - ret = abx500_set_register_interruptible(di-dev, 0x11, 0x00, 0x2); - if (ret) { - dev_err(di-dev, %d write failed\n, __LINE__); - return; + if (is_ab8500(di-parent)) { + /* enable the OPT emulation registers */ + ret = abx500_set_register_interruptible(di-dev, +0x11, 0x00, 0x2); + if (ret) { + dev_err(di-dev, %d write failed\n, __LINE__); + goto disable_otp; + } } if (fallback) - reg |= 0x8; + val |= (1 bit); else - reg = ~0x8; + val = ~(1 bit); /* write back the changed fallback bit value to register */ - ret = abx500_set_register_interruptible(di-dev, 0x15, 0x00, reg); + ret = abx500_set_register_interruptible(di-dev, bank, reg, val); if (ret) { dev_err(di-dev, %d write failed\n, __LINE__); - return; } - /* disable the set OTP registers again */ - ret = abx500_set_register_interruptible(di-dev, 0x11, 0x00, 0x0); - if (ret) { - dev_err(di-dev, %d write failed\n, __LINE__); - return; +disable_otp: + if (is_ab8500(di-parent)) { + /* disable the set OTP registers again */ + ret = abx500_set_register_interruptible(di-dev, +0x11, 0x00, 0x0); + if (ret) + dev_err(di-dev, %d write failed\n, __LINE__); } } -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 26/57] power: charge: update watchdog for pm2xxx support
From: Loic Pallardy loic.palla...@stericsson.com AB and PMxxx doesn't have same watchdog refresh period Add watchdog to refresh period parameters in x500 charger structure, this should kick watchdog every 30sec. The AC charging should also kick both pm2xxx and the AB charger watchdog. Signed-off-by: Rajkumar Kasirajan rajkumar.kasira...@stericsson.com Signed-off-by: Loic Pallardy loic.palla...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Michel JAOUEN michel.jao...@stericsson.com Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_charger.c|6 ++ drivers/power/abx500_chargalg.c | 23 +-- include/linux/mfd/abx500/ux500_chargalg.h |3 +++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 3100f11..4129599 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -90,6 +90,8 @@ #define CHARGER_STATUS_POLL 10 /* in ms */ +#define CHG_WD_INTERVAL(60 * HZ) + /* UsbLineStatus register - usb types */ enum ab8500_charger_link_status { USB_STAT_NOT_CONFIGURED, @@ -2945,7 +2947,9 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di-ac_chg.max_out_curr = ab8500_charger_current_map[ ARRAY_SIZE(ab8500_charger_current_map) - 1]; + di-ac_chg.wdt_refresh = CHG_WD_INTERVAL; di-ac_chg.enabled = di-pdata-ac_enabled; + di-ac_chg.external = false; /* USB supply */ /* power_supply base class */ @@ -2964,7 +2968,9 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di-usb_chg.max_out_curr = ab8500_charger_current_map[ ARRAY_SIZE(ab8500_charger_current_map) - 1]; + di-usb_chg.wdt_refresh = CHG_WD_INTERVAL; di-usb_chg.enabled = di-pdata-usb_enabled; + di-usb_chg.external = false; /* Create a work queue for the charger */ di-charger_wq = diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index ca87cb2..d3efc2a 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -453,8 +453,18 @@ static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di) { /* Check if charger exists and kick watchdog if charging */ if (di-ac_chg di-ac_chg-ops.kick_wd - di-chg_info.online_chg AC_CHG) + di-chg_info.online_chg AC_CHG) { + /* +* If AB charger watchdog expired, pm2xxx charging +* gets disabled. To be safe, kick both AB charger watchdog +* and pm2xxx watchdog. +*/ + if (di-ac_chg-external + di-usb_chg di-usb_chg-ops.kick_wd) + di-usb_chg-ops.kick_wd(di-usb_chg); + return di-ac_chg-ops.kick_wd(di-ac_chg); + } else if (di-usb_chg di-usb_chg-ops.kick_wd di-chg_info.online_chg USB_CHG) return di-usb_chg-ops.kick_wd(di-usb_chg); @@ -1591,6 +1601,8 @@ static void abx500_chargalg_periodic_work(struct work_struct *work) static void abx500_chargalg_wd_work(struct work_struct *work) { int ret; + int refresh_time; + struct abx500_chargalg *di = container_of(work, struct abx500_chargalg, chargalg_wd_work.work); @@ -1600,8 +1612,15 @@ static void abx500_chargalg_wd_work(struct work_struct *work) if (ret 0) dev_err(di-dev, failed to kick watchdog\n); + if (di-chg_info.online_chg AC_CHG) + refresh_time = di-ac_chg-wdt_refresh; + else if (di-chg_info.online_chg USB_CHG) + refresh_time = di-usb_chg-wdt_refresh; + else + refresh_time = CHG_WD_INTERVAL; + queue_delayed_work(di-chargalg_wq, - di-chargalg_wd_work, CHG_WD_INTERVAL); + di-chargalg_wd_work, refresh_time); } /** diff --git a/include/linux/mfd/abx500/ux500_chargalg.h b/include/linux/mfd/abx500/ux500_chargalg.h index 5b77a61..d43ac0f 100644 --- a/include/linux/mfd/abx500/ux500_chargalg.h +++ b/include/linux/mfd/abx500/ux500_chargalg.h @@ -28,13 +28,16 @@ struct ux500_charger_ops { * @max_out_volt maximum output charger voltage in mV * @max_out_curr maximum output charger current in mA * @enabledindicates if this charger is used or not + * @external external charger unit (pm2xxx) */ struct ux500_charger { struct power_supply psy; struct ux500_charger_ops ops; int max_out_volt; int max_out_curr; + int
[PATCH 08/57] power: ab8500_fg: flush sync on suspend
From: Jonas Aaberg jonas.ab...@stericsson.com Do flush sync on the fg workqueue at suspend instead of just flushing it. Signed-off-by: Jonas Aaberg jonas.ab...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Johan BJORNSTEDT johan.bjornst...@stericsson.com --- drivers/power/ab8500_fg.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 342d118..1e02b00 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2437,7 +2437,7 @@ static int ab8500_fg_suspend(struct platform_device *pdev, { struct ab8500_fg *di = platform_get_drvdata(pdev); - flush_delayed_work(di-fg_periodic_work); + flush_delayed_work_sync(di-fg_periodic_work); /* * If the FG is enabled we will disable it before going to suspend -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 07/57] power: ab8500_bm: Detect removed charger
From: Jonas Aaberg jonas.ab...@stericsson.com Signed-off-by: Jonas Aaberg jonas.ab...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/power/ab8500_charger.c | 122 +++- 1 files changed, 121 insertions(+), 1 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index a7d0c3a..f7bba07 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -66,6 +66,11 @@ #define MAIN_CH_NOK0x01 #define VBUS_DET 0x80 +#define MAIN_CH_STATUS2_MAINCHGDROP0x80 +#define MAIN_CH_STATUS2_MAINCHARGERDETDBNC 0x40 +#define USB_CH_VBUSDROP0x40 +#define USB_CH_VBUSDETDBNC 0x01 + /* UsbLineStatus register bit masks */ #define AB8500_USB_LINK_STATUS 0x78 #define AB8500_STD_HOST_SUSP 0x18 @@ -80,6 +85,8 @@ /* Step up/down delay in us */ #define STEP_UDELAY1000 +#define CHARGER_STATUS_POLL 10 /* in ms */ + /* UsbLineStatus register - usb types */ enum ab8500_charger_link_status { USB_STAT_NOT_CONFIGURED, @@ -201,6 +208,10 @@ struct ab8500_charger_usb_state { * @check_usbchgnotok_work:Work for checking USB charger not ok status * @kick_wd_work: Work for kicking the charger watchdog in case * of ABB rev 1.* due to the watchog logic bug + * @ac_charger_attached_work: Work for checking if AC charger is still + * connected + * @usb_charger_attached_work: Work for checking if USB charger is still + * connected * @ac_work: Work for checking AC charger connection * @detect_usb_type_work: Work for detecting the USB type connected * @usb_link_status_work: Work for checking the new USB link status @@ -237,6 +248,8 @@ struct ab8500_charger { struct delayed_work check_hw_failure_work; struct delayed_work check_usbchgnotok_work; struct delayed_work kick_wd_work; + struct delayed_work ac_charger_attached_work; + struct delayed_work usb_charger_attached_work; struct work_struct ac_work; struct work_struct detect_usb_type_work; struct work_struct usb_link_status_work; @@ -347,6 +360,15 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di, dev_dbg(di-dev, USB connected:%i\n, connected); di-usb.charger_connected = connected; sysfs_notify(di-usb_chg.psy.dev-kobj, NULL, present); + + if (connected) { + queue_delayed_work(di-charger_wq, + di-usb_charger_attached_work, + HZ); + } else { + cancel_delayed_work_sync + (di-usb_charger_attached_work); + } } } @@ -1703,6 +1725,81 @@ static void ab8500_charger_ac_work(struct work_struct *work) sysfs_notify(di-ac_chg.psy.dev-kobj, NULL, present); } +static void ab8500_charger_usb_attached_work(struct work_struct *work) +{ + int i; + int ret; + u8 statval; + struct ab8500_charger *di = container_of(work, +struct ab8500_charger, +usb_charger_attached_work.work); + + for (i = 0 ; i 10; i++) { + ret = abx500_get_register_interruptible(di-dev, + AB8500_CHARGER, + AB8500_CH_USBCH_STAT1_REG, + statval); + if (ret 0) { + dev_err(di-dev, ab8500 read failed %d\n, + __LINE__); + goto reschedule; + } + if ((statval (USB_CH_VBUSDROP | + USB_CH_VBUSDETDBNC)) != + (USB_CH_VBUSDROP | USB_CH_VBUSDETDBNC)) + goto reschedule; + + msleep(CHARGER_STATUS_POLL); + } + + (void) ab8500_charger_usb_en(di-usb_chg, 0, 0, 0); + + return; +reschedule: + queue_delayed_work(di-charger_wq, + di-usb_charger_attached_work, + HZ); +} + +static void ab8500_charger_ac_attached_work(struct work_struct *work) +{ + + int i; + int ret; + u8 statval; + struct ab8500_charger *di = container_of(work, +struct ab8500_charger, +ac_charger_attached_work.work); + + for (i = 0 ; i 10; i++) { + ret = abx500_get_register_interruptible(di-dev, + AB8500_CHARGER
[PATCH 14/57] power: Adds support for Car/Travel Adapters
From: Hakan Berg hakan.b...@stericsson.com The Travel and Carkit adapter should be handled directly by the charger driver. Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_charger.c | 94 +- include/linux/mfd/abx500/ab8500-bm.h |1 + 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 06a7c8b..09edd9c 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -105,6 +105,18 @@ enum ab8500_charger_link_status { USB_STAT_HM_IDGND, USB_STAT_RESERVED, USB_STAT_NOT_VALID_LINK, + USB_STAT_PHY_EN, + USB_STAT_SUP_NO_IDGND_VBUS, + USB_STAT_SUP_IDGND_VBUS, + USB_STAT_CHARGER_LINE_1, + USB_STAT_CARKIT_1, + USB_STAT_CARKIT_2, + USB_STAT_ACA_DOCK_CHARGER, + USB_STAT_SAMSUNG_USB_PHY_DIS, + USB_STAT_SAMSUNG_USB_PHY_ENA, + USB_STAT_SAMSUNG_UART_PHY_DIS, + USB_STAT_SAMSUNG_UART_PHY_ENA, + USB_STAT_MOTOROLA_USB_PHY_ENA, }; enum ab8500_usb_state { @@ -577,7 +589,7 @@ static int ab8500_charger_detect_chargers(struct ab8500_charger *di) * Returns error code in case of failure else 0 on success */ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, - enum ab8500_charger_link_status link_status) + enum ab8500_charger_link_status link_status) { int ret = 0; @@ -585,16 +597,20 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, case USB_STAT_STD_HOST_NC: case USB_STAT_STD_HOST_C_NS: case USB_STAT_STD_HOST_C_S: - dev_dbg(di-dev, USB Type - Standard host is - detected through USB driver\n); + dev_dbg(di-dev, USB Type - Standard host is ); + dev_dbg(di-dev, detected through USB driver\n); di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P09; break; case USB_STAT_HOST_CHG_HS_CHIRP: di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; + dev_dbg(di-dev, USB Type - 0x%02x MaxCurr: %d, link_status, + di-max_usb_in_curr); break; case USB_STAT_HOST_CHG_HS: case USB_STAT_ACA_RID_C_HS: di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P9; + dev_dbg(di-dev, USB Type - 0x%02x MaxCurr: %d, link_status, + di-max_usb_in_curr); break; case USB_STAT_ACA_RID_A: /* @@ -602,6 +618,8 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, * can consume (300mA). Closest level is 1100mA */ di-max_usb_in_curr = USB_CH_IP_CUR_LVL_1P1; + dev_dbg(di-dev, USB Type - 0x%02x MaxCurr: %d, link_status, + di-max_usb_in_curr); break; case USB_STAT_ACA_RID_B: /* @@ -609,34 +627,50 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, * 100mA for potential accessory). Closest level is 1300mA */ di-max_usb_in_curr = USB_CH_IP_CUR_LVL_1P3; + dev_dbg(di-dev, USB Type - 0x%02x MaxCurr: %d, link_status, + di-max_usb_in_curr); break; - case USB_STAT_DEDICATED_CHG: case USB_STAT_HOST_CHG_NM: - case USB_STAT_ACA_RID_C_HS_CHIRP: + case USB_STAT_DEDICATED_CHG: case USB_STAT_ACA_RID_C_NM: + case USB_STAT_ACA_RID_C_HS_CHIRP: di-max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5; - break; - case USB_STAT_RESERVED: - /* -* This state is used to indicate that VBUS has dropped below -* the detection level 4 times in a row. This is due to the -* charger output current is set to high making the charger -* voltage collapse. This have to be propagated through to -* chargalg. This is done using the property -* POWER_SUPPLY_PROP_CURRENT_AVG = 1 -*/ - di-flags.vbus_collapse = true; - dev_dbg(di-dev, USB Type - USB_STAT_RESERVED - VBUS has collapsed\n); - ret = -1; + dev_dbg(di-dev, USB Type - 0x%02x MaxCurr: %d, link_status, + di-max_usb_in_curr); break; case USB_STAT_HM_IDGND: - case USB_STAT_NOT_CONFIGURED: case USB_STAT_NOT_VALID_LINK: + case USB_STAT_NOT_CONFIGURED: dev_err(di-dev, USB Type - Charging not allowed\n); di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05; ret = -ENXIO
[PATCH 16/57] power: bm remove superfluous BTEMP thermal comp.
From: Hakan Berg hakan.b...@stericsson.com BTEMP thermal compensation factor times 10 is applied in two places, probe and get_property. Removed from probe. Signed-off-by: Hakan Berg hakan.b...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Karl KOMIEROWSKI karl.komierow...@stericsson.com --- drivers/power/ab8500_btemp.c |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index 04f9dec..74cddba 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -1026,8 +1026,8 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) ab8500_btemp_periodic_work); /* Set BTEMP thermal limits. Low and Med are fixed */ - di-btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT * 10; - di-btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT * 10; + di-btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT; + di-btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT; ret = abx500_get_register_interruptible(di-dev, AB8500_CHARGER, AB8500_BTEMP_HIGH_TH, val); -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 21/57] power: Overflow in current calculation
From: Paer-Olof Haakansson par-olof.hakans...@stericsson.com When calculating the average current the nominator will overflow when the charging current is high. Signed-off-by: Henrik Sölver henrik.sol...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Par-Olof HAKANSSON par-olof.hakans...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_fg.c | 15 --- 1 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 46010ec..7c42150 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -805,15 +805,13 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work) /* * Convert to unit value in mA -* Full scale input voltage is -* 66.660mV = LSB = 66.660mV/(4096*res) = 1.627mA -* Given a 250ms conversion cycle time the LSB corresponds -* to 112.9 nAh. Convert to current by dividing by the conversion +* by dividing by the conversion * time in hours (= samples / (3600 * 4)h) -* 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm +* and multiply with 1000 */ - di-avg_curr = (val * QLSB_NANO_AMP_HOURS_X10 * 36) / - (1000 * di-bat-fg_res * (di-fg_samples / 4)); + + di-avg_curr = (di-accu_charge * 36) / + ((di-fg_samples / 4) * 10); di-flags.conv_done = true; @@ -821,6 +819,9 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work) queue_work(di-fg_wq, di-fg_work); + dev_dbg(di-dev, + fg_res: %d, fg_samples: %d, gasg: %d, accu_charge: %d\n, + di-bat-fg_res, di-fg_samples, val, di-accu_charge); return; exit: dev_err(di-dev, -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 25/57] power: ab8500: adaptation to ab version
From: Michel JAOUEN michel.jao...@stericsson.com Add AB9540 and AB8505 support to ab8500_temp driver. Signed-off-by: Rajkumar Kasirajan rajkumar.kasira...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Michel JAOUEN michel.jao...@stericsson.com Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_btemp.c | 71 ++--- include/linux/mfd/abx500/ab8500-bm.h |2 + 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index 74cddba..506f124 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -37,6 +37,9 @@ #define BTEMP_BATCTRL_CURR_SRC_7UA 7 #define BTEMP_BATCTRL_CURR_SRC_20UA20 +#define BTEMP_BATCTRL_CURR_SRC_16UA16 +#define BTEMP_BATCTRL_CURR_SRC_18UA18 + #define to_ab8500_btemp_device_info(x) container_of((x), \ struct ab8500_btemp, btemp_psy); @@ -212,10 +215,18 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di, /* Only do this for batteries with internal NTC */ if (di-bat-adc_therm == ABx500_ADC_THERM_BATCTRL enable) { - if (di-curr_source == BTEMP_BATCTRL_CURR_SRC_7UA) - curr = BAT_CTRL_7U_ENA; - else - curr = BAT_CTRL_20U_ENA; + + if (is_ab9540(di-parent) || is_ab8505(di-parent)) { + if (di-curr_source == BTEMP_BATCTRL_CURR_SRC_16UA) + curr = BAT_CTRL_16U_ENA; + else + curr = BAT_CTRL_18U_ENA; + } else { + if (di-curr_source == BTEMP_BATCTRL_CURR_SRC_7UA) + curr = BAT_CTRL_7U_ENA; + else + curr = BAT_CTRL_20U_ENA; + } dev_dbg(di-dev, Set BATCTRL %duA\n, di-curr_source); @@ -246,11 +257,22 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di, } else if (di-bat-adc_therm == ABx500_ADC_THERM_BATCTRL !enable) { dev_dbg(di-dev, Disable BATCTRL curr source\n); - /* Write 0 to the curr bits */ - ret = abx500_mask_and_set_register_interruptible(di-dev, - AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE, - BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA, - ~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA)); + if (is_ab9540(di-parent) || is_ab8505(di-parent)) { + /* Write 0 to the curr bits */ + ret = abx500_mask_and_set_register_interruptible( + di-dev, + AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE, + BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA, + ~(BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA)); + } else { + /* Write 0 to the curr bits */ + ret = abx500_mask_and_set_register_interruptible( + di-dev, + AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE, + BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA, + ~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA)); + } + if (ret) { dev_err(di-dev, %s failed disabling current source\n, __func__); @@ -292,11 +314,20 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di, * if we got an error above */ disable_curr_source: - /* Write 0 to the curr bits */ - ret = abx500_mask_and_set_register_interruptible(di-dev, + if (is_ab9540(di-parent) || is_ab8505(di-parent)) { + /* Write 0 to the curr bits */ + ret = abx500_mask_and_set_register_interruptible(di-dev, + AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE, + BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA, + ~(BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA)); + } else { + /* Write 0 to the curr bits */ + ret = abx500_mask_and_set_register_interruptible(di-dev, AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE, BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA, ~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA)); + } + if (ret) { dev_err(di-dev, %s failed disabling current source\n, __func__); @@ -510,8 +541,11 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) { int res; u8 i; + if (is_ab9540(di-parent) || is_ab8505(di-parent)) + di-curr_source
[PATCH 23/57] power: Add plaform data charger configurables
From: Loic Pallardy loic.palla...@stericsson.com Allow to indicate wheter AC and USB charge capabilities are supported from platform data. Signed-off-by: Loic Pallardy loic.palla...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/58093 Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Olivier CLERGEAUD olivier.clerge...@stericsson.com --- drivers/power/ab8500_charger.c| 36 ++-- include/linux/mfd/abx500.h|2 + include/linux/mfd/abx500/ux500_chargalg.h |2 + 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index cbc9fd7..3100f11 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2878,8 +2878,11 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev) destroy_workqueue(di-charger_wq); flush_scheduled_work(); - power_supply_unregister(di-usb_chg.psy); - power_supply_unregister(di-ac_chg.psy); + if (di-usb_chg.enabled) + power_supply_unregister(di-usb_chg.psy); + if (di-ac_chg.enabled) + power_supply_unregister(di-ac_chg.psy); + platform_set_drvdata(pdev, NULL); kfree(di); @@ -2942,6 +2945,7 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di-ac_chg.max_out_curr = ab8500_charger_current_map[ ARRAY_SIZE(ab8500_charger_current_map) - 1]; + di-ac_chg.enabled = di-pdata-ac_enabled; /* USB supply */ /* power_supply base class */ @@ -2960,7 +2964,7 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di-usb_chg.max_out_curr = ab8500_charger_current_map[ ARRAY_SIZE(ab8500_charger_current_map) - 1]; - + di-usb_chg.enabled = di-pdata-usb_enabled; /* Create a work queue for the charger */ di-charger_wq = @@ -3036,17 +3040,21 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) } /* Register AC charger class */ - ret = power_supply_register(di-dev, di-ac_chg.psy); - if (ret) { - dev_err(di-dev, failed to register AC charger\n); - goto free_regulator; + if (di-ac_chg.enabled) { + ret = power_supply_register(di-dev, di-ac_chg.psy); + if (ret) { + dev_err(di-dev, failed to register AC charger\n); + goto free_regulator; + } } /* Register USB charger class */ - ret = power_supply_register(di-dev, di-usb_chg.psy); - if (ret) { - dev_err(di-dev, failed to register USB charger\n); - goto free_ac; + if (di-usb_chg.enabled) { + ret = power_supply_register(di-dev, di-usb_chg.psy); + if (ret) { + dev_err(di-dev, failed to register USB charger\n); + goto free_ac; + } } di-usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); @@ -3122,9 +3130,11 @@ free_irq: put_usb_phy: usb_put_phy(di-usb_phy); free_usb: - power_supply_unregister(di-usb_chg.psy); + if (di-usb_chg.enabled) + power_supply_unregister(di-usb_chg.psy); free_ac: - power_supply_unregister(di-ac_chg.psy); + if (di-ac_chg.enabled) + power_supply_unregister(di-ac_chg.psy); free_regulator: regulator_put(di-regu); free_charger_wq: diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h index 4d44a10..eef1ddc 100644 --- a/include/linux/mfd/abx500.h +++ b/include/linux/mfd/abx500.h @@ -398,6 +398,8 @@ struct abx500_charger_platform_data { char **supplied_to; size_t num_supplicants; bool autopower_cfg; + bool ac_enabled; + bool usb_enabled; }; struct abx500_btemp_platform_data { diff --git a/include/linux/mfd/abx500/ux500_chargalg.h b/include/linux/mfd/abx500/ux500_chargalg.h index 9b07725..5b77a61 100644 --- a/include/linux/mfd/abx500/ux500_chargalg.h +++ b/include/linux/mfd/abx500/ux500_chargalg.h @@ -27,12 +27,14 @@ struct ux500_charger_ops { * @opsux500 charger operations * @max_out_volt maximum output charger voltage in mV * @max_out_curr maximum output charger current in mA + * @enabledindicates if this charger is used or not */ struct ux500_charger { struct power_supply psy; struct ux500_charger_ops ops; int max_out_volt; int max_out_curr; + bool enabled; }; #endif -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord
[PATCH 22/57] power: AB workaround for invalid charger
From: Henrik Sölver henrik.sol...@stericsson.com AB8500 refuses to start charging when some types of non standard chargers are connected. This change force the AB to start charging. Signed-off-by: Henrik Sölver henrik.sol...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Yvan FILLION yvan.fill...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_charger.c | 70 +-- 1 files changed, 66 insertions(+), 4 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 7cd4165..cbc9fd7 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -203,6 +203,7 @@ struct ab8500_charger_usb_state { * @old_vbat Previously measured battery voltage * @usb_device_is_unrecognised USB device is unrecognised by the hardware * @autopower Indicate if we should have automatic pwron after pwrloss + * @invalid_charger_detect_state State when forcing AB to use invalid charger * @parent:Pointer to the struct ab8500 * @gpadc: Pointer to the struct gpadc * @pdata: Pointer to the abx500_charger platform data @@ -246,6 +247,7 @@ struct ab8500_charger { int old_vbat; bool usb_device_is_unrecognised; bool autopower; + int invalid_charger_detect_state; struct ab8500 *parent; struct ab8500_gpadc *gpadc; struct abx500_charger_platform_data *pdata; @@ -650,7 +652,6 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, break; } case USB_STAT_HM_IDGND: - case USB_STAT_NOT_VALID_LINK: dev_err(di-dev, USB Type - Charging not allowed\n); di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05; ret = -ENXIO; @@ -679,6 +680,9 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; dev_dbg(di-dev, USB Type - 0x%02x MaxCurr: %d, link_status, di-max_usb_in_curr); + case USB_STAT_NOT_VALID_LINK: + dev_err(di-dev, USB Type invalid - try charging anyway\n); + di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; break; default: @@ -1945,7 +1949,9 @@ static void ab8500_charger_usb_link_attach_work(struct work_struct *work) */ static void ab8500_charger_usb_link_status_work(struct work_struct *work) { + int detected_chargers; int ret; + u8 val; struct ab8500_charger *di = container_of(work, struct ab8500_charger, usb_link_status_work); @@ -1955,11 +1961,66 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) * synchronously, we have the check if is * connected by reading the status register */ - ret = ab8500_charger_detect_chargers(di); - if (ret 0) + detected_chargers = ab8500_charger_detect_chargers(di); + if (detected_chargers 0) return; - if (!(ret USB_PW_CONN)) { + /* +* Some chargers that breaks the USB spec is +* identified as invalid by AB8500 and it refuse +* to start the charging process. but by jumping +* thru a few hoops it can be forced to start. +*/ + ret = abx500_get_register_interruptible(di-dev, AB8500_USB, + AB8500_USB_LINE_STAT_REG, val); + if (ret = 0) + dev_dbg(di-dev, UsbLineStatus register = 0x%02x\n, val); + else + dev_dbg(di-dev, Error reading USB link status\n); + + if (detected_chargers USB_PW_CONN) { + if (((val AB8500_USB_LINK_STATUS) 3) == + USB_STAT_NOT_VALID_LINK + di-invalid_charger_detect_state == 0) { + dev_dbg(di-dev, +Invalid charger detected, state= 0\n); + /*Enable charger*/ + abx500_mask_and_set_register_interruptible(di-dev, + AB8500_CHARGER, + AB8500_USBCH_CTRL1_REG, + 0x01, 0x01) + /*Enable charger detection*/ + abx500_mask_and_set_register_interruptible(di-dev, + AB8500_USB, + AB8500_MCH_IPT_CURLVL_REG, + 0x01, 0x01); + di-invalid_charger_detect_state = 1; + /*exit and wait for new link status interrupt.*/ + return; + + } + if (di-invalid_charger_detect_state == 1
[PATCH 20/57] power: Adds support for legacy USB chargers
From: Marcus Cooper marcus.xm.coo...@stericsson.com A Legacy USB charger should be handled directly by the charger driver. Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Karl KOMIEROWSKI karl.komierow...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_charger.c | 66 ++- 1 files changed, 57 insertions(+), 9 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 4155feb..7cd4165 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -85,6 +85,9 @@ /* Step up/down delay in us */ #define STEP_UDELAY1000 +/* Wait for enumeration before charging in ms */ +#define WAIT_FOR_USB_ENUMERATION (5 * 1000) + #define CHARGER_STATUS_POLL 10 /* in ms */ /* UsbLineStatus register - usb types */ @@ -198,6 +201,7 @@ struct ab8500_charger_usb_state { * charger is enabled * @vbat Battery voltage * @old_vbat Previously measured battery voltage + * @usb_device_is_unrecognised USB device is unrecognised by the hardware * @autopower Indicate if we should have automatic pwron after pwrloss * @parent:Pointer to the struct ab8500 * @gpadc: Pointer to the struct gpadc @@ -216,6 +220,7 @@ struct ab8500_charger_usb_state { * @check_usbchgnotok_work:Work for checking USB charger not ok status * @kick_wd_work: Work for kicking the charger watchdog in case * of ABB rev 1.* due to the watchog logic bug + * @attach_work: Work for checking the usb enumeration * @ac_charger_attached_work: Work for checking if AC charger is still * connected * @usb_charger_attached_work: Work for checking if USB charger is still @@ -239,6 +244,7 @@ struct ab8500_charger { bool vddadc_en_usb; int vbat; int old_vbat; + bool usb_device_is_unrecognised; bool autopower; struct ab8500 *parent; struct ab8500_gpadc *gpadc; @@ -256,6 +262,7 @@ struct ab8500_charger { struct delayed_work check_hw_failure_work; struct delayed_work check_usbchgnotok_work; struct delayed_work kick_wd_work; + struct delayed_work attach_work; struct delayed_work ac_charger_attached_work; struct delayed_work usb_charger_attached_work; struct work_struct ac_work; @@ -588,6 +595,8 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, { int ret = 0; + di-usb_device_is_unrecognised = false; + switch (link_status) { case USB_STAT_STD_HOST_NC: case USB_STAT_STD_HOST_C_NS: @@ -633,9 +642,15 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, dev_dbg(di-dev, USB Type - 0x%02x MaxCurr: %d, link_status, di-max_usb_in_curr); break; + case USB_STAT_NOT_CONFIGURED: + if (di-vbus_detected) { + di-usb_device_is_unrecognised = true; + dev_dbg(di-dev, USB Type - Legacy charger.\n); + di-max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5; + break; + } case USB_STAT_HM_IDGND: case USB_STAT_NOT_VALID_LINK: - case USB_STAT_NOT_CONFIGURED: dev_err(di-dev, USB Type - Charging not allowed\n); di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05; ret = -ENXIO; @@ -1899,6 +1914,30 @@ static void ab8500_charger_detect_usb_type_work(struct work_struct *work) } /** + * ab8500_charger_usb_link_attach_work() - delayd work to detect USB type + * @work: pointer to the work_struct structure + * + * Detect the type of USB plugged + */ +static void ab8500_charger_usb_link_attach_work(struct work_struct *work) +{ + int ret; + + struct ab8500_charger *di = container_of(work, + struct ab8500_charger, attach_work.work); + + /* Update maximum input current if USB enumeration is not detected */ + if (!di-usb.charger_online) { + ret = ab8500_charger_set_vbus_in_curr(di, di-max_usb_in_curr); + if (ret) + return; + } + + ab8500_charger_set_usb_connected(di, true); + ab8500_power_supply_changed(di, di-usb_chg.psy); +} + +/** * ab8500_charger_usb_link_status_work() - work to detect USB type * @work: pointer to the work_struct structure * @@ -1928,14 +1967,20 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) di-vbus_detected = 1; ret = ab8500_charger_read_usb_type(di); if (!ret) { - /* Update maximum input current */ - ret
[PATCH 19/57] power: remove unused defines.
From: Marcus Cooper marcus.xm.coo...@stericsson.com Cleanup of the ab8500_charger driver. Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Karl KOMIEROWSKI karl.komierow...@stericsson.com --- drivers/power/ab8500_charger.c |5 - 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 09edd9c..4155feb 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -112,11 +112,6 @@ enum ab8500_charger_link_status { USB_STAT_CARKIT_1, USB_STAT_CARKIT_2, USB_STAT_ACA_DOCK_CHARGER, - USB_STAT_SAMSUNG_USB_PHY_DIS, - USB_STAT_SAMSUNG_USB_PHY_ENA, - USB_STAT_SAMSUNG_UART_PHY_DIS, - USB_STAT_SAMSUNG_UART_PHY_ENA, - USB_STAT_MOTOROLA_USB_PHY_ENA, }; enum ab8500_usb_state { -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 17/57] power: ab8500_bm: Added support for BATT_OVV
From: Hakan Berg hakan.b...@stericsson.com Add support for the battery over-voltage situation Signed-off-by: Hakan Berg hakan.b...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Karl KOMIEROWSKI karl.komierow...@stericsson.com --- drivers/power/ab8500_fg.c | 32 1 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index c4d9307..8507254 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -1842,24 +1842,26 @@ static void ab8500_fg_check_hw_failure_work(struct work_struct *work) * If we have had a battery over-voltage situation, * check ovv-bit to see if it should be reset. */ - if (di-flags.bat_ovv) { - ret = abx500_get_register_interruptible(di-dev, - AB8500_CHARGER, AB8500_CH_STAT_REG, - reg_value); - if (ret 0) { - dev_err(di-dev, %s ab8500 read failed\n, __func__); - return; - } - if ((reg_value BATT_OVV) != BATT_OVV) { - dev_dbg(di-dev, Battery recovered from OVV\n); - di-flags.bat_ovv = false; + ret = abx500_get_register_interruptible(di-dev, + AB8500_CHARGER, AB8500_CH_STAT_REG, + reg_value); + if (ret 0) { + dev_err(di-dev, %s ab8500 read failed\n, __func__); + return; + } + if ((reg_value BATT_OVV) == BATT_OVV) { + if (!di-flags.bat_ovv) { + dev_dbg(di-dev, Battery OVV\n); + di-flags.bat_ovv = true; power_supply_changed(di-fg_psy); - return; } - /* Not yet recovered from ovv, reschedule this test */ queue_delayed_work(di-fg_wq, di-fg_check_hw_failure_work, - round_jiffies(HZ)); + HZ); + } else { + dev_dbg(di-dev, Battery recovered from OVV\n); + di-flags.bat_ovv = false; + power_supply_changed(di-fg_psy); } } @@ -2039,8 +2041,6 @@ static irqreturn_t ab8500_fg_batt_ovv_handler(int irq, void *_di) struct ab8500_fg *di = _di; dev_dbg(di-dev, Battery OVV\n); - di-flags.bat_ovv = true; - power_supply_changed(di-fg_psy); /* Schedule a new HW failure check */ queue_delayed_work(di-fg_wq, di-fg_check_hw_failure_work, 0); -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 15/57] power: ab8500_fg: Round capacity output
From: pender01 peter.enderb...@stericsson.com Round the capacity values for better enduser experience. Signed-off-by: pender01 peter.enderb...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_fg.c | 28 +++- 1 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 492f6bf..c4d9307 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -31,6 +31,7 @@ #include linux/mfd/abx500.h #include linux/time.h #include linux/completion.h +#include linux/kernel.h #define MILLI_TO_MICRO 1000 #define FG_LSB_IN_MA 1627 @@ -1160,7 +1161,7 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di) { int ret, percent; - percent = di-bat_cap.permille / 10; + percent = DIV_ROUND_CLOSEST(di-bat_cap.permille, 10); if (percent = di-bat-cap_levels-critical || di-flags.low_bat) @@ -1281,6 +1282,7 @@ static void ab8500_fg_update_cap_scalers(struct ab8500_fg *di) static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) { bool changed = false; + int percent = DIV_ROUND_CLOSEST(di-bat_cap.permille, 10); di-bat_cap.level = ab8500_fg_capacity_level(di); @@ -1312,6 +1314,7 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) dev_dbg(di-dev, Battery low, set capacity to 0\n); di-bat_cap.prev_percent = 0; di-bat_cap.permille = 0; + percent = 0; di-bat_cap.prev_mah = 0; di-bat_cap.mah = 0; changed = true; @@ -1321,7 +1324,7 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) * and show 100% during maintenance charging (scaling). */ if (di-flags.force_full) { - di-bat_cap.prev_percent = di-bat_cap.permille / 10; + di-bat_cap.prev_percent = percent; di-bat_cap.prev_mah = di-bat_cap.mah; changed = true; @@ -1334,19 +1337,18 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) di-bat_cap.prev_percent; di-bat_cap.cap_scale.disable_cap_level = 100; } - } else if (di-bat_cap.prev_percent != - (di-bat_cap.permille) / 10) { + } else if (di-bat_cap.prev_percent != percent) { dev_dbg(di-dev, battery reported full but capacity dropping: %d\n, - di-bat_cap.permille / 10); - di-bat_cap.prev_percent = di-bat_cap.permille / 10; + percent); + di-bat_cap.prev_percent = percent; di-bat_cap.prev_mah = di-bat_cap.mah; changed = true; } - } else if (di-bat_cap.prev_percent != di-bat_cap.permille / 10) { - if (di-bat_cap.permille / 10 == 0) { + } else if (di-bat_cap.prev_percent != percent) { + if (percent == 0) { /* * We will not report 0% unless we've got * the LOW_BAT IRQ, no matter what the FG @@ -1356,11 +1358,11 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) di-bat_cap.permille = 1; di-bat_cap.prev_mah = 1; di-bat_cap.mah = 1; + percent = 1; changed = true; } else if (!(!di-flags.charging - (di-bat_cap.permille / 10) - di-bat_cap.prev_percent) || init) { + percent di-bat_cap.prev_percent) || init) { /* * We do not allow reported capacity to go up * unless we're charging or if we're in init @@ -1368,9 +1370,9 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) dev_dbg(di-dev, capacity changed from %d to %d (%d)\n, di-bat_cap.prev_percent, - di-bat_cap.permille / 10, + percent, di-bat_cap.permille); - di-bat_cap.prev_percent = di-bat_cap.permille / 10; + di-bat_cap.prev_percent = percent; di-bat_cap.prev_mah = di-bat_cap.mah; changed = true; @@ -1378,7
[PATCH 13/57] power: ab8500_bm: Ignore false btemp low interrupt
From: Hakan Berg hakan.b...@stericsson.com Ignore the low btemp interrupts for ab8500 3.0 and 3.3 Signed-off-by: Hakan Berg hakan.b...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_btemp.c | 22 +++--- include/linux/mfd/abx500/ab8500.h |5 + 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index 45b10ad..04f9dec 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -622,9 +622,9 @@ static irqreturn_t ab8500_btemp_templow_handler(int irq, void *_di) { struct ab8500_btemp *di = _di; - if (is_ab8500_2p0_or_earlier(di-parent)) { - dev_dbg(di-dev, Ignore false btemp low irq -for ABB cut 1.0, 1.1 and 2.0\n); + if (is_ab8500_3p3_or_earlier(di-parent)) { + dev_dbg(di-dev, Ignore false btemp low irq); + dev_dbg(di-dev, for ABB cut 1.0, 1.1, 2.0 and 3.3\n); } else { dev_crit(di-dev, Battery temperature lower than -10deg c\n); @@ -738,30 +738,30 @@ static int ab8500_btemp_get_temp(struct ab8500_btemp *di) int temp = 0; /* -* The BTEMP events are not reliabe on AB8500 cut2.0 +* The BTEMP events are not reliabe on AB8500 cut3.3 * and prior versions */ - if (is_ab8500_2p0_or_earlier(di-parent)) { + if (is_ab8500_3p3_or_earlier(di-parent)) { temp = di-bat_temp * 10; } else { if (di-events.btemp_low) { if (temp di-btemp_ranges.btemp_low_limit) - temp = di-btemp_ranges.btemp_low_limit; + temp = di-btemp_ranges.btemp_low_limit * 10; else temp = di-bat_temp * 10; } else if (di-events.btemp_high) { if (temp di-btemp_ranges.btemp_high_limit) - temp = di-btemp_ranges.btemp_high_limit; + temp = di-btemp_ranges.btemp_high_limit * 10; else temp = di-bat_temp * 10; } else if (di-events.btemp_lowmed) { if (temp di-btemp_ranges.btemp_med_limit) - temp = di-btemp_ranges.btemp_med_limit; + temp = di-btemp_ranges.btemp_med_limit * 10; else temp = di-bat_temp * 10; } else if (di-events.btemp_medhigh) { if (temp di-btemp_ranges.btemp_med_limit) - temp = di-btemp_ranges.btemp_med_limit; + temp = di-btemp_ranges.btemp_med_limit * 10; else temp = di-bat_temp * 10; } else @@ -1026,8 +1026,8 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) ab8500_btemp_periodic_work); /* Set BTEMP thermal limits. Low and Med are fixed */ - di-btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT; - di-btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT; + di-btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT * 10; + di-btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT * 10; ret = abx500_get_register_interruptible(di-dev, AB8500_CHARGER, AB8500_BTEMP_HIGH_TH, val); diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h index db8a1e3..087b445 100644 --- a/include/linux/mfd/abx500/ab8500.h +++ b/include/linux/mfd/abx500/ab8500.h @@ -340,6 +340,11 @@ static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab) return (is_ab8500(ab) (ab-chip_id = AB8500_CUT2P0)); } +static inline int is_ab8500_3p3_or_earlier(struct ab8500 *ab) +{ + return (is_ab8500(ab) (ab-chip_id = AB8500_CUT3P3)); +} + /* exclude also ab8505, ab9540... */ static inline int is_ab8500_2p0(struct ab8500 *ab) { -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 12/57] power: ab8500_fg: balance IRQ enable
From: Rickard Andersson rickard.anders...@stericsson.com In case of time out error IRQ needs to be disabled otherwise we will get unbalanced enable/disable pairs. Signed-off-by: Rickard Andersson rickard.anders...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_fg.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 7af616c..492f6bf 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -746,6 +746,7 @@ int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di) dev_dbg(di-dev, %s instant current: %d, __func__, res); return res; fail: + disable_irq(di-irq); mutex_unlock(di-cc_lock); return ret; } -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 11/57] power: Recharge condition not optimal for battery
From: Marcus Cooper marcus.xm.coo...@stericsson.com Today the battery recharge is determined with a voltage threshold. This voltage threshold is only valid when the battery is relaxed. In charging algorithm the voltage read is the loaded battery voltage and no compensation is done to get the relaxed voltage. When maintenance charging is not selected, this makes the recharging condition to almost immediately activate when there is a discharge present on the battery. Depending on which vendor the battery comes from this behavior can wear out the battery much faster than normal. The fuelgauge driver is responsible to monitor the actual battery capacity and is able to estimate the remaining capacity. It is better to use the remaining capacity as a limit to determine when battery should be recharged. Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Hakan BERG hakan.b...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_fg.c | 157 +++ drivers/power/abx500_chargalg.c | 59 +++ include/linux/mfd/abx500.h |6 +- 3 files changed, 191 insertions(+), 31 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 0db17c7..7af616c 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -112,6 +112,13 @@ struct ab8500_fg_avg_cap { int sum; }; +struct ab8500_fg_cap_scaling { + bool enable; + int cap_to_scale[2]; + int disable_cap_level; + int scaled_cap; +}; + struct ab8500_fg_battery_capacity { int max_mah_design; int max_mah; @@ -122,6 +129,7 @@ struct ab8500_fg_battery_capacity { int prev_percent; int prev_level; int user_mah; + struct ab8500_fg_cap_scaling cap_scale; }; struct ab8500_fg_flags { @@ -928,10 +936,11 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di) resist = tbl[tbl_size - 1].resist; } - dev_dbg(di-dev, %s Temp: %d battery internal resistance: %d -fg resistance %d, total: %d (mOhm)\n, - __func__, di-bat_temp, resist, di-bat-fg_res / 10, - (di-bat-fg_res / 10) + resist); + dev_dbg(di-dev, %s Temp: %d battery internal resistance: %d, + __func__, di-bat_temp, resist); + dev_dbg(di-dev, fg resistance %d, total: %d (mOhm)\n, + di-bat-fg_res / 10, + (di-bat-fg_res / 10) + resist); /* fg_res variable is in 0.1mOhm */ resist += di-bat-fg_res / 10; @@ -1168,6 +1177,99 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di) } /** + * ab8500_fg_calculate_scaled_capacity() - Capacity scaling + * @di:pointer to the ab8500_fg structure + * + * Calculates the capacity to be shown to upper layers. Scales the capacity + * to have 100% as a reference from the actual capacity upon removal of charger + * when charging is in maintenance mode. + */ +static int ab8500_fg_calculate_scaled_capacity(struct ab8500_fg *di) +{ + struct ab8500_fg_cap_scaling *cs = di-bat_cap.cap_scale; + int capacity = di-bat_cap.prev_percent; + + if (!cs-enable) + return capacity; + + /* +* As long as we are in fully charge mode scale the capacity +* to show 100%. +*/ + if (di-flags.fully_charged) { + cs-cap_to_scale[0] = 100; + cs-cap_to_scale[1] = + max(capacity, di-bat-fg_params-maint_thres); + dev_dbg(di-dev, Scale cap with %d/%d\n, +cs-cap_to_scale[0], cs-cap_to_scale[1]); + } + + /* Calculates the scaled capacity. */ + if ((cs-cap_to_scale[0] != cs-cap_to_scale[1]) +(cs-cap_to_scale[1] 0)) + capacity = min(100, +DIV_ROUND_CLOSEST(di-bat_cap.prev_percent * +cs-cap_to_scale[0], +cs-cap_to_scale[1])); + + if (di-flags.charging) { + if (capacity cs-disable_cap_level) { + cs-disable_cap_level = capacity; + dev_dbg(di-dev, Cap to stop scale lowered %d%%\n, + cs-disable_cap_level); + } else if (!di-flags.fully_charged) { + if (di-bat_cap.prev_percent = + cs-disable_cap_level) { + dev_dbg(di-dev, Disabling scaled capacity\n); + cs-enable = false; + capacity = di-bat_cap.prev_percent; + } else { + dev_dbg(di-dev
[PATCH 10/57] power: ab8500_charger: Handle gpadc errors
From: Jonas Aaberg jonas.ab...@stericsson.com Gracefully handle gpadc conversion errors. Signed-off-by: Jonas Aaberg jonas.ab...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Johan BJORNSTEDT johan.bjornst...@stericsson.com --- drivers/power/ab8500_charger.c | 22 ++ 1 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index f7bba07..06a7c8b 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -157,6 +157,7 @@ struct ab8500_charger_info { int charger_voltage; int cv_active; bool wd_expired; + int charger_current; }; struct ab8500_charger_event_flags { @@ -2341,6 +2342,7 @@ static int ab8500_charger_ac_get_property(struct power_supply *psy, union power_supply_propval *val) { struct ab8500_charger *di; + int ret; di = to_ab8500_charger_ac_device_info(psy_to_ux500_charger(psy)); @@ -2362,7 +2364,10 @@ static int ab8500_charger_ac_get_property(struct power_supply *psy, val-intval = di-ac.charger_connected; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - di-ac.charger_voltage = ab8500_charger_get_ac_voltage(di); + ret = ab8500_charger_get_ac_voltage(di); + if (ret = 0) + di-ac.charger_voltage = ret; + /* On error, use previous value */ val-intval = di-ac.charger_voltage * 1000; break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: @@ -2374,7 +2379,10 @@ static int ab8500_charger_ac_get_property(struct power_supply *psy, val-intval = di-ac.cv_active; break; case POWER_SUPPLY_PROP_CURRENT_NOW: - val-intval = ab8500_charger_get_ac_current(di) * 1000; + ret = ab8500_charger_get_ac_current(di); + if (ret = 0) + di-ac.charger_current = ret; + val-intval = di-ac.charger_current * 1000; break; default: return -EINVAL; @@ -2401,6 +2409,7 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy, union power_supply_propval *val) { struct ab8500_charger *di; + int ret; di = to_ab8500_charger_usb_device_info(psy_to_ux500_charger(psy)); @@ -2424,7 +2433,9 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy, val-intval = di-usb.charger_connected; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - di-usb.charger_voltage = ab8500_charger_get_vbus_voltage(di); + ret = ab8500_charger_get_vbus_voltage(di); + if (ret = 0) + di-usb.charger_voltage = ret; val-intval = di-usb.charger_voltage * 1000; break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: @@ -2436,7 +2447,10 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy, val-intval = di-usb.cv_active; break; case POWER_SUPPLY_PROP_CURRENT_NOW: - val-intval = ab8500_charger_get_usb_current(di) * 1000; + ret = ab8500_charger_get_usb_current(di); + if (ret = 0) + di-usb.charger_current = ret; + val-intval = di-usb.charger_current * 1000; break; case POWER_SUPPLY_PROP_CURRENT_AVG: /* -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 06/57] power: ab8500_bm: Skip first CCEOC irq for instant current
From: Johan Bjornstedt johan.bjornst...@stericsson.com When enabling the CCEOC irq we might get false interrupt from ab8500-driver due to the latched value will be saved and interpreted as an IRQ when enabled Signed-off-by: Johan Bjornstedt johan.bjornst...@stericsson.com Signed-off-by: Henrik Solver henrik.sol...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Karl KOMIEROWSKI karl.komierow...@stericsson.com --- drivers/power/ab8500_btemp.c | 11 ++ drivers/power/ab8500_fg.c| 63 + include/linux/mfd/abx500/ab8500-bm.h |6 +++ 3 files changed, 65 insertions(+), 15 deletions(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index 41a8ce4..45b10ad 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -374,13 +374,10 @@ static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di) return ret; } - /* -* Since there is no interrupt when current measurement is done, -* loop for over 250ms (250ms is one sample conversion time -* with 32.768 Khz RTC clock). Note that a stop time must be set -* since the ab8500_btemp_read_batctrl_voltage call can block and -* take an unknown amount of time to complete. -*/ + do { + msleep(20); + } while (!ab8500_fg_inst_curr_started(di-fg)); + i = 0; do { diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index c098ddd..342d118 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -159,6 +159,7 @@ struct inst_curr_result_list { * @recovery_cnt: Counter for recovery mode * @high_curr_cnt: Counter for high current mode * @init_cnt: Counter for init mode + * @nbr_cceoc_irq_cnt Counter for number of CCEOC irqs received since enabled * @recovery_needed: Indicate if recovery is needed * @high_curr_mode:Indicate if we're in high current mode * @init_capacity: Indicate if initial capacity measuring should be done @@ -166,6 +167,7 @@ struct inst_curr_result_list { * @calib_stateState during offset calibration * @discharge_state: Current discharge state * @charge_state: Current charge state + * @ab8500_fg_started Completion struct used for the instant current start * @ab8500_fg_complete Completion struct used for the instant current reading * @flags: Structure for information about events triggered * @bat_cap: Structure for battery capacity specific parameters @@ -199,6 +201,7 @@ struct ab8500_fg { int recovery_cnt; int high_curr_cnt; int init_cnt; + int nbr_cceoc_irq_cnt; bool recovery_needed; bool high_curr_mode; bool init_capacity; @@ -206,6 +209,7 @@ struct ab8500_fg { enum ab8500_fg_calibration_state calib_state; enum ab8500_fg_discharge_state discharge_state; enum ab8500_fg_charge_state charge_state; + struct completion ab8500_fg_started; struct completion ab8500_fg_complete; struct ab8500_fg_flags flags; struct ab8500_fg_battery_capacity bat_cap; @@ -525,13 +529,14 @@ cc_err: * Note: This is part one and has to be called before * ab8500_fg_inst_curr_finalize() */ - int ab8500_fg_inst_curr_start(struct ab8500_fg *di) +int ab8500_fg_inst_curr_start(struct ab8500_fg *di) { u8 reg_val; int ret; mutex_lock(di-cc_lock); + di-nbr_cceoc_irq_cnt = 0; ret = abx500_get_register_interruptible(di-dev, AB8500_RTC, AB8500_RTC_CC_CONF_REG, reg_val); if (ret 0) @@ -559,6 +564,7 @@ cc_err: } /* Return and WFI */ + INIT_COMPLETION(di-ab8500_fg_started); INIT_COMPLETION(di-ab8500_fg_complete); enable_irq(di-irq); @@ -570,6 +576,17 @@ fail: } /** + * ab8500_fg_inst_curr_started() - check if fg conversion has started + * @di: pointer to the ab8500_fg structure + * + * Returns 1 if conversion started, 0 if still waiting + */ +int ab8500_fg_inst_curr_started(struct ab8500_fg *di) +{ + return completion_done(di-ab8500_fg_started); +} + +/** * ab8500_fg_inst_curr_done() - check if fg conversion is done * @di: pointer to the ab8500_fg structure * @@ -597,13 +614,15 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) int timeout; if (!completion_done(di-ab8500_fg_complete)) { - timeout = wait_for_completion_timeout(di-ab8500_fg_complete, + timeout = wait_for_completion_timeout( + di-ab8500_fg_complete, INS_CURR_TIMEOUT); dev_dbg(di-dev, Finalize time: %d ms\n, ((INS_CURR_TIMEOUT - timeout) * 1000) / HZ); if (!timeout) { ret = -ETIME
[PATCH 00/57] power: Upgrade to ux500 battery management driver
From: Mathieu J. Poirier mathieu.poir...@linaro.org This patch set upgrades the current ux500 battery management driver to the latest HW and functionality. Pull request for convenience: The following changes since commit 56d27adcb536b7430d5f8a6240df8ad261eb00bd: Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile (2012-09-24 16:17:17 -0700) are available in the git repository at: git://git.linaro.org/people/mpoirier/linux.git ux500-battery-management Daniel WILLERUD (1): power: Add sysfs interfaces for capacity Hakan Berg (10): power: ab8500_bm: Ignore false btemp low interrupt power: Adds support for Car/Travel Adapters power: bm remove superfluous BTEMP thermal comp. power: ab8500_bm: Added support for BATT_OVV power: ab8500_fg: Adjust for RF bursts voltage drops. power: ab8500_btemp: Filter btemp readings power: charging: Allow capacity to raise from 1% power: charging: Add AB8505_USB_LINK_STATUS power: ab8500-chargalg: update battery health on safety timer exp power: abx500_chargalg: Use hrtimer Henrik Sölver (1): power: AB workaround for invalid charger Johan Bjornstedt (2): power: ab8500_bm: Charger current step-up/down power: ab8500_bm: Skip first CCEOC irq for instant current Jonas Aaberg (7): power: ab8500_btemp: Detect battery type in workqueue power: ab8500_bm: Detect removed charger power: ab8500_fg: flush sync on suspend power: ab8500_fg: usleep_range instead of short msleep power: ab8500_charger: Handle gpadc errors power: ab8500: Flush sync all works power: ab8500_charger: Do not touch VBUSOVV bits Kalle Komierowski (2): power: ab8500_bm: Don't clear the CCMuxOffset bit power: ab8500_bm: Quick re-attach charging behaviour Loic Pallardy (3): power: Add plaform data charger configurables power: charge: update watchdog for pm2xxx support power: chargealg: Realign with upstream version Marcus Cooper (8): power: Recharge condition not optimal for battery power: remove unused defines. power: Adds support for legacy USB chargers power: ab8500: ADC for battery thermistor power: ab8500: remove unecesary define flag power: ab8500_charger: Use USBLink1Status Register power: ab8500_charger: Add UsbLineCtrl2 reference power: abx500_chargalg: Fix quick re-attach charger issue. Martin Bergstrom (2): power: ab8500_fg: Report unscaled capacity power: ab8500_charger: Limit USB charger current Martin Bergström (1): power: ab8500_fg: Goto INIT_RECOVERY when charger removed Martin Sjoblom (1): power: ab8500_charger: Prevent auto drop of VBUS Mathieu J. Poirier (4): power: Harmonising platform data declaration/handling power: Cancelling status charging notification. power: ab8500: Re-alignment with internal developement. power: ab8500_fg: Moving structure definitions to header file Michel JAOUEN (2): power: ab8500: adaptation to ab version power: sysfs interface update Nicolas Guion (1): power: ab8500 - Accessing Autopower register fails Paer-Olof Haakansson (3): power: ab8500_bm: Rename the power_loss function power: Overflow in current calculation power: u8500_charger: Delay for USB enumeration Philippe Langlais (1): power: ab8500: bm: movimg back to ab8500 platform data managment Rajkumar Kasirajan (1): power: ab8500_fg: fix to use correct battery charge full design Rickard Andersson (1): power: ab8500_fg: balance IRQ enable Rikard Olsson (1): power: ab8500_fg: add power cut feature for ab8505 Rupesh Kumar (3): power: l9540: Charge only mode fixes power: ab8500: defer btemp filtering while init power: ab8500 : quick re-attach for ext charger Yang QU (1): power: add backup battery charge voltages. pender01 (1): power: ab8500_fg: Round capacity output drivers/mfd/ab8500-core.c |6 + drivers/power/Kconfig |7 - drivers/power/ab8500_btemp.c | 165 +++-- drivers/power/ab8500_charger.c| 1410 +++-- drivers/power/ab8500_fg.c | 1085 +-- drivers/power/ab8500_fg.h | 201 drivers/power/abx500_chargalg.c | 333 ++-- include/linux/mfd/abx500.h| 30 +- include/linux/mfd/abx500/ab8500-bm.h | 47 +- include/linux/mfd/abx500/ab8500.h | 22 +- include/linux/mfd/abx500/ux500_chargalg.h |8 + 11 files changed, 2607 insertions(+), 707 deletions(-) create mode 100644 drivers/power/ab8500_fg.h -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 05/57] power: ab8500_bm: Rename the power_loss function
From: Paer-Olof Haakansson par-olof.hakans...@stericsson.com Rename the ab8500_power_loss_handling function to a more describing name ab8500_enable_disable_sw_fallback Signed-off-by: Robert Marklund robert.markl...@stericsson.com Signed-off-by: Paer-Olof Haakansson par-olof.hakans...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Par-Olof HAKANSSON par-olof.hakans...@stericsson.com Reviewed-by: Karl KOMIEROWSKI karl.komierow...@stericsson.com --- drivers/power/ab8500_charger.c | 23 +++ 1 files changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 22076f5..a7d0c3a 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -268,20 +268,19 @@ static enum power_supply_property ab8500_charger_usb_props[] = { POWER_SUPPLY_PROP_CURRENT_NOW, }; -/** - * ab8500_power_loss_handling - set how we handle powerloss. - * @di:pointer to the ab8500_charger structure - * - * Magic nummbers are from STE HW department. +/* + * Function for enabling and disabling sw fallback mode + * should always be disabled when no charger is connected. */ -static void ab8500_power_loss_handling(struct ab8500_charger *di) +static void ab8500_enable_disable_sw_fallback(struct ab8500_charger *di, + bool fallback) { u8 reg; int ret; - dev_dbg(di-dev, Autopower : %d\n, di-autopower); + dev_dbg(di-dev, SW Fallback: %d\n, fallback); - /* read the autopower register */ + /* read the register containing fallback bit */ ret = abx500_get_register_interruptible(di-dev, 0x15, 0x00, reg); if (ret) { dev_err(di-dev, %d write failed\n, __LINE__); @@ -295,12 +294,12 @@ static void ab8500_power_loss_handling(struct ab8500_charger *di) return; } - if (di-autopower) + if (fallback) reg |= 0x8; else reg = ~0x8; - /* write back the changed value to autopower reg */ + /* write back the changed fallback bit value to register */ ret = abx500_set_register_interruptible(di-dev, 0x15, 0x00, reg); if (ret) { dev_err(di-dev, %d write failed\n, __LINE__); @@ -330,12 +329,12 @@ static void ab8500_power_supply_changed(struct ab8500_charger *di, !di-ac.charger_connected di-autopower) { di-autopower = false; - ab8500_power_loss_handling(di); + ab8500_enable_disable_sw_fallback(di, false); } else if (!di-autopower (di-ac.charger_connected || di-usb.charger_connected)) { di-autopower = true; - ab8500_power_loss_handling(di); + ab8500_enable_disable_sw_fallback(di, true); } } power_supply_changed(psy); -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 03/57] power: ab8500_btemp: Detect battery type in workqueue
From: Jonas Aaberg jonas.ab...@stericsson.com Detect battery type in work queue instead of probe. This reduces the system boot time with 1.5s Signed-off-by: Jonas Aaberg jonas.ab...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Karl KOMIEROWSKI karl.komierow...@stericsson.com --- drivers/power/ab8500_btemp.c | 15 +++ 1 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index bba3cca..94a3ee8 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -83,6 +83,7 @@ struct ab8500_btemp_ranges { * @btemp_ranges: Battery temperature range structure * @btemp_wq: Work queue for measuring the temperature periodically * @btemp_periodic_work: Work for measuring the temperature periodically + * @initialized: True if battery id read. */ struct ab8500_btemp { struct device *dev; @@ -100,6 +101,7 @@ struct ab8500_btemp { struct ab8500_btemp_ranges btemp_ranges; struct workqueue_struct *btemp_wq; struct delayed_work btemp_periodic_work; + bool initialized; }; /* BTEMP power supply properties */ @@ -569,6 +571,13 @@ static void ab8500_btemp_periodic_work(struct work_struct *work) struct ab8500_btemp *di = container_of(work, struct ab8500_btemp, btemp_periodic_work.work); + if (!di-initialized) { + di-initialized = true; + /* Identify the battery */ + if (ab8500_btemp_id(di) 0) + dev_warn(di-dev, failed to identify the battery\n); + } + di-bat_temp = ab8500_btemp_measure_temp(di); if (di-bat_temp != di-prev_bat_temp) { @@ -981,6 +990,8 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) di-parent = dev_get_drvdata(pdev-dev.parent); di-gpadc = ab8500_gpadc_get(ab8500-gpadc.0); + di-initialized = false; + /* get btemp specific platform data */ di-pdata = plat_data-btemp; if (!di-pdata) { @@ -1021,10 +1032,6 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) INIT_DELAYED_WORK_DEFERRABLE(di-btemp_periodic_work, ab8500_btemp_periodic_work); - /* Identify the battery */ - if (ab8500_btemp_id(di) 0) - dev_warn(di-dev, failed to identify the battery\n); - /* Set BTEMP thermal limits. Low and Med are fixed */ di-btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT; di-btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT; -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 02/57] power: ab8500_bm: Don't clear the CCMuxOffset bit
From: Kalle Komierowski karl.komierow...@stericsson.com The CCMuxOffset bit is not kept set, this will force the columb counter of the AB8500 to use the measure offset calibration. This should increase the accuracy of the fuel gauge. Signed-off-by: Kalle Komierowski karl.komierow...@stericsson.com Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_fg.c |8 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index bf02225..af792a8 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -485,8 +485,9 @@ static int ab8500_fg_coulomb_counter(struct ab8500_fg *di, bool enable) di-flags.fg_enabled = true; } else { /* Clear any pending read requests */ - ret = abx500_set_register_interruptible(di-dev, - AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG, 0); + ret = abx500_mask_and_set_register_interruptible(di-dev, + AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG, + (RESET_ACCU | READ_REQ), 0); if (ret) goto cc_err; @@ -1404,8 +1405,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) sleep_time = di-bat-fg_params-init_timer; /* Discard the first [x] seconds */ - if (di-init_cnt - di-bat-fg_params-init_discard_time) { + if (di-init_cnt di-bat-fg_params-init_discard_time) { ab8500_fg_calc_cap_discharge_voltage(di, true); ab8500_fg_check_capacity_limits(di, true); -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 00/57] power: Upgrade to ux500 battery management driver
On 12-09-26 09:38 PM, Anton Vorontsov wrote: On Tue, Sep 25, 2012 at 10:11:57AM -0600, mathieu.poir...@linaro.org wrote: From: Mathieu J. Poirier mathieu.poir...@linaro.org This patch set upgrades the current ux500 battery management driver to the latest HW and functionality. Pull request for convenience: The following changes since commit 56d27adcb536b7430d5f8a6240df8ad261eb00bd: Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile (2012-09-24 16:17:17 -0700) are available in the git repository at: git://git.linaro.org/people/mpoirier/linux.git ux500-battery-management I reviewed this series before, and all looked quite good overall. But I took another look, especially at the patches w/ empty commit messages, and there are some issues. I tried to write some descriptions myself, but I failed: some changes are not obvious to me, so I couldn't write rationale for them. :-/ Thanks, Anton. Thank you very much for the review. I am half way through your comments - some I can handle myself, for others I needed to go back to the original author for clarification. Another set will follow shortly. Your time is much appreciated, Mathieu. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] drivers/tty: Folding Android's keyreset driver in sysRQ
From: Mathieu J. Poirier mathieu.poir...@linaro.org Andrew, After requesting a number of changes that, to my understanding have been implemented, I have not been able to get the attention of the subsystem maintainer on this patch. If there are still issues, I'm open to making changes but I want to make sure it doesn't get forgotten. If there no objections, would you consider queuint it ? This patch adds keyreset functionality to the sysrq driver. It allows certain button/key combinations to be used in order to trigger device resets. The first time the key-combo is detected a work function that syncs the filesystems is scheduled and the kernel rebooted. If all the keys are released and then pressed again, it calls panic. Reboot on panic should be set for this to work. A platform device that specify a reset key-combo should be added to the board file to trigger the feature. Alternatively keys can be passed to the driver via the /sys/module/sysrq interface. This functionality comes from the keyreset driver submitted by Arve Hjønnevåg in the Android kernel. Cc: a...@android.com Cc: kernel-t...@android.com Cc: dmitry.torok...@gmail.com Cc: john.stu...@linaro.org Cc: a...@lxorguk.ukuu.org.uk Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/tty/sysrq.c | 308 + include/linux/sysrq.h |8 ++ 2 files changed, 316 insertions(+), 0 deletions(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 05728894..c44056f 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -41,14 +41,30 @@ #include linux/slab.h #include linux/input.h #include linux/uaccess.h +#include linux/platform_device.h +#include linux/syscalls.h +#include linux/atomic.h +#include linux/moduleparam.h +#include linux/mutex.h #include asm/ptrace.h #include asm/irq_regs.h +#define KEY_DOWN_MAX 20 /* how many is enough ? */ +int keyreset_param[KEY_DOWN_MAX]; +struct mutex sysrq_mutex; +static struct sysrq_state *sysrq_handle; + /* Whether we react on sysrq keys or just ignore them */ static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; static bool __read_mostly sysrq_always_enabled; +static struct input_handler sysrq_handler; + +/* Keep track of what has been called */ +static atomic_t restart_requested; + + static bool sysrq_on(void) { return sysrq_enabled || sysrq_always_enabled; @@ -570,6 +586,15 @@ struct sysrq_state { struct input_handle handle; struct work_struct reinject_work; unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; + unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long key[BITS_TO_LONGS(KEY_CNT)]; + int (*reset_fn)(void); + int key_down_target; + int key_down_ctn; + int key_up_ctn; + int keyreset_data; + int restart_disabled; unsigned int alt; unsigned int alt_use; bool active; @@ -603,6 +628,101 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work) } } + +static int sysrq_probe(struct platform_device *pdev) +{ + struct keyreset_platform_data *pdata = pdev-dev.platform_data; + + /* +* No sequence of keys to trigger on, +* assuming default sysRQ behavior. +*/ + if (pdata) { + atomic_set(restart_requested, 0); + sysrq_handler.private = pdata; + } else + sysrq_handler.private = NULL; + + /* FETCH DT INFO HERE */ + + return 0; + +} + +static void deferred_restart(struct work_struct *dummy) +{ + atomic_inc(restart_requested); + sys_sync(); + atomic_inc(restart_requested); + kernel_restart(NULL); +} +static DECLARE_WORK(restart_work, deferred_restart); + +static int do_keyreset_event(struct sysrq_state *state, +unsigned int code, int value) +{ + int ret; + int processed = 0; + + mutex_lock(sysrq_mutex); + + /* Is the code of interest to us */ + if (!test_bit(code, state-keybit)) { + mutex_unlock(sysrq_mutex); + return processed; + } + + /* No need to take care of key up events */ + if (!test_bit(code, state-key) == !value) { + mutex_unlock(sysrq_mutex); + return processed; + } + + /* Record new entry */ + __change_bit(code, state-key); + + processed = 1; + + if (test_bit(code, state-upbit)) { + if (value) { + state-restart_disabled = 1; + state-key_up_ctn++; + } else + state-key_up_ctn--; + } else { + if (value) + state-key_down_ctn++; + else + state-key_down_ctn--; + } + + if (state-key_down_ctn == 0 state-key_up_ctn == 0) + state
Re: [PATCH] drivers/tty: Folding Android's keyreset driver in sysRQ
On 12-10-05 12:16 PM, Dmitry Torokhov wrote: On Fri, Oct 05, 2012 at 11:59:29AM -0600, mathieu.poir...@linaro.org wrote: From: Mathieu J. Poirier mathieu.poir...@linaro.org Andrew, After requesting a number of changes that, to my understanding have been implemented, I have not been able to get the attention of the subsystem maintainer on this patch. If there are still issues, I'm open to making changes but I want to make sure it doesn't get forgotten. If there no objections, would you consider queuint it ? Mathieu, I have the same objection as before: using platform device solely for the purpose of passing some data from board code to the driver. Surely there are other ways of passing this bit of data... What about, for example, making it an empty weak symbol so that board code could override it with strong one? Thanks for the comments - I will implement a weak function in the keyreset driver. Mathieu. Thanks. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH] drivers/tty: Folding Android's keyreset driver in sysRQ
On 12-10-16 09:35 PM, Arve Hjønnevåg wrote: On Fri, Oct 5, 2012 at 12:48 PM, Mathieu Poirier mathieu.poir...@linaro.org wrote: On 12-10-05 12:16 PM, Dmitry Torokhov wrote: On Fri, Oct 05, 2012 at 11:59:29AM -0600, mathieu.poir...@linaro.org wrote: From: Mathieu J. Poirier mathieu.poir...@linaro.org Andrew, After requesting a number of changes that, to my understanding have been implemented, I have not been able to get the attention of the subsystem maintainer on this patch. If there are still issues, I'm open to making changes but I want to make sure it doesn't get forgotten. If there no objections, would you consider queuint it ? Mathieu, I have the same objection as before: using platform device solely for the purpose of passing some data from board code to the driver. Surely there are other ways of passing this bit of data... What about, for example, making it an empty weak symbol so that board code could override it with strong one? Thanks for the comments - I will implement a weak function in the keyreset driver. A weak symbol does not work. A single kernel can support multiple devices that have unique reset key combinations. I'm afraid Arve has a point here... His comment about supporting multiple combinations got me thinking and forced me to dive back in the code. The original keyreset driver can indeed be instantiated multiple times while the sysrq driver is a one instance model. In its current implementation the keyreset extension can only support one reset sequence. But does a system realistically need to support more than one reset sequence ? If so then I can enhance the keyreset extension of the sysrq driver but that will also mean, as stated by Arve, that we will need to keep the platform data. On the flip side it is deemed sufficient to support a single reset sequence then I'll implement the weak symbol method. The subject is up for debate, please chime in with your opinion. Mathieu. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v4] drivers/tty: Folding Android's keyreset driver in sysRQ
From: Mathieu J. Poirier mathieu.poir...@linaro.org This patch adds keyreset functionality to the sysrq driver. It allows certain button/key combinations to be used in order to trigger device resets. The first time the key-combo is detected a work function that syncs the filesystems is scheduled and the kernel rebooted. If all the keys are released and then pressed again, it calls panic. Reboot on panic should be set for this to work. Redefining the '__weak sysrq_keyreset_get_params' function is required to trigger the feature. Alternatively keys can be passed to the driver via the /sys/module/sysrq interface. This functionality comes from the keyreset driver submitted by Arve Hjønnevåg in the Android kernel. Cc: a...@android.com Cc: kernel-t...@android.com Cc: dmitry.torok...@gmail.com Cc: john.stu...@linaro.org Cc: a...@lxorguk.ukuu.org.uk Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/tty/sysrq.c | 303 + include/linux/sysrq.h |2 + 2 files changed, 305 insertions(+), 0 deletions(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 05728894..da4f538 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -41,14 +41,29 @@ #include linux/slab.h #include linux/input.h #include linux/uaccess.h +#include linux/syscalls.h +#include linux/atomic.h +#include linux/moduleparam.h +#include linux/mutex.h #include asm/ptrace.h #include asm/irq_regs.h +#define KEY_RESET_MAX 20 /* how many is enough ? */ +int keyreset_param[KEY_RESET_MAX]; +struct mutex sysrq_mutex; +static struct sysrq_state *sysrq_handle; + /* Whether we react on sysrq keys or just ignore them */ static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; static bool __read_mostly sysrq_always_enabled; +static struct input_handler sysrq_handler; + +/* Keep track of what has been called */ +static atomic_t restart_requested; + + static bool sysrq_on(void) { return sysrq_enabled || sysrq_always_enabled; @@ -570,6 +585,15 @@ struct sysrq_state { struct input_handle handle; struct work_struct reinject_work; unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; + unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long key[BITS_TO_LONGS(KEY_CNT)]; + int (*reset_fn)(void); + int key_down_target; + int key_down_ctn; + int key_up_ctn; + int keyreset_data; + int restart_disabled; unsigned int alt; unsigned int alt_use; bool active; @@ -603,6 +627,80 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work) } } +static void deferred_restart(struct work_struct *dummy) +{ + atomic_inc(restart_requested); + sys_sync(); + atomic_inc(restart_requested); + kernel_restart(NULL); +} +static DECLARE_WORK(restart_work, deferred_restart); + +static int do_keyreset_event(struct sysrq_state *state, +unsigned int code, int value) +{ + int ret; + int processed = 0; + + mutex_lock(sysrq_mutex); + + /* Is the code of interest to us */ + if (!test_bit(code, state-keybit)) { + mutex_unlock(sysrq_mutex); + return processed; + } + + /* No need to take care of key up events */ + if (!test_bit(code, state-key) == !value) { + mutex_unlock(sysrq_mutex); + return processed; + } + + /* Record new entry */ + __change_bit(code, state-key); + + processed = 1; + + if (test_bit(code, state-upbit)) { + if (value) { + state-restart_disabled = 1; + state-key_up_ctn++; + } else + state-key_up_ctn--; + } else { + if (value) + state-key_down_ctn++; + else + state-key_down_ctn--; + } + + if (state-key_down_ctn == 0 state-key_up_ctn == 0) + state-restart_disabled = 0; + + if (value !state-restart_disabled + state-key_down_ctn == state-key_down_target) { + state-restart_disabled = 1; + if (atomic_read(restart_requested)) + panic(keyboard reset failed, %d - panic\n, +atomic_read(restart_requested)); + if (state-reset_fn) { + ret = state-reset_fn(); + atomic_set(restart_requested, ret); + } else { + pr_info(keyboard reset\n); + schedule_work(restart_work); + atomic_inc(restart_requested); + } + } + + mutex_unlock(sysrq_mutex); + + /* no need to suppress keyreset characters */ + state-active = false; + + return processed
Re: Out-of-bound access in sysrq
On 13-03-28 04:34 AM, Jiri Slaby wrote: Guys, how is this supposed to work? #define SYSRQ_KEY_RESET_MAX 20 /* Should be plenty */ static unsigned short sysrq_reset_seq[SYSRQ_KEY_RESET_MAX]; ... unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED }; ... static inline void sysrq_register_handler(void) { ... for (i = 0; i ARRAY_SIZE(sysrq_reset_seq); i++) { key = platform_sysrq_reset_seq[i]; if (key == KEY_RESERVED || key KEY_MAX) ... i runs from 0 to 19 incl., but platform_sysrq_reset_seq, if not overriden, is of size 1, so? thanks, Unless I'm missing something, 'i' won't go higher than '0' since the first element of platform_sysrq_reset_seq is set to KEY_RESERVED and in such case the 'break' is executed. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v4] drivers/tty: Folding Android's keyreset driver in sysRQ
On 13-02-27 09:57 AM, Linus Torvalds wrote: On Tue, Feb 26, 2013 at 11:33 PM, Dave Airlie airl...@gmail.com wrote: It looks to me like the weak bit isn't working so well if (platform_sysrq_reset_seq) { for (i = 0; i ARRAY_SIZE(sysrq_reset_seq); i++) { key = platform_sysrq_reset_seq[i]; 6d: 66 8b 8c 00 00 00 00mov0x0(%eax,%eax,1),%cx 74: 00 is around where it craps out. gcc version 4.7.2 20121109 (Red Hat 4.7.2-8) (GCC) Fedora 18 machine. Hmm. I would love to blame gcc, but no, I think the code is crap. The whole 'platform_sysrq_reset_seq[]' thing is broken in current git, and it apparently only happens to work by mistake for most of us. Doing a grep for it shows all three uses: git grep platform_sysrq_reset_seq extern unsigned short platform_sysrq_reset_seq[] __weak; if (platform_sysrq_reset_seq) { key = platform_sysrq_reset_seq[i]; and the thing is, if it is declared as an array (not a pointer), then I think it is perfectly understandable that when then testing the *address* of that array, gcc just says you're stupid, you're testing something that cannot possibly be NULL, so I'll throw your idiotic test away. And gcc would be completely correct. That test is moronic. You just said that platform_sysrq_reset_seq[] was an external array, there is no way in hell that is NULL. Now, if it was a _pointer_, that would be a different thing entirely. A pointer can have a NULL value. A named array, not so much. So I *think* the fix might be something like the attached. Totally untested. It may compile, or it may not. Linus Your fix is compiling, running and yielding the correct results - apologies about that. Acked-by: Mathieu Poirier mathieu.poir...@linaro.org -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v3] drivers/tty: Folding Android's keyreset driver in sysRQ
From: Mathieu J. Poirier mathieu.poir...@linaro.org This patch adds keyreset functionality to the sysrq driver. It allows certain button/key combinations to be used in order to trigger device resets. The first time the key-combo is detected a work function that syncs the filesystems is scheduled and the kernel rebooted. If all the keys are released and then pressed again, it calls panic. Reboot on panic should be set for this to work. A platform device that specify a reset key-combo should be added to the board file to trigger the feature. Alternatively keys can be passed to the driver via the /sys/module/sysrq interface. This functionality comes from the keyreset driver submitted by Arve Hjønnevåg in the Android kernel. Cc: a...@android.com Cc: kernel-t...@android.com Cc: dmitry.torok...@gmail.com Cc: john.stu...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/tty/sysrq.c | 302 + include/linux/sysrq.h |8 ++ 2 files changed, 310 insertions(+), 0 deletions(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 05728894..41122a7 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -41,14 +41,30 @@ #include linux/slab.h #include linux/input.h #include linux/uaccess.h +#include linux/platform_device.h +#include linux/syscalls.h +#include linux/atomic.h +#include linux/moduleparam.h #include asm/ptrace.h #include asm/irq_regs.h +#include asm/mutex.h + +#define KEY_DOWN_MAX 20 /* how many is enough ? */ +int keyreset_param[KEY_DOWN_MAX]; +struct mutex sysrq_mutex; +static struct sysrq_state *sysrq_handle; /* Whether we react on sysrq keys or just ignore them */ static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; static bool __read_mostly sysrq_always_enabled; +static struct input_handler sysrq_handler; + +/* Keep track of what has been called */ +static atomic_t restart_requested; + + static bool sysrq_on(void) { return sysrq_enabled || sysrq_always_enabled; @@ -570,6 +586,15 @@ struct sysrq_state { struct input_handle handle; struct work_struct reinject_work; unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; + unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long key[BITS_TO_LONGS(KEY_CNT)]; + int (*reset_fn)(void); + int key_down_target; + int key_down_ctn; + int key_up_ctn; + int keyreset_data; + int restart_disabled; unsigned int alt; unsigned int alt_use; bool active; @@ -603,6 +628,101 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work) } } + +static int sysrq_probe(struct platform_device *pdev) +{ + struct keyreset_platform_data *pdata = pdev-dev.platform_data; + + /* +* No sequence of keys to trigger on, +* assuming default sysRQ behavior. +*/ + if (pdata) { + atomic_set(restart_requested, 0); + sysrq_handler.private = pdata; + } else + sysrq_handler.private = NULL; + + /* FETCH DT INFO HERE */ + + return 0; + +} + +static void deferred_restart(struct work_struct *dummy) +{ + atomic_inc(restart_requested); + sys_sync(); + atomic_inc(restart_requested); + kernel_restart(NULL); +} +static DECLARE_WORK(restart_work, deferred_restart); + +static int do_keyreset_event(struct sysrq_state *state, +unsigned int code, int value) +{ + int ret; + int processed = 0; + + mutex_lock(sysrq_mutex); + + /* Is the code of interest to us */ + if (!test_bit(code, state-keybit)) { + mutex_unlock(sysrq_mutex); + return processed; + } + + /* No need to take care of key up events */ + if (!test_bit(code, state-key) == !value) { + mutex_unlock(sysrq_mutex); + return processed; + } + + /* Record new entry */ + __change_bit(code, state-key); + + processed = 1; + + if (test_bit(code, state-upbit)) { + if (value) { + state-restart_disabled = 1; + state-key_up_ctn++; + } else + state-key_up_ctn--; + } else { + if (value) + state-key_down_ctn++; + else + state-key_down_ctn--; + } + + if (state-key_down_ctn == 0 state-key_up_ctn == 0) + state-restart_disabled = 0; + + if (value !state-restart_disabled + state-key_down_ctn == state-key_down_target) { + state-restart_disabled = 1; + if (atomic_read(restart_requested)) + panic(keyboard reset failed, %d - panic\n, +atomic_read(restart_requested
[PATCH v2] drivers/tty: Folding Android's keyreset driver in sysRQ
From: Mathieu J. Poirier mathieu.poir...@linaro.org This patch adds keyreset functionality to the sysrq driver. It allows certain button/key combinations to be used in order to trigger device resets. The first time the key-combo is detected a work function that syncs the filesystems is scheduled and the kernel rebooted. If all the keys are released and then pressed again, it calls panic. Reboot on panic should be set for this to work. A platform device that specify a reset key-combo should be added to the board file to trigger the feature. This functionality comes from the keyreset driver submitted by Arve Hjønnevåg in the Android kernel. Cc: a...@android.com Cc: kernel-t...@android.com Cc: dmitry.torok...@gmail.com Cc: john.stu...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/tty/sysrq.c | 161 + include/linux/sysrq.h |8 +++ 2 files changed, 169 insertions(+), 0 deletions(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 05728894..f210853 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -41,6 +41,9 @@ #include linux/slab.h #include linux/input.h #include linux/uaccess.h +#include linux/platform_device.h +#include linux/syscalls.h +#include linux/atomic.h #include asm/ptrace.h #include asm/irq_regs.h @@ -49,6 +52,11 @@ static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; static bool __read_mostly sysrq_always_enabled; +static struct input_handler sysrq_handler; + +/* Keep track of what has been called */ +static atomic_t restart_requested; + static bool sysrq_on(void) { return sysrq_enabled || sysrq_always_enabled; @@ -570,6 +578,15 @@ struct sysrq_state { struct input_handle handle; struct work_struct reinject_work; unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; + unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long key[BITS_TO_LONGS(KEY_CNT)]; + int (*reset_fn)(void); + int key_down_target; + int key_down_ctn; + int key_up_ctn; + int keyreset_data; + int restart_disabled; unsigned int alt; unsigned int alt_use; bool active; @@ -603,6 +620,93 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work) } } + +static int sysrq_probe(struct platform_device *pdev) +{ + struct keyreset_platform_data *pdata = pdev-dev.platform_data; + + /* +* No sequence of keys to trigger on, +* assuming default sysRQ behavior. +*/ + if (pdata) { + atomic_set(restart_requested, 0); + sysrq_handler.private = pdata; + } else + sysrq_handler.private = NULL; + + /* FETCH DT INFO HERE */ + + return 0; + +} + +static void deferred_restart(struct work_struct *dummy) +{ + atomic_inc(restart_requested); + sys_sync(); + atomic_inc(restart_requested); + kernel_restart(NULL); +} +static DECLARE_WORK(restart_work, deferred_restart); + +static int do_keyreset_event(struct sysrq_state *state, +unsigned int code, int value) +{ + int ret; + int processed = 0; + + /* Is the code is of interest to us */ + if (!test_bit(code, state-keybit)) + return processed; + + /* No need to take care of key up events */ + if (!test_bit(code, state-key) == !value) + return processed; + + /* Record new entry */ + __change_bit(code, state-key); + + processed = 1; + + if (test_bit(code, state-upbit)) { + if (value) { + state-restart_disabled = 1; + state-key_up_ctn++; + } else + state-key_up_ctn--; + } else { + if (value) + state-key_down_ctn++; + else + state-key_down_ctn--; + } + + if (state-key_down_ctn == 0 state-key_up_ctn == 0) + state-restart_disabled = 0; + + if (value !state-restart_disabled + state-key_down_ctn == state-key_down_target) { + state-restart_disabled = 1; + if (atomic_read(restart_requested)) + panic(keyboard reset failed, %d - panic\n, +atomic_read(restart_requested)); + if (state-reset_fn) { + ret = state-reset_fn(); + atomic_set(restart_requested, ret); + } else { + pr_info(keyboard reset\n); + schedule_work(restart_work); + atomic_inc(restart_requested); + } + } + + /* no need to suppress keyreset characters */ + state-active = false; + + return processed; +} + static bool
Re: [PATCH v2] drivers/tty: Folding Android's keyreset driver in sysRQ
On 12-08-30 05:01 PM, Dmitry Torokhov wrote: Hi Matthieu, On Thu, Aug 30, 2012 at 04:30:54PM -0600, mathieu.poir...@linaro.org wrote: From: Mathieu J. Poirier mathieu.poir...@linaro.org This patch adds keyreset functionality to the sysrq driver. It allows certain button/key combinations to be used in order to trigger device resets. The first time the key-combo is detected a work function that syncs the filesystems is scheduled and the kernel rebooted. If all the keys are released and then pressed again, it calls panic. Reboot on panic should be set for this to work. A platform device that specify a reset key-combo should be added to the board file to trigger the feature. Why do we need to involve a platform device and not use, for example, a module parameter, that could be set up from userspace? The platform device comes from the original design and was included to minimise the amount of changes in code that make use of the current keyreset driver. I am definitely willing to explore the possibility of adding module parameter to complement the platform data but again, to avoid impacting board code I'm in favour of keeping the platform data/device - get back to me if you disagree. Thinking back on this it may be better to call 'platform_driver_probe' rather than 'platform_driver_register'. That way one wouldn't have to instantiate a platform_device. Also, why do we need reset_fn() and not simply invoke SysRq-B handler that should call ctrl_alt_del() for us? The reset_fn() gives an implementer the chance of calling some custom function before the reset sequence is started and in my opinion should stay. On the flip side I'm not sure that I understand what you mean by SysRq-B handler - are you talking about the sysrq_reboot_op ? Please expand on that ? Thanks for the review and comments, Mathieu. Thanks. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v2] drivers/tty: Folding Android's keyreset driver in sysRQ
On 12-08-31 04:02 PM, Alan Cox wrote: Why do we need to involve a platform device and not use, for example, a module parameter, that could be set up from userspace? The platform device comes from the original design and was included to minimise the amount of changes in code that make use of the current keyreset driver. The platform device is IMHO the right answer. In this class of devices the stuff is compiled in, the userspace is Android, there are no modules and there is no reason for it to be configurable. I am definitely willing to explore the possibility of adding module parameter to complement the platform data but again, to avoid impacting board code I'm in favour of keeping the platform data/device - get back to me if you disagree. Thinking back on this it may be better to call 'platform_driver_probe' rather than 'platform_driver_register'. That way one wouldn't have to instantiate a platform_device. Also, why do we need reset_fn() and not simply invoke SysRq-B handler that should call ctrl_alt_del() for us? The reset_fn() gives an implementer the chance of calling some custom function before the reset sequence is started and in my opinion should I did not express myself clearly - with reset_fn() a system can do whatever it wants when a specific series of keys is pressed. Granted that the next steps are most likely converging toward rebooting the system - but it may not be right away and depending on the circumstances a reboot could be avoided altogether. So why wouldn't that already be using the reset notifiers ? I am not familiar with the reset notifiers that have been referred to but a little bit of research indicate that a registering subsystem gets notified when the event of interest (in this case a reboot) happens. I understand your proposition here but aren't we loosing flexibility in what we can achieve when the event has been triggered ? What do you think of adding a keyreset event that would be fired (and caught by a registering subsystem) instead of calling reset_fn() ? Thanks, Mathieu. Alan -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v2] drivers/tty: Folding Android's keyreset driver in sysRQ
On 12-08-31 04:41 PM, Dmitry Torokhov wrote: On Fri, Aug 31, 2012 at 11:02:27PM +0100, Alan Cox wrote: Why do we need to involve a platform device and not use, for example, a module parameter, that could be set up from userspace? The platform device comes from the original design and was included to minimise the amount of changes in code that make use of the current keyreset driver. The platform device is IMHO the right answer. In this class of devices the stuff is compiled in, the userspace is Android, there are no modules and there is no reason for it to be configurable. It does not matter if it is built in or not, /sys/module/XXX/parameters is still there, and while havig it in kernel is easy you could as easily stuff needed data into a sysfs attribute during booting. And we should be able to get this from DT even without the platform device (this was the next step, wasn't it?). Correct - my hope was to get the main functionality accepted before adding DT support. Do you think the lack of DT support is a blocker for acceptance ? Please confirm. Mathieu. Thanks. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v2] drivers/tty: Folding Android's keyreset driver in sysRQ
On 12-08-31 05:22 PM, Dmitry Torokhov wrote: On Fri, Aug 31, 2012 at 04:57:04PM -0600, Mathieu Poirier wrote: On 12-08-31 04:41 PM, Dmitry Torokhov wrote: On Fri, Aug 31, 2012 at 11:02:27PM +0100, Alan Cox wrote: Why do we need to involve a platform device and not use, for example, a module parameter, that could be set up from userspace? The platform device comes from the original design and was included to minimise the amount of changes in code that make use of the current keyreset driver. The platform device is IMHO the right answer. In this class of devices the stuff is compiled in, the userspace is Android, there are no modules and there is no reason for it to be configurable. It does not matter if it is built in or not, /sys/module/XXX/parameters is still there, and while havig it in kernel is easy you could as easily stuff needed data into a sysfs attribute during booting. And we should be able to get this from DT even without the platform device (this was the next step, wasn't it?). Correct - my hope was to get the main functionality accepted before adding DT support. Do you think the lack of DT support is a blocker for acceptance ? Please confirm. No, lack of DT is not a blocker, but I am unconvinced that we need platform device. Thanks, A platform device is really easy to spin-off in a board file and once it is there you don't have to worry about other loose ends to tie in before the solution is functional. I don't mind supplementing the current proposition with a module parameter interface to get the key_down and key_up sequences. Which brings us to the reset_fn() function - in my opinion it offers significant advantages and should be kept in the design. What I'm not so clear about is on the implementation. Should it be kept as part of a platform data or be implemented as a notifier as suggested by Alan. I am looking for guidance here and suggestions are encouraged. Regards, Mathieu. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] [RFC]: drivers/tty: Folding Android's keyreset driver in sysRQ
From: Mathieu J. Poirier mathieu.poir...@linaro.org This patch adds keyreset functionality to the sysrq driver. It allows certain button/key combinations to be used in order to trigger device resets. The first time the key-combo is detected a work function that syncs the filesystems is scheduled and the kernel rebooted. If all the keys are released and then pressed again, it calls panic. Reboot on panic should be set for this to work. A platform device that specify a reset key-combo should be added to the board file to trigger the feature. This functionality comes from the keyreset driver submitted by Arve Hjønnevåg in the Android kernel. It is sent out as an initial draft and comments are welcomed. In the design most of the original author's code has been added alongside the sysrq functionality, taking great care not to remove or constrain functionality people might currently be using. The keyreset platform data and driver name were kept intact to minimize disruption on products that already instantiate the keyreset driver. Cc: a...@android.com Cc: kernel-t...@android.com Cc: dmitry.torok...@gmail.com Cc: john.stu...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/tty/sysrq.c | 159 + include/linux/sysrq.h |8 +++ 2 files changed, 167 insertions(+), 0 deletions(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 05728894..c2b869d 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -41,6 +41,9 @@ #include linux/slab.h #include linux/input.h #include linux/uaccess.h +#include linux/platform_device.h +#include linux/syscalls.h +#include linux/atomic.h #include asm/ptrace.h #include asm/irq_regs.h @@ -49,6 +52,11 @@ static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; static bool __read_mostly sysrq_always_enabled; +static struct input_handler sysrq_handler; + +/* Keep track of what has been called */ +static atomic_t restart_requested; + static bool sysrq_on(void) { return sysrq_enabled || sysrq_always_enabled; @@ -570,6 +578,15 @@ struct sysrq_state { struct input_handle handle; struct work_struct reinject_work; unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; + unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long key[BITS_TO_LONGS(KEY_CNT)]; + int (*reset_fn)(void); + int key_down_target; + int key_down_ctn; + int key_up_ctn; + int keyreset_data; + int restart_disabled; unsigned int alt; unsigned int alt_use; bool active; @@ -603,6 +620,92 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work) } } + +static int sysrq_probe(struct platform_device *pdev) +{ + struct keyreset_platform_data *pdata = pdev-dev.platform_data; + + /* No sequence of keys to trigger on, +* assuming default sysRQ behavior. +*/ + if (pdata) { + atomic_set(restart_requested, 0); + sysrq_handler.private = pdata; + } else + sysrq_handler.private = NULL; + + /* FETCH DT INFO HERE */ + + return 0; + +} + +static void deferred_restart(struct work_struct *dummy) +{ + atomic_inc(restart_requested); + sys_sync(); + atomic_inc(restart_requested); + kernel_restart(NULL); +} +static DECLARE_WORK(restart_work, deferred_restart); + +static int do_keyreset_event(struct sysrq_state *state, +unsigned int code, int value) +{ + int ret; + int processed = 0; + + /* Is the code is of interestest to us */ + if (!test_bit(code, state-keybit)) + return processed; + + /* No need to take care of key up events */ + if (!test_bit(code, state-key) == !value) + return processed; + + /* Record new entry */ + __change_bit(code, state-key); + + processed = 1; + + if (test_bit(code, state-upbit)) { + if (value) { + state-restart_disabled = 1; + state-key_up_ctn++; + } else + state-key_up_ctn--; + } else { + if (value) + state-key_down_ctn++; + else + state-key_down_ctn--; + } + + if (state-key_down_ctn == 0 state-key_up_ctn == 0) + state-restart_disabled = 0; + + if (value !state-restart_disabled + state-key_down_ctn == state-key_down_target) { + state-restart_disabled = 1; + if (atomic_read(restart_requested)) + panic(KERN_ERR keyboard reset failed, %d - panic\n, +atomic_read(restart_requested)); + if (state-reset_fn) { + ret = state-reset_fn
[PATCH] drivers/tty: Folding Android's keyreset driver in sysRQ
From: Mathieu J. Poirier mathieu.poir...@linaro.org This patch adds keyreset functionality to the sysrq driver. It allows certain button/key combinations to be used in order to trigger device resets. The first time the key-combo is detected a work function that syncs the filesystems is scheduled and the kernel rebooted. If all the keys are released and then pressed again, it calls panic. Reboot on panic should be set for this to work. A platform device that specify a reset key-combo should be added to the board file to trigger the feature. This functionality comes from the keyreset driver submitted by Arve Hjønnevåg in the Android kernel. Cc: a...@android.com Cc: kernel-t...@android.com Cc: dmitry.torok...@gmail.com Cc: john.stu...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/tty/sysrq.c | 159 + include/linux/sysrq.h |8 +++ 2 files changed, 167 insertions(+), 0 deletions(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 05728894..6cf5531 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -41,6 +41,9 @@ #include linux/slab.h #include linux/input.h #include linux/uaccess.h +#include linux/platform_device.h +#include linux/syscalls.h +#include linux/atomic.h #include asm/ptrace.h #include asm/irq_regs.h @@ -49,6 +52,11 @@ static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; static bool __read_mostly sysrq_always_enabled; +static struct input_handler sysrq_handler; + +/* Keep track of what has been called */ +static atomic_t restart_requested; + static bool sysrq_on(void) { return sysrq_enabled || sysrq_always_enabled; @@ -570,6 +578,15 @@ struct sysrq_state { struct input_handle handle; struct work_struct reinject_work; unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; + unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long key[BITS_TO_LONGS(KEY_CNT)]; + int (*reset_fn)(void); + int key_down_target; + int key_down_ctn; + int key_up_ctn; + int keyreset_data; + int restart_disabled; unsigned int alt; unsigned int alt_use; bool active; @@ -603,6 +620,92 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work) } } + +static int sysrq_probe(struct platform_device *pdev) +{ + struct keyreset_platform_data *pdata = pdev-dev.platform_data; + + /* No sequence of keys to trigger on, +* assuming default sysRQ behavior. +*/ + if (pdata) { + atomic_set(restart_requested, 0); + sysrq_handler.private = pdata; + } else + sysrq_handler.private = NULL; + + /* FETCH DT INFO HERE */ + + return 0; + +} + +static void deferred_restart(struct work_struct *dummy) +{ + atomic_inc(restart_requested); + sys_sync(); + atomic_inc(restart_requested); + kernel_restart(NULL); +} +static DECLARE_WORK(restart_work, deferred_restart); + +static int do_keyreset_event(struct sysrq_state *state, +unsigned int code, int value) +{ + int ret; + int processed = 0; + + /* Is the code is of interestest to us */ + if (!test_bit(code, state-keybit)) + return processed; + + /* No need to take care of key up events */ + if (!test_bit(code, state-key) == !value) + return processed; + + /* Record new entry */ + __change_bit(code, state-key); + + processed = 1; + + if (test_bit(code, state-upbit)) { + if (value) { + state-restart_disabled = 1; + state-key_up_ctn++; + } else + state-key_up_ctn--; + } else { + if (value) + state-key_down_ctn++; + else + state-key_down_ctn--; + } + + if (state-key_down_ctn == 0 state-key_up_ctn == 0) + state-restart_disabled = 0; + + if (value !state-restart_disabled + state-key_down_ctn == state-key_down_target) { + state-restart_disabled = 1; + if (atomic_read(restart_requested)) + panic(keyboard reset failed, %d - panic\n, +atomic_read(restart_requested)); + if (state-reset_fn) { + ret = state-reset_fn(); + atomic_set(restart_requested, ret); + } else { + pr_info(keyboard reset\n); + schedule_work(restart_work); + atomic_inc(restart_requested); + } + } + + /* no need to suppress keyreset characters */ + state-active = false; + + return processed; +} + static bool
Re: [PATCH 33/57] power: u8500_charger: Delay for USB enumeration
On 12-09-27 01:42 AM, Anton Vorontsov wrote: On Tue, Sep 25, 2012 at 10:12:30AM -0600, mathieu.poir...@linaro.org wrote: From: Paer-Olof Haakansson par-olof.hakans...@stericsson.com If charging is started before USB enumeration of an Accessory Charger Adapter has finished, the AB8500 will generate a VBUS_ERROR. This in turn results in timeouts and delays the enumeration with around 15 seconds. This patch delays the charging and then ramps currents slowly to avoid VBUS errors. The delay allows the enumeration to have finished before charging is turned on. Signed-off-by: Martin Sjoblom martin.w.sjob...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- [...] @@ -264,17 +275,19 @@ struct ab8500_charger { struct ab8500_charger_info usb; struct regulator *regu; struct workqueue_struct *charger_wq; +struct mutex usb_ipt_crnt_lock; struct delayed_work check_vbat_work; struct delayed_work check_hw_failure_work; struct delayed_work check_usbchgnotok_work; struct delayed_work kick_wd_work; +struct delayed_work usb_state_changed_work; struct delayed_work attach_work; struct delayed_work ac_charger_attached_work; struct delayed_work usb_charger_attached_work; +struct delayed_work vbus_drop_end_work; struct work_struct ac_work; struct work_struct detect_usb_type_work; struct work_struct usb_link_status_work; -struct work_struct usb_state_changed_work; This just moves line around. Doesn't belong to this patch. This is moving 'usb_state_changed_work' from type 'struct work_struct' to 'struct delayed_work'. Is it that you want to see the change on the same line rather than two different lines ? struct work_struct check_main_thermal_prot_work; struct work_struct check_usb_thermal_prot_work; struct usb_phy *usb_phy; @@ -560,6 +573,7 @@ static int ab8500_charger_usb_cv(struct ab8500_charger *di) /** * ab8500_charger_detect_chargers() - Detect the connected chargers * @di: pointer to the ab8500_charger structure + * @probe: if probe, don't delay and wait for HW * * Returns the type of charger connected. * For USB it will not mean we can actually charge from it @@ -570,10 +584,10 @@ static int ab8500_charger_usb_cv(struct ab8500_charger *di) * Returns an integer value, that means, * NO_PW_CONN no power supply is connected * AC_PW_CONN if the AC power supply is connected - * USB_PW_CONN if the USB power supply is connected + * USB_PW_CONN if the USB power supply is connected Cosmetic change... doesn't belong to this patch, I guess. * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected */ -static int ab8500_charger_detect_chargers(struct ab8500_charger *di) +static int ab8500_charger_detect_chargers(struct ab8500_charger *di, bool probe) { int result = NO_PW_CONN; int ret; @@ -591,6 +605,15 @@ static int ab8500_charger_detect_chargers(struct ab8500_charger *di) result = AC_PW_CONN; /* Check for USB charger */ +if (!probe) { +/* + * AB8500 says VBUS_DET_DBNC1 VBUS_DET_DBNC100 + * when disconnecting ACA even though no + * charger was connected. Try waiting a little + * longer than the 100 ms of VBUS_DET_DBNC100... + */ +msleep(110); +} ret = abx500_get_register_interruptible(di-dev, AB8500_CHARGER, AB8500_CH_USBCH_STAT1_REG, val); if (ret 0) { @@ -598,6 +621,9 @@ static int ab8500_charger_detect_chargers(struct ab8500_charger *di) return ret; } +dev_dbg(di-dev, +%s AB8500_CH_USBCH_STAT1_REG %x\n, __func__, val); + if ((val VBUS_DET_DBNC1) (val VBUS_DET_DBNC100)) result |= USB_PW_CONN; @@ -620,33 +646,47 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, di-usb_device_is_unrecognised = false; +/* + * Platform only supports USB 2.0. + * This means that charging current from USB source + * is maximum 500 mA. Every occurence of USB_STAT_*_HOST_* + * should set USB_CH_IP_CUR_LVL_0P5. + */ + switch (link_status) { case USB_STAT_STD_HOST_NC: case USB_STAT_STD_HOST_C_NS: case USB_STAT_STD_HOST_C_S: dev_dbg(di-dev, USB Type - Standard host is ); dev_dbg(di-dev, detected through USB driver\n); -di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P09; +di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; +di-is_usb_host = true; +di-is_aca_rid = 0; break; case USB_STAT_HOST_CHG_HS_CHIRP: di-max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; -dev_dbg(di-dev, USB Type - 0x%02x MaxCurr: %d, link_status
Re: [PATCH 17/57] power: ab8500_bm: Added support for BATT_OVV
On 12-09-26 09:36 PM, Anton Vorontsov wrote: On Tue, Sep 25, 2012 at 10:12:14AM -0600, mathieu.poir...@linaro.org wrote: From: Hakan Berg hakan.b...@stericsson.com Add support for the battery over-voltage situation Signed-off-by: Hakan Berg hakan.b...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Karl KOMIEROWSKI karl.komierow...@stericsson.com --- drivers/power/ab8500_fg.c | 32 1 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index c4d9307..8507254 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -1842,24 +1842,26 @@ static void ab8500_fg_check_hw_failure_work(struct work_struct *work) * If we have had a battery over-voltage situation, * check ovv-bit to see if it should be reset. */ -if (di-flags.bat_ovv) { -ret = abx500_get_register_interruptible(di-dev, -AB8500_CHARGER, AB8500_CH_STAT_REG, -reg_value); -if (ret 0) { -dev_err(di-dev, %s ab8500 read failed\n, __func__); -return; -} -if ((reg_value BATT_OVV) != BATT_OVV) { -dev_dbg(di-dev, Battery recovered from OVV\n); -di-flags.bat_ovv = false; +ret = abx500_get_register_interruptible(di-dev, +AB8500_CHARGER, AB8500_CH_STAT_REG, +reg_value); +if (ret 0) { +dev_err(di-dev, %s ab8500 read failed\n, __func__); +return; +} +if ((reg_value BATT_OVV) == BATT_OVV) { +if (!di-flags.bat_ovv) { +dev_dbg(di-dev, Battery OVV\n); +di-flags.bat_ovv = true; power_supply_changed(di-fg_psy); -return; } - /* Not yet recovered from ovv, reschedule this test */ queue_delayed_work(di-fg_wq, di-fg_check_hw_failure_work, - round_jiffies(HZ)); +HZ); Why this change? I.e. round_jiffies(HZ) - HZ? Yes, it seems like round_jiffies(HZ) is not needed since HZ itself is a full second.. But the change itself does not belong to this patch. I agree with your point of view. How do we fix it now ? Do you think it's worth crafting a one-line patch ? +} else { +dev_dbg(di-dev, Battery recovered from OVV\n); +di-flags.bat_ovv = false; +power_supply_changed(di-fg_psy); } } @@ -2039,8 +2041,6 @@ static irqreturn_t ab8500_fg_batt_ovv_handler(int irq, void *_di) struct ab8500_fg *di = _di; dev_dbg(di-dev, Battery OVV\n); -di-flags.bat_ovv = true; -power_supply_changed(di-fg_psy); /* Schedule a new HW failure check */ queue_delayed_work(di-fg_wq, di-fg_check_hw_failure_work, 0); -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 18/57] power: Add sysfs interfaces for capacity
On 12-09-27 01:08 AM, Anton Vorontsov wrote: On Tue, Sep 25, 2012 at 10:12:15AM -0600, mathieu.poir...@linaro.org wrote: From: Daniel WILLERUD daniel.wille...@stericsson.com Switchable depending on whether capacity scaling is enabled Signed-off-by: Marcus Cooper marcus.xm.coo...@stericsson.com Signed-off-by: Daniel WILLERUD daniel.wille...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_fg.c | 57 - 1 files changed, 56 insertions(+), 1 deletions(-) diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 8507254..46010ec 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -266,7 +266,6 @@ static enum power_supply_property ab8500_fg_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_NOW, -POWER_SUPPLY_PROP_CAPACITY, [...] +static struct device_attribute ab8500_fg_sysfs_psy_attrs[] = { +__ATTR(capacity, S_IRUGO, ab8500_show_capacity, NULL), +}; I don't understand the rationale behind this patch. Why remove normal power supply property, and make your own with the same name? Something isn't right... The similarity in the naming convention it a coincidence here. In one case it's a enum and the other sysfs attribute. Could you expand on your suspicions ? -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 27/57] power: sysfs interface update
On 12-09-27 01:20 AM, Anton Vorontsov wrote: On Tue, Sep 25, 2012 at 10:12:24AM -0600, mathieu.poir...@linaro.org wrote: From: Michel JAOUEN michel.jao...@stericsson.com Add new sysfs interface to get current charge status Signed-off-by: Michel JAOUEN michel.jao...@stericsson.com Signed-off-by: Loic Pallardy loic.palla...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Olivier CLERGEAUD olivier.clerge...@stericsson.com Reviewed-by: Jonas ABERG jonas.ab...@stericsson.com --- drivers/power/ab8500_charger.c |3 +++ drivers/power/abx500_chargalg.c | 24 +++- 2 files changed, 26 insertions(+), 1 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 4129599..0a781a0 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2759,6 +2759,9 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, enum ab8500_usb_state bm_usb_state; unsigned mA = *((unsigned *)power); +if (di == NULL) +return NOTIFY_DONE; + I'd write !di. Not sure I agree with you here. If di is NULL there is nothing to work with and as such, exit. [...] +static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj, +struct attribute *attr, char *buf) +{ +struct abx500_chargalg *di = container_of(kobj, +struct abx500_chargalg, chargalg_kobject); + +if ((di-susp_status.ac_suspended == true) +(di-susp_status.usb_suspended == true)) +return sprintf(buf, 0\n); +else +return sprintf(buf, 1\n); just return sprintf(buf, %d\n, di-susp_status.ac_suspended di-susp_status.usb_suspended); Much cleaner yes. +} + /* Exposure to the sysfs interface */ /** @@ -1749,7 +1770,7 @@ static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj, static struct attribute abx500_chargalg_en_charger = \ { .name = chargalg, -.mode = S_IWUGO, +.mode = S_IRUGO | S_IWUSR, }; static struct attribute *abx500_chargalg_chg[] = { @@ -1758,6 +1779,7 @@ static struct attribute *abx500_chargalg_chg[] = { }; static const struct sysfs_ops abx500_chargalg_sysfs_ops = { +.show = abx500_chargalg_sysfs_show, .store = abx500_chargalg_sysfs_charger, }; -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 30/57] power: ab8500: Flush sync all works
On 12-09-27 01:23 AM, Anton Vorontsov wrote: On Tue, Sep 25, 2012 at 10:12:27AM -0600, mathieu.poir...@linaro.org wrote: From: Jonas Aaberg jonas.ab...@stericsson.com Flush and sync all workqueues at suspend to avoid that we suspend in the middle of a work. Signed-off-by: Jonas Aaberg jonas.ab...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com --- drivers/power/ab8500_charger.c | 11 +++ drivers/power/ab8500_fg.c |5 + 2 files changed, 16 insertions(+), 0 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index ee5ad7b..071c7c2 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2862,6 +2862,17 @@ static int ab8500_charger_suspend(struct platform_device *pdev, if (delayed_work_pending(di-check_hw_failure_work)) cancel_delayed_work(di-check_hw_failure_work); +flush_delayed_work_sync(di-attach_work); +flush_delayed_work_sync(di-usb_charger_attached_work); +flush_delayed_work_sync(di-ac_charger_attached_work); +flush_delayed_work_sync(di-check_usbchgnotok_work); +flush_delayed_work_sync(di-check_vbat_work); +flush_delayed_work_sync(di-kick_wd_work); + +flush_work_sync(di-usb_link_status_work); +flush_work_sync(di-ac_work); +flush_work_sync(di-detect_usb_type_work); I belive each of these have to be added by the patches that add the appropriate work structs. But really, it's better to avoid these many delayed work. Agreed - on the flip side they were added over multiple patches spanning many centuries. Tracking all this work down would be impossible as history was re-written many time over. What would you like to see happening here ? return 0; } #else diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index e7a0e1f..0e71e7e 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2626,6 +2626,11 @@ static int ab8500_fg_suspend(struct platform_device *pdev, struct ab8500_fg *di = platform_get_drvdata(pdev); flush_delayed_work_sync(di-fg_periodic_work); +flush_work_sync(di-fg_work); +flush_work_sync(di-fg_acc_cur_work); +flush_delayed_work_sync(di-fg_reinit_work); +flush_delayed_work_sync(di-fg_low_bat_work); +flush_delayed_work_sync(di-fg_check_hw_failure_work); /* * If the FG is enabled we will disable it before going to suspend -- 1.7.5.4 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 38/57] power: l9540: Charge only mode fixes
On 12-09-27 06:27 PM, Anton Vorontsov wrote: On Tue, Sep 25, 2012 at 10:12:35AM -0600, mathieu.poir...@linaro.org wrote: From: Rupesh Kumar rupesh.ku...@stericsson.com Fix for: charging not getting enabled in charge only mode by external charger. Subject says l9540.. what is this? Signed-off-by: Rupesh Kumar rupesh.ku...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Marcus COOPER marcus.xm.coo...@stericsson.com Reviewed-by: Michel JAOUEN michel.jao...@stericsson.com Reviewed-by: Philippe LANGLAIS philippe.langl...@stericsson.com Reviewed-by: Philippe LANGLAIS philippe.langl...@stericsson.com --- drivers/power/ab8500_charger.c| 42 + drivers/power/abx500_chargalg.c | 14 + include/linux/mfd/abx500/ux500_chargalg.h |2 + 3 files changed, 58 insertions(+), 0 deletions(-) diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 70e7c5e..ebeb068 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -15,6 +15,7 @@ #include linux/device.h #include linux/interrupt.h #include linux/delay.h +#include linux/notifier.h #include linux/slab.h #include linux/platform_device.h #include linux/power_supply.h @@ -94,6 +95,10 @@ #define AB8500_SW_CONTROL_FALLBACK 0x03 /* Wait for enumeration before charging in us */ #define WAIT_ACA_RID_ENUMERATION(5 * 1000) +/*External charger control*/ +#define AB8500_SYS_CHARGER_CONTROL_REG 0x52 +#define EXTERNAL_CHARGER_DISABLE_REG_VAL0x03 +#define EXTERNAL_CHARGER_ENABLE_REG_VAL 0x07 /* UsbLineStatus register - usb types */ enum ab8500_charger_link_status { @@ -1672,6 +1677,29 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, return ret; } +static int ab8500_external_charger_prepare(struct notifier_block *charger_nb, +unsigned long event, void *data) +{ +int ret; +struct device *dev = data; Need an empty line here. +/*Toggle External charger control pin*/ Spaces after /* and before */. +ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK, + AB8500_SYS_CHARGER_CONTROL_REG, + EXTERNAL_CHARGER_DISABLE_REG_VAL); +if (ret 0) { +dev_err(dev, write reg failed %d\n, ret); +goto out; No need for goto. +} +ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK, + AB8500_SYS_CHARGER_CONTROL_REG, + EXTERNAL_CHARGER_ENABLE_REG_VAL); +if (ret 0) +dev_err(dev, Write reg failed %d\n, ret); + +out: +return ret; +} + /** * ab8500_charger_usb_check_enable() - enable usb charging * @charger:pointer to the ux500_charger structure @@ -3201,6 +3229,10 @@ static int ab8500_charger_suspend(struct platform_device *pdev, #define ab8500_charger_resume NULL #endif +static struct notifier_block charger_nb = { +.notifier_call = ab8500_external_charger_prepare, +}; + static int __devexit ab8500_charger_remove(struct platform_device *pdev) { struct ab8500_charger *di = platform_get_drvdata(pdev); @@ -3233,6 +3265,11 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev) /* Delete the work queue */ destroy_workqueue(di-charger_wq); +/*Unregister external charger enable notifier*/ Spaces. +if (!di-ac_chg.enabled) +blocking_notifier_chain_unregister( +charger_notifier_list, charger_nb); + flush_scheduled_work(); if (di-usb_chg.enabled) power_supply_unregister(di-usb_chg.psy); @@ -3307,6 +3344,11 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) di-ac_chg.enabled = di-pdata-ac_enabled; di-ac_chg.external = false; +/*notifier for external charger enabling*/ Spaces. +if (!di-ac_chg.enabled) +blocking_notifier_chain_register( +charger_notifier_list, charger_nb); + /* USB supply */ /* power_supply base class */ di-usb_chg.psy.name = ab8500_usb; diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 9568f63..3ca00dd 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -24,6 +24,7 @@ #include linux/mfd/abx500.h #include linux/mfd/abx500/ux500_chargalg.h #include linux/mfd/abx500/ab8500-bm.h +#include linux/notifier.h /* Watchdog kick interval */ #define CHG_WD_INTERVAL (6 * HZ) @@ -255,6 +256,9 @@ static enum power_supply_property abx500_chargalg_props[] = { POWER_SUPPLY_PROP_HEALTH, }; +/*External charger prepare notifier*/ +BLOCKING_NOTIFIER_HEAD(charger_notifier_list
Re: [PATCH 52/57] power: abx500_chargalg: Use hrtimer
On 12-09-27 08:47 PM, Anton Vorontsov wrote: On Tue, Sep 25, 2012 at 10:12:49AM -0600, mathieu.poir...@linaro.org wrote: From: Hakan Berg hakan.b...@stericsson.com Timers used for charging safety and maintenance must work even when CPU is power collapsed. By using hrtimers with realtime clock, system is able to trigger an alarm that wakes the CPU up and make it possible to handle the event. Allow a little slack of 5 minutes to the hrtimers to allow CPU to be waked up in a more optimal power saving way. A 5 minute delay to time out timers on hours does not impact on safety. Signed-off-by: Hakan Berg hakan.b...@stericsson.com Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org Reviewed-by: Mian Yousaf KAUKAB mian.yousaf.kau...@stericsson.com --- drivers/power/abx500_chargalg.c | 94 ++- 1 files changed, 53 insertions(+), 41 deletions(-) diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 636d970..c8849af 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -1,5 +1,6 @@ /* * Copyright (C) ST-Ericsson SA 2012 + * Copyright (c) 2012 Sony Mobile Communications AB * * Charging algorithm driver for abx500 variants * @@ -8,11 +9,13 @@ * Johan Palsson johan.pals...@stericsson.com * Karl Komierowski karl.komierow...@stericsson.com * Arun R Murthy arun.mur...@stericsson.com + * Imre Sunyi imre.su...@sonymobile.com */ #include linux/init.h #include linux/module.h #include linux/device.h +#include linux/hrtimer.h #include linux/interrupt.h #include linux/delay.h #include linux/slab.h @@ -32,6 +35,12 @@ /* End-of-charge criteria counter */ #define EOC_COND_CNT10 +/* One hour expressed in seconds */ +#define ONE_HOUR_IN_SECONDS 3600 + +/* Five minutes expressed in seconds */ +#define FIVE_MINUTES_IN_SECONDS 300 + #define to_abx500_chargalg_device_info(x) container_of((x), \ struct abx500_chargalg, chargalg_psy); @@ -245,8 +254,8 @@ struct abx500_chargalg { struct delayed_work chargalg_periodic_work; struct delayed_work chargalg_wd_work; struct work_struct chargalg_work; -struct timer_list safety_timer; -struct timer_list maintenance_timer; +struct hrtimer safety_timer; +struct hrtimer maintenance_timer; struct kobject chargalg_kobject; }; @@ -261,38 +270,47 @@ BLOCKING_NOTIFIER_HEAD(charger_notifier_list); /** * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer - * @data: pointer to the abx500_chargalg structure + * @timer: pointer to the hrtimer structure * * This function gets called when the safety timer for the charger * expires */ -static void abx500_chargalg_safety_timer_expired(unsigned long data) +static enum hrtimer_restart +abx500_chargalg_safety_timer_expired(struct hrtimer *timer) { -struct abx500_chargalg *di = (struct abx500_chargalg *) data; +struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg, +safety_timer); Empty line here. dev_err(di-dev, Safety timer expired\n); di-events.safety_timer_expired = true; /* Trigger execution of the algorithm instantly */ queue_work(di-chargalg_wq, di-chargalg_work); + +return HRTIMER_NORESTART; } /** * abx500_chargalg_maintenance_timer_expired() - Expiration of * the maintenance timer - * @i: pointer to the abx500_chargalg structure + * @timer: pointer to the timer structure * * This function gets called when the maintenence timer * expires */ -static void abx500_chargalg_maintenance_timer_expired(unsigned long data) +static enum hrtimer_restart +abx500_chargalg_maintenance_timer_expired(struct hrtimer *timer) + { -struct abx500_chargalg *di = (struct abx500_chargalg *) data; +struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg, +maintenance_timer); dev_dbg(di-dev, Maintenance timer expired\n); di-events.maintenance_timer_expired = true; /* Trigger execution of the algorithm instantly */ queue_work(di-chargalg_wq, di-chargalg_work); + +return HRTIMER_NORESTART; } /** @@ -392,19 +410,16 @@ static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di) */ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di) { -unsigned long timer_expiration = 0; +/* Charger-dependent expiration time in hours*/ +int timer_expiration = 0; switch (di-chg_info.charger_type) { case AC_CHG: -timer_expiration = -round_jiffies(jiffies + -(di-bat-main_safety_tmr_h * 3600 * HZ)); +timer_expiration = di-bat
[RFC PATCH 08/11] coresight: adding support for beagle board
From: Panchaxari Prasannamurthy panchaxari.prasannamur...@linaro.org Added support for coresight device in dts for Beagle Board, by adding blocks of coresight, ETM, ETB blocks. Signed-off-by: Panchaxari Prasannamurthy panchaxari.prasannamur...@linaro.org --- arch/arm/boot/dts/omap3-beagle.dts | 30 ++ 1 file changed, 30 insertions(+) diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts index 5053766..0017084 100644 --- a/arch/arm/boot/dts/omap3-beagle.dts +++ b/arch/arm/boot/dts/omap3-beagle.dts @@ -80,6 +80,36 @@ }; }; + + coresight { + compatible = arm,coresight; + #address-cells = 1; + #size-cells = 1; + clocks = emu_src_ck; + ranges; + + etb: etb@54000 { + compatible = arm,coresight-etb; + reg = 0x5401b000 0x1000; + + coresight-id = 0; + coresight-name = coresight-etb; + coresight-nr-inports = 1; + coresight-default-sink; + }; + + etm@5401 { + compatible = arm,coresight-etm; + reg = 0x5401 0x1000; + + coresight-id = 1; + coresight-name = coresight-etm; + coresight-nr-inports = 0; + coresight-outports = 0; + coresight-child-list = etb; + coresight-child-ports = 0; + }; + }; }; omap3_pmx_wkup { -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[RFC PATCH 06/11] coresight: add CoreSight Replicator driver
From: Pratik Patel prat...@codeaurora.org This driver manages CoreSight Replicator that takes single input trace data stream and replicates it to produce two identical trace data output streams. Replicators are typically used to route single interleaved trace data stream to two or more sinks. Signed-off-by: Pratik Patel prat...@codeaurora.org Signed-off-by: Panchaxari Prasannamurthy panchaxari.prasannamur...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/coresight/Makefile | 2 +- drivers/coresight/coresight-replicator.c | 130 +++ 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 drivers/coresight/coresight-replicator.c diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile index 1f66804..25296a2 100644 --- a/drivers/coresight/Makefile +++ b/drivers/coresight/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_CORESIGHT) += coresight.o obj-$(CONFIG_OF) += of_coresight.o obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o \ - coresight-etb.o coresight-funnel.o + coresight-etb.o coresight-funnel.o \ diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c new file mode 100644 index 000..1cbb288 --- /dev/null +++ b/drivers/coresight/coresight-replicator.c @@ -0,0 +1,130 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include linux/kernel.h +#include linux/module.h +#include linux/init.h +#include linux/device.h +#include linux/platform_device.h +#include linux/io.h +#include linux/err.h +#include linux/slab.h +#include linux/clk.h +#include linux/of_coresight.h +#include linux/coresight.h + +#include coresight-priv.h + +struct replicator_drvdata { + struct device *dev; + struct coresight_device *csdev; +}; + +static int replicator_enable(struct coresight_device *csdev, int inport, +int outport) +{ + struct replicator_drvdata *drvdata = dev_get_drvdata(csdev-dev.parent); + dev_info(drvdata-dev, REPLICATOR enabled\n); + + return 0; +} + +static void replicator_disable(struct coresight_device *csdev, int inport, + int outport) +{ + struct replicator_drvdata *drvdata = dev_get_drvdata(csdev-dev.parent); + dev_info(drvdata-dev, REPLICATOR disabled\n); +} + +static const struct coresight_ops_link replicator_link_ops = { + .enable = replicator_enable, + .disable= replicator_disable, +}; + +static const struct coresight_ops replicator_cs_ops = { + .link_ops = replicator_link_ops, +}; + +static int replicator_probe(struct platform_device *pdev) +{ + struct device *dev = pdev-dev; + struct coresight_platform_data *pdata; + struct replicator_drvdata *drvdata; + struct coresight_desc *desc; + + if (pdev-dev.of_node) { + pdata = of_get_coresight_platform_data(dev, pdev-dev.of_node); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + pdev-dev.platform_data = pdata; + } + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + drvdata-dev = pdev-dev; + platform_set_drvdata(pdev, drvdata); + + desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); + if (!desc) + return -ENOMEM; + desc-type = CORESIGHT_DEV_TYPE_LINK; + desc-subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; + desc-ops = replicator_cs_ops; + desc-pdata = pdev-dev.platform_data; + desc-dev = pdev-dev; + desc-owner = THIS_MODULE; + drvdata-csdev = coresight_register(desc); + if (IS_ERR(drvdata-csdev)) + return PTR_ERR(drvdata-csdev); + + dev_info(dev, REPLICATOR initialized\n); + return 0; +} + +static int replicator_remove(struct platform_device *pdev) +{ + struct replicator_drvdata *drvdata = platform_get_drvdata(pdev); + + coresight_unregister(drvdata-csdev); + return 0; +} + +static struct of_device_id replicator_match[] = { + {.compatible = arm,coresight-replicator}, + {} +}; + +static struct platform_driver replicator_driver = { + .probe = replicator_probe, + .remove = replicator_remove, + .driver
[RFC PATCH 00/11] CoreSight framework and drivers
From: Mathieu Poirier mathieu.poir...@linaro.org This RFC is rescucitating the work submitted by Pratik Patel in 2012 [1]. This set is addressing comments gathered from the initial RFC and enhance the framework in a few areas. More specifically: . Sysfs entries have been moved to debugfs. . The removal of the bus concept. . Setting the size of the ETB in accordance to HW capabilities. . Adding a status entry in debugfs to better debug ETM configurations. . Adding cpu affinity for ETM/PTMs. . Tying of each IP block to a specific and configurable clock. . Adjusted the ETM/PTM power up sequence. . Adding support for beagle/beagleXM and ARM's TC2 platform. Support for other platforms will be coming shortly but we felt confident the current code base was mature enough to suscitate comments. More advanced features like CTI and STMs present in the original patchset was intentionally left out to concentrate on the foundation. They will be added at a later stage when the initial framework has been ironned-out. Regards, Mathieu [1]. http://lists.infradead.org/pipermail/linux-arm-kernel/2012-December/138028.html Mathieu Poirier (3): coresight: adding basic support for Vexpress TC2 coresight: adding support for beagleXM ARM: moving support for etb/etm to the drivers directory Panchaxari Prasannamurthy (1): coresight: adding support for beagle board Pratik Patel (7): coresight: add CoreSight core layer framework coresight: add CoreSight TMC driver coresight: add CoreSight TPIU driver coresight: add CoreSight ETB driver coresight: add CoreSight Funnel driver coresight: add CoreSight Replicator driver coresight: add CoreSight ETM driver .../devicetree/bindings/arm/coresight.txt | 138 ++ arch/arm/boot/dts/omap3-beagle-xm.dts | 30 + arch/arm/boot/dts/omap3-beagle.dts | 30 + arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 122 + arch/arm/include/asm/hardware/coresight.h | 157 -- arch/arm/include/asm/hardware/cp14.h | 540 + arch/arm/kernel/Makefile |1 - arch/arm/kernel/etm.c | 654 -- arch/arm/kernel/hw_breakpoint.c|4 +- arch/arm/mach-omap2/Kconfig|8 - arch/arm/mach-omap2/Makefile |1 - arch/arm/mach-omap2/emu.c | 50 - drivers/Kconfig|2 + drivers/Makefile |1 + drivers/coresight/Kconfig | 37 + drivers/coresight/Makefile |8 + drivers/coresight/coresight-etb.c | 586 + drivers/coresight/coresight-etm-cp14.c | 511 + drivers/coresight/coresight-etm.c | 2360 drivers/coresight/coresight-funnel.c | 310 +++ drivers/coresight/coresight-priv.h | 46 + drivers/coresight/coresight-replicator.c | 130 ++ drivers/coresight/coresight-tmc.c | 796 +++ drivers/coresight/coresight-tpiu.c | 229 ++ drivers/coresight/coresight.c | 739 ++ drivers/coresight/of_coresight.c | 124 + include/linux/coresight.h | 181 ++ include/linux/of_coresight.h | 27 + 28 files changed, 6949 insertions(+), 873 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/coresight.txt delete mode 100644 arch/arm/include/asm/hardware/coresight.h create mode 100644 arch/arm/include/asm/hardware/cp14.h delete mode 100644 arch/arm/kernel/etm.c delete mode 100644 arch/arm/mach-omap2/emu.c create mode 100644 drivers/coresight/Kconfig create mode 100644 drivers/coresight/Makefile create mode 100644 drivers/coresight/coresight-etb.c create mode 100644 drivers/coresight/coresight-etm-cp14.c create mode 100644 drivers/coresight/coresight-etm.c create mode 100644 drivers/coresight/coresight-funnel.c create mode 100644 drivers/coresight/coresight-priv.h create mode 100644 drivers/coresight/coresight-replicator.c create mode 100644 drivers/coresight/coresight-tmc.c create mode 100644 drivers/coresight/coresight-tpiu.c create mode 100644 drivers/coresight/coresight.c create mode 100644 drivers/coresight/of_coresight.c create mode 100644 include/linux/coresight.h create mode 100644 include/linux/of_coresight.h -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[RFC PATCH 10/11] coresight: adding support for beagleXM
From: Mathieu Poirier mathieu.poir...@linaro.org Currently supporting ETM and ETB. Support for TPIU and SDTI are yet to be added. Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- arch/arm/boot/dts/omap3-beagle-xm.dts | 30 ++ 1 file changed, 30 insertions(+) diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts index 447e714..b39bede 100644 --- a/arch/arm/boot/dts/omap3-beagle-xm.dts +++ b/arch/arm/boot/dts/omap3-beagle-xm.dts @@ -86,6 +86,36 @@ reset-gpios = gpio5 19 GPIO_ACTIVE_LOW; /* gpio_147 */ vcc-supply = hsusb2_power; }; + + coresight { + compatible = arm,coresight; + #address-cells = 1; + #size-cells = 1; + clocks = emu_src_ck; + ranges; + + etb: etb@54000 { + compatible = arm,coresight-etb; + reg = 0x5401b000 0x1000; + + coresight-id = 0; + coresight-name = coresight-etb; + coresight-nr-inports = 1; + coresight-default-sink; + }; + + etm@5401 { + compatible = arm,coresight-etm; + reg = 0x5401 0x1000; + + coresight-id = 1; + coresight-name = coresight-etm; + coresight-nr-inports = 0; + coresight-outports = 0; + coresight-child-list = etb; + coresight-child-ports = 0; + }; + }; }; omap3_pmx_wkup { -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[RFC PATCH 11/11] ARM: moving support for etb/etm to the drivers directory
From: Mathieu Poirier mathieu.poir...@linaro.org Removing minimal support for etb/etm to favour an implentation that is more flexible, extensible and capable of handling more platforms. Also removing the only client of the old driver. That code can easily be replaced by entries for etb/etm in the device tree. Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- arch/arm/include/asm/hardware/coresight.h | 157 --- arch/arm/kernel/Makefile | 1 - arch/arm/kernel/etm.c | 654 -- arch/arm/kernel/hw_breakpoint.c | 4 +- arch/arm/mach-omap2/Kconfig | 8 - arch/arm/mach-omap2/Makefile | 1 - arch/arm/mach-omap2/emu.c | 50 --- 7 files changed, 2 insertions(+), 873 deletions(-) delete mode 100644 arch/arm/include/asm/hardware/coresight.h delete mode 100644 arch/arm/kernel/etm.c delete mode 100644 arch/arm/mach-omap2/emu.c diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h deleted file mode 100644 index ad774f3..000 --- a/arch/arm/include/asm/hardware/coresight.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * linux/arch/arm/include/asm/hardware/coresight.h - * - * CoreSight components' registers - * - * Copyright (C) 2009 Nokia Corporation. - * Alexander Shishkin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __ASM_HARDWARE_CORESIGHT_H -#define __ASM_HARDWARE_CORESIGHT_H - -#define TRACER_ACCESSED_BIT0 -#define TRACER_RUNNING_BIT 1 -#define TRACER_CYCLE_ACC_BIT 2 -#define TRACER_ACCESSEDBIT(TRACER_ACCESSED_BIT) -#define TRACER_RUNNING BIT(TRACER_RUNNING_BIT) -#define TRACER_CYCLE_ACC BIT(TRACER_CYCLE_ACC_BIT) - -#define TRACER_TIMEOUT 1 - -#define etm_writel(t, v, x) \ - (writel_relaxed((v), (t)-etm_regs + (x))) -#define etm_readl(t, x) (readl_relaxed((t)-etm_regs + (x))) - -/* CoreSight Management Registers */ -#define CSMR_LOCKACCESS 0xfb0 -#define CSMR_LOCKSTATUS 0xfb4 -#define CSMR_AUTHSTATUS 0xfb8 -#define CSMR_DEVID 0xfc8 -#define CSMR_DEVTYPE 0xfcc -/* CoreSight Component Registers */ -#define CSCR_CLASS 0xff4 - -#define CS_LAR_KEY 0xc5acce55 - -/* ETM control register, ETM Architecture, 3.3.1 */ -#define ETMR_CTRL 0 -#define ETMCTRL_POWERDOWN 1 -#define ETMCTRL_PROGRAM(1 10) -#define ETMCTRL_PORTSEL(1 11) -#define ETMCTRL_DO_CONTEXTID (3 14) -#define ETMCTRL_PORTMASK1 (7 4) -#define ETMCTRL_PORTMASK2 (1 21) -#define ETMCTRL_PORTMASK (ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2) -#define ETMCTRL_PORTSIZE(x) x) 7) 4) | (!!((x) 8)) 21) -#define ETMCTRL_DO_CPRT(1 1) -#define ETMCTRL_DATAMASK (3 2) -#define ETMCTRL_DATA_DO_DATA (1 2) -#define ETMCTRL_DATA_DO_ADDR (1 3) -#define ETMCTRL_DATA_DO_BOTH (ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR) -#define ETMCTRL_BRANCH_OUTPUT (1 8) -#define ETMCTRL_CYCLEACCURATE (1 12) - -/* ETM configuration code register */ -#define ETMR_CONFCODE (0x04) - -/* ETM trace start/stop resource control register */ -#define ETMR_TRACESSCTRL (0x18) - -/* ETM trigger event register */ -#define ETMR_TRIGEVT (0x08) - -/* address access type register bits, ETM architecture, - * table 3-27 */ -/* - access type */ -#define ETMAAT_IFETCH 0 -#define ETMAAT_IEXEC 1 -#define ETMAAT_IEXECPASS 2 -#define ETMAAT_IEXECFAIL 3 -#define ETMAAT_DLOADSTORE 4 -#define ETMAAT_DLOAD 5 -#define ETMAAT_DSTORE 6 -/* - comparison access size */ -#define ETMAAT_JAVA(0 3) -#define ETMAAT_THUMB (1 3) -#define ETMAAT_ARM (3 3) -/* - data value comparison control */ -#define ETMAAT_NOVALCMP(0 5) -#define ETMAAT_VALMATCH(1 5) -#define ETMAAT_VALNOMATCH (3 5) -/* - exact match */ -#define ETMAAT_EXACTMATCH (1 7) -/* - context id comparator control */ -#define ETMAAT_IGNCONTEXTID(0 8) -#define ETMAAT_VALUE1 (1 8) -#define ETMAAT_VALUE2 (2 8) -#define ETMAAT_VALUE3 (3 8) -/* - security level control */ -#define ETMAAT_IGNSECURITY (0 10) -#define ETMAAT_NSONLY (1 10) -#define ETMAAT_SONLY (2 10) - -#define ETMR_COMP_VAL(x) (0x40 + (x) * 4) -#define ETMR_COMP_ACC_TYPE(x) (0x80 + (x) * 4) - -/* ETM status register, ETM Architecture, 3.3.2 */ -#define ETMR_STATUS(0x10) -#define ETMST_OVERFLOW BIT(0) -#define ETMST_PROGBIT BIT(1) -#define ETMST_STARTSTOPBIT(2) -#define ETMST_TRIGGER BIT(3) - -#define etm_progbit(t) (etm_readl((t), ETMR_STATUS) ETMST_PROGBIT) -#define etm_started(t) (etm_readl((t
[RFC PATCH 04/11] coresight: add CoreSight ETB driver
From: Pratik Patel prat...@codeaurora.org This driver manages CoreSight ETB (Embedded Trace Buffer) which acts as a circular buffer sink collecting generated trace data. Signed-off-by: Pratik Patel prat...@codeaurora.org Signed-off-by: Panchaxari Prasannamurthy panchaxari.prasannamur...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/coresight/Makefile| 3 +- drivers/coresight/coresight-etb.c | 586 ++ 2 files changed, 588 insertions(+), 1 deletion(-) create mode 100644 drivers/coresight/coresight-etb.c diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile index 540df99..8d4443b 100644 --- a/drivers/coresight/Makefile +++ b/drivers/coresight/Makefile @@ -3,4 +3,5 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o obj-$(CONFIG_OF) += of_coresight.o -obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o +obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o \ + coresight-etb.o diff --git a/drivers/coresight/coresight-etb.c b/drivers/coresight/coresight-etb.c new file mode 100644 index 000..5cb0dcb --- /dev/null +++ b/drivers/coresight/coresight-etb.c @@ -0,0 +1,586 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include linux/kernel.h +#include linux/module.h +#include linux/init.h +#include linux/types.h +#include linux/device.h +#include linux/platform_device.h +#include linux/io.h +#include linux/err.h +#include linux/fs.h +#include linux/miscdevice.h +#include linux/uaccess.h +#include linux/slab.h +#include linux/delay.h +#include linux/spinlock.h +#include linux/clk.h +#include linux/of_coresight.h +#include linux/coresight.h + +#include coresight-priv.h + +#define etb_writel(drvdata, val, off) __raw_writel((val), drvdata-base + off) +#define etb_readl(drvdata, off)__raw_readl(drvdata-base + off) + +#define ETB_LOCK(drvdata) \ +do { \ + /* wait for things to settle */ \ + mb(); \ + etb_writel(drvdata, 0x0, CORESIGHT_LAR);\ +} while (0) +#define ETB_UNLOCK(drvdata)\ +do { \ + etb_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \ + /* make sure eveyone has seen this */ \ + mb(); \ +} while (0) + +#define ETB_RAM_DEPTH_REG (0x004) +#define ETB_STATUS_REG (0x00C) +#define ETB_RAM_READ_DATA_REG (0x010) +#define ETB_RAM_READ_POINTER (0x014) +#define ETB_RAM_WRITE_POINTER (0x018) +#define ETB_TRG(0x01C) +#define ETB_CTL_REG(0x020) +#define ETB_RWD_REG(0x024) +#define ETB_FFSR (0x300) +#define ETB_FFCR (0x304) +#define ETB_ITMISCOP0 (0xEE0) +#define ETB_ITTRFLINACK(0xEE4) +#define ETB_ITTRFLIN (0xEE8) +#define ETB_ITATBDATA0 (0xEEC) +#define ETB_ITATBCTR2 (0xEF0) +#define ETB_ITATBCTR1 (0xEF4) +#define ETB_ITATBCTR0 (0xEF8) + +#define BYTES_PER_WORD 4 +#define FRAME_SIZE_WORDS 4 + +struct etb_drvdata { + void __iomem*base; + struct device *dev; + struct coresight_device *csdev; + struct miscdevice miscdev; + struct clk *clk; + spinlock_t spinlock; + boolreading; + atomic_tin_use; + uint8_t *buf; + uint32_tbuffer_depth; + boolenable; + uint32_ttrigger_cntr; +}; + +static unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata) +{ + int ret; + uint32_t depth = 0; + + ret = clk_prepare_enable(drvdata-clk); + if (ret) + return ret; + + /* RO registers don't need locking */ + depth = etb_readl(drvdata, ETB_RAM_DEPTH_REG); + + clk_disable_unprepare(drvdata-clk); + return depth; +} + +static void __etb_enable(struct etb_drvdata *drvdata) +{ + int i; + uint32_t depth; + + ETB_UNLOCK
[RFC PATCH 09/11] coresight: adding basic support for Vexpress TC2
From: Mathieu Poirier mathieu.poir...@linaro.org Support for the 2 PTMs, 3 ETMs, funnel, TPIU and replicator connected to the ETB are included. Proper handling of the ITM and the replicator linked to it along with the CTIs and SWO are not included. Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 122 + 1 file changed, 122 insertions(+) diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts index 15f98cb..18de06e 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts @@ -334,6 +334,128 @@ }; }; + coresight { + compatible = arm,coresight; + #address-cells = 1; + #size-cells = 1; + ranges = 0x2001 0 0x2001 0x1000 + 0x2003 0 0x2003 0x1000 + 0x2004 0 0x2004 0x1000 + 0x2201c000 0 0x2201c000 0x1000 + 0x2201d000 0 0x2201d000 0x1000 + 0x2203c000 0 0x2203c000 0x1000 + 0x2203d000 0 0x2203d000 0x1000 + 0x2203e000 0 0x2203e000 0x1000; + + etb: etb@2001 { + compatible = arm,coresight-etb; + reg = 0x2001 0x1000; + + coresight-id = 0; + coresight-name = coresight-etb; + coresight-nr-inports = 1; + coresight-default-sink; + }; + + etb_replicator: replicator { + compatible = arm,coresight-replicator; + + coresight-id = 1; + coresight-name = coresight-etb-replicator; + coresight-nr-inports = 1; + coresight-outports = 0 1; + coresight-child-list = etb tpiu; + coresight-child-ports = 0 0; + }; + + tpiu: tpiu@2003 { + compatible = arm,coresight-tpiu; + reg = 0x2003 0x1000; + + coresight-id = 2; + coresight-name = coresight-tpiu; + coresight-nr-inports = 1; + }; + + funnel: funnel@2004 { + compatible = arm,coresight-funnel; + reg = 0x2004 0x1000; + + coresight-id = 3; + coresight-name = coresight-funnel; + coresight-nr-inports = 1; + coresight-outports = 0; + coresight-child-list = etb_replicator; + coresight-child-ports = 0; + }; + + ptm0: ptm@2201c000 { + compatible = arm,coresight-etm; + reg = 0x2201c000 0x1000; + + coresight-id = 4; + coresight-name = coresight-ptm0; + cpu = cpu0; + coresight-nr-inports = 0; + coresight-outports = 0; + coresight-child-list = funnel; + coresight-child-ports = 0; + }; + + ptm1: ptm@2201d000 { + compatible = arm,coresight-etm; + reg = 0x2201d000 0x1000; + + coresight-id = 5; + coresight-name = coresight-ptm1; + cpu = cpu1; + coresight-nr-inports = 0; + coresight-outports = 0; + coresight-child-list = funnel; + coresight-child-ports = 1; + }; + + etm0: etm@2203c000 { + compatible = arm,coresight-etm; + reg = 0x2203c000 0x1000; + + coresight-id = 6; + coresight-name = coresight-etm0; + cpu = cpu2; + coresight-nr-inports = 0; + coresight-outports = 0; + coresight-child-list = funnel; + coresight-child-ports = 2; + }; + + etm1: etm@2203d000 { + compatible = arm,coresight-etm; + reg = 0x2203d000 0x1000; + + coresight-id = 7; + coresight-name = coresight-etm1; + cpu = cpu3; + coresight-nr-inports = 0; + coresight-outports = 0; + coresight-child-list = funnel; + coresight-child-ports = 4; + }; + + etm2: etm@2203e000
[RFC PATCH 03/11] coresight: add CoreSight TPIU driver
From: Pratik Patel prat...@codeaurora.org This driver manages CoreSight TPIU (Trace Port Interface Unit) which acts as a sink. TPIU is typically connected to some offchip hardware hosting a storage buffer. Signed-off-by: Pratik Patel prat...@codeaurora.org Signed-off-by: Panchaxari Prasannamurthy panchaxari.prasannamur...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/coresight/Makefile | 2 +- drivers/coresight/coresight-tpiu.c | 229 + 2 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 drivers/coresight/coresight-tpiu.c diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile index 16e26c5..540df99 100644 --- a/drivers/coresight/Makefile +++ b/drivers/coresight/Makefile @@ -3,4 +3,4 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o obj-$(CONFIG_OF) += of_coresight.o -obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o +obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c new file mode 100644 index 000..b552d1e --- /dev/null +++ b/drivers/coresight/coresight-tpiu.c @@ -0,0 +1,229 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include linux/kernel.h +#include linux/module.h +#include linux/init.h +#include linux/device.h +#include linux/platform_device.h +#include linux/io.h +#include linux/err.h +#include linux/slab.h +#include linux/clk.h +#include linux/of_coresight.h +#include linux/coresight.h + +#include coresight-priv.h + +#define tpiu_writel(drvdata, val, off) __raw_writel((val), drvdata-base + off) +#define tpiu_readl(drvdata, off) __raw_readl(drvdata-base + off) + +#define TPIU_LOCK(drvdata) \ +do { \ + /* wait for things to settle */ \ + mb(); \ + tpiu_writel(drvdata, 0x0, CORESIGHT_LAR); \ +} while (0) +#define TPIU_UNLOCK(drvdata) \ +do { \ + tpiu_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \ + /* make sure everyone has seen this */ \ + mb(); \ +} while (0) + +#define TPIU_SUPP_PORTSZ (0x000) +#define TPIU_CURR_PORTSZ (0x004) +#define TPIU_SUPP_TRIGMODES(0x100) +#define TPIU_TRIG_CNTRVAL (0x104) +#define TPIU_TRIG_MULT (0x108) +#define TPIU_SUPP_TESTPATM (0x200) +#define TPIU_CURR_TESTPATM (0x204) +#define TPIU_TEST_PATREPCNTR (0x208) +#define TPIU_FFSR (0x300) +#define TPIU_FFCR (0x304) +#define TPIU_FSYNC_CNTR(0x308) +#define TPIU_EXTCTL_INPORT (0x400) +#define TPIU_EXTCTL_OUTPORT(0x404) +#define TPIU_ITTRFLINACK (0xEE4) +#define TPIU_ITTRFLIN (0xEE8) +#define TPIU_ITATBDATA0(0xEEC) +#define TPIU_ITATBCTR2 (0xEF0) +#define TPIU_ITATBCTR1 (0xEF4) +#define TPIU_ITATBCTR0 (0xEF8) + +struct tpiu_drvdata { + void __iomem*base; + struct device *dev; + struct coresight_device *csdev; + struct clk *clk; +}; + +static void __tpiu_enable(struct tpiu_drvdata *drvdata) +{ + TPIU_UNLOCK(drvdata); + + /* TODO: fill this up */ + + TPIU_LOCK(drvdata); +} + +static int tpiu_enable(struct coresight_device *csdev) +{ + struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev-dev.parent); + int ret; + + ret = clk_prepare_enable(drvdata-clk); + if (ret) + return ret; + + __tpiu_enable(drvdata); + + dev_info(drvdata-dev, TPIU enabled\n); + return 0; +} + +static void __tpiu_disable(struct tpiu_drvdata *drvdata) +{ + TPIU_UNLOCK(drvdata); + + tpiu_writel(drvdata, 0x3000, TPIU_FFCR); + tpiu_writel(drvdata, 0x3040, TPIU_FFCR); + + TPIU_LOCK(drvdata); +} + +static void tpiu_disable(struct coresight_device *csdev) +{ + struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev-dev.parent); + + __tpiu_disable(drvdata); + + clk_disable_unprepare(drvdata-clk); + + dev_info(drvdata-dev, TPIU disabled\n); +} + +static void
[RFC PATCH 01/11] coresight: add CoreSight core layer framework
From: Pratik Patel prat...@codeaurora.org CoreSight components are compliant with the ARM CoreSight architecture specification and can be connected in various topologies to suite a particular SoCs tracing needs. These trace components can generally be classified as sources, links and sinks. Trace data produced by one or more sources flows through the intermediate links connecting the source to the currently selected sink. CoreSight framework provides an interface for the CoreSight trace drivers to register themselves with. It's intended to build up a topological view of the CoreSight components and configure the right series of components on user input via debugfs. For eg., when enabling a source, framework builds up a path consisting of all the components connecting the source to the currently selected sink and enables all of them. Framework also supports switching between available sinks and also provides status information to user space applications through sysfs interface. Signed-off-by: Pratik Patel prat...@codeaurora.org Signed-off-by: Panchaxari Prasannamurthy panchaxari.prasannamur...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- .../devicetree/bindings/arm/coresight.txt | 138 drivers/Kconfig| 2 + drivers/Makefile | 1 + drivers/coresight/Kconfig | 9 + drivers/coresight/Makefile | 5 + drivers/coresight/coresight-priv.h | 46 ++ drivers/coresight/coresight.c | 739 + drivers/coresight/of_coresight.c | 124 include/linux/coresight.h | 181 + include/linux/of_coresight.h | 27 + 10 files changed, 1272 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight.txt create mode 100644 drivers/coresight/Kconfig create mode 100644 drivers/coresight/Makefile create mode 100644 drivers/coresight/coresight-priv.h create mode 100644 drivers/coresight/coresight.c create mode 100644 drivers/coresight/of_coresight.c create mode 100644 include/linux/coresight.h create mode 100644 include/linux/of_coresight.h diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt new file mode 100644 index 000..3e21665 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -0,0 +1,138 @@ +* CoreSight Components + +CoreSight components are compliant with the ARM CoreSight architecture +specification and can be connected in various topologies to suite a particular +SoCs tracing needs. These trace components can generally be classified as sinks, +links and sources. Trace data produced by one or more sources flows through the +intermediate links connecting the source to the currently selected sink. Each +CoreSight component device should use these properties to describe its hardware +characteristcs. + +Required properties: + +- compatible : name of the component used for driver matching +- reg : physical base address and length of the register set(s) of the component +- coresight-id : unique integer identifier for the component +- coresight-name : unique descriptive name of the component +- coresight-nr-inports : number of input ports on the component + +coresight-outports, coresight-child-list and coresight-child-ports lists will +be of the same length and will have a one to one correspondence among the +elements at the same list index. + +coresight-default-sink must be specified for one of the sink devices that is +intended to be made the default sink. Other sink devices must not have this +specified. Not specifying this property on any of the sinks is invalid. + +Optional properties: + +- coresight-outports : list of output port numbers of this component +- coresight-child-list : list of phandles pointing to the children of this +component +- coresight-child-ports : list of input port numbers of the children +- coresight-default-sink : represents the default compile time CoreSight sink +- arm,buffer-size : size of contiguous buffer space for TMC ETR +- arm,cp14 : cp14 access to ETM registers is implemented and should be used +- clocks : the clock associated to the coresight entity. +- cpu: only valid for ETM/PTMs - the cpu this ETM/PTM is affined to. + +Example: + +1. Bus declaration: + coresight { + compatible = arm,coresight; + #address-cells = 1; + #size-cells = 1; + ranges; + ... + ... + ... +}; + +coresight { + compatible = arm,coresight; + #address-cells = 1; + #size-cells = 1; + ranges = 0x2001 0 0x2001 0x1000 + 0x2003 0 0x2003 0x1000
[RFC PATCH 05/11] coresight: add CoreSight Funnel driver
From: Pratik Patel prat...@codeaurora.org This driver manages CoreSight Funnel which acts as a link. Funnels have multiple input ports (typically 8) each of which represents an input trace data stream. These multiple input trace data streams are interleaved into a single output stream coming out of the Funnel. Signed-off-by: Pratik Patel prat...@codeaurora.org Signed-off-by: Panchaxari Prasannamurthy panchaxari.prasannamur...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/coresight/Makefile | 2 +- drivers/coresight/coresight-funnel.c | 310 +++ 2 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 drivers/coresight/coresight-funnel.c diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile index 8d4443b..1f66804 100644 --- a/drivers/coresight/Makefile +++ b/drivers/coresight/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_CORESIGHT) += coresight.o obj-$(CONFIG_OF) += of_coresight.o obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o \ - coresight-etb.o + coresight-etb.o coresight-funnel.o diff --git a/drivers/coresight/coresight-funnel.c b/drivers/coresight/coresight-funnel.c new file mode 100644 index 000..c1024df --- /dev/null +++ b/drivers/coresight/coresight-funnel.c @@ -0,0 +1,310 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include linux/kernel.h +#include linux/module.h +#include linux/init.h +#include linux/types.h +#include linux/device.h +#include linux/platform_device.h +#include linux/io.h +#include linux/err.h +#include linux/fs.h +#include linux/slab.h +#include linux/clk.h +#include linux/of_coresight.h +#include linux/coresight.h + +#include coresight-priv.h + +#define funnel_writel(drvdata, val, off) \ + __raw_writel((val), drvdata-base + off) +#define funnel_readl(drvdata, off) \ + __raw_readl(drvdata-base + off) + +#define FUNNEL_LOCK(drvdata) \ +do { \ + /* wait for things to settle */ \ + mb(); \ + funnel_writel(drvdata, 0x0, CORESIGHT_LAR); \ +} while (0) +#define FUNNEL_UNLOCK(drvdata) \ +do { \ + funnel_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);\ + /* make sure everyone has seen this */ \ + mb(); \ +} while (0) + +#define FUNNEL_FUNCTL (0x000) +#define FUNNEL_PRICTL (0x004) + +#define FUNNEL_HOLDTIME_MASK (0xF00) +#define FUNNEL_HOLDTIME_SHFT (0x8) +#define FUNNEL_HOLDTIME(0x7 FUNNEL_HOLDTIME_SHFT) + +struct funnel_drvdata { + void __iomem*base; + struct device *dev; + struct coresight_device *csdev; + struct clk *clk; + uint32_tpriority; +}; + +static void __funnel_enable(struct funnel_drvdata *drvdata, int port) +{ + uint32_t functl; + + FUNNEL_UNLOCK(drvdata); + + functl = funnel_readl(drvdata, FUNNEL_FUNCTL); + functl = ~FUNNEL_HOLDTIME_MASK; + functl |= FUNNEL_HOLDTIME; + functl |= (1 port); + funnel_writel(drvdata, functl, FUNNEL_FUNCTL); + funnel_writel(drvdata, drvdata-priority, FUNNEL_PRICTL); + + FUNNEL_LOCK(drvdata); +} + +static int funnel_enable(struct coresight_device *csdev, int inport, +int outport) +{ + struct funnel_drvdata *drvdata = dev_get_drvdata(csdev-dev.parent); + int ret; + + ret = clk_prepare_enable(drvdata-clk); + if (ret) + return ret; + + __funnel_enable(drvdata, inport); + + dev_info(drvdata-dev, FUNNEL inport %d enabled\n, inport); + return 0; +} + +static void __funnel_disable(struct funnel_drvdata *drvdata, int inport) +{ + uint32_t functl; + + FUNNEL_UNLOCK(drvdata); + + functl = funnel_readl(drvdata, FUNNEL_FUNCTL); + functl = ~(1 inport); + funnel_writel(drvdata, functl, FUNNEL_FUNCTL); + + FUNNEL_LOCK(drvdata); +} + +static void
[RFC PATCH 02/11] coresight: add CoreSight TMC driver
From: Pratik Patel prat...@codeaurora.org This driver manages CoreSight TMC (Trace Memory Controller) which can act as a link or a sink depending upon its configuration. It can present itself as an ETF (Embedded Trace FIFO) or ETR (Embedded Trace Router). ETF when configured in circular buffer mode acts as a trace collection sink. When configured in HW fifo mode it acts as link. ETR always acts as a sink and can be used to route data to memory allocated in RAM. Signed-off-by: Pratik Patel prat...@codeaurora.org Signed-off-by: Panchaxari Prasannamurthy panchaxari.prasannamur...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/coresight/Kconfig | 11 + drivers/coresight/Makefile| 1 + drivers/coresight/coresight-tmc.c | 796 ++ 3 files changed, 808 insertions(+) create mode 100644 drivers/coresight/coresight-tmc.c diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig index 88fd44a..224903b 100644 --- a/drivers/coresight/Kconfig +++ b/drivers/coresight/Kconfig @@ -7,3 +7,14 @@ menuconfig CORESIGHT the right series of components on user input via sysfs. It also provides status information to user space applications through the debugfs interface. + +if CORESIGHT + +config CORESIGHT_LINKS_AND_SINKS + bool CoreSight Link and Sink drivers + help + This enables support for CoreSight link and sink drivers that are + responsible for transporting and collecting the trace data + respectively. + +endif diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile index 218e3b5..16e26c5 100644 --- a/drivers/coresight/Makefile +++ b/drivers/coresight/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o obj-$(CONFIG_OF) += of_coresight.o +obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c new file mode 100644 index 000..afcab7c --- /dev/null +++ b/drivers/coresight/coresight-tmc.c @@ -0,0 +1,796 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include linux/kernel.h +#include linux/module.h +#include linux/init.h +#include linux/types.h +#include linux/device.h +#include linux/platform_device.h +#include linux/io.h +#include linux/err.h +#include linux/fs.h +#include linux/miscdevice.h +#include linux/uaccess.h +#include linux/slab.h +#include linux/dma-mapping.h +#include linux/delay.h +#include linux/spinlock.h +#include linux/clk.h +#include linux/of.h +#include linux/of_coresight.h +#include linux/coresight.h + +#include coresight-priv.h + +#define tmc_writel(drvdata, val, off) __raw_writel((val), drvdata-base + off) +#define tmc_readl(drvdata, off)__raw_readl(drvdata-base + off) + +#define TMC_LOCK(drvdata) \ +do { \ + /* settle everything first */ \ + mb(); \ + tmc_writel(drvdata, 0x0, CORESIGHT_LAR);\ +} while (0) +#define TMC_UNLOCK(drvdata)\ +do { \ + tmc_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \ + /* make sure everyone sees this */ \ + mb(); \ +} while (0) + +#define TMC_RSZ(0x004) +#define TMC_STS(0x00C) +#define TMC_RRD(0x010) +#define TMC_RRP(0x014) +#define TMC_RWP(0x018) +#define TMC_TRG(0x01C) +#define TMC_CTL(0x020) +#define TMC_RWD(0x024) +#define TMC_MODE (0x028) +#define TMC_LBUFLEVEL (0x02C) +#define TMC_CBUFLEVEL (0x030) +#define TMC_BUFWM (0x034) +#define TMC_RRPHI (0x038) +#define TMC_RWPHI (0x03C) +#define TMC_AXICTL (0x110) +#define TMC_DBALO (0x118) +#define TMC_DBAHI (0x11C) +#define TMC_FFSR (0x300) +#define TMC_FFCR (0x304) +#define TMC_PSCR (0x308) +#define TMC_ITMISCOP0 (0xEE0
Re: [RFC PATCH 04/11] coresight: add CoreSight ETB driver
On 30 May 2014 07:53, Russell King - ARM Linux li...@arm.linux.org.uk wrote: NAK for all the reasons I mentioned in the previous submission in 2012. You partially did the right thing - you read through the previous submission, and you said in your cover message that you had addressed some of the comments from that submission. What I find extremely distasteful is that you seem to have chosen to completely ignore my comments - you haven't mentioned them in your covering message at all, and you've just gone ahead and converted ETM and ETB to be platform devices. That gets you a NAK for that change, because you have done nothing what so ever to address the concerns I raised. From my initial reading of your assessment it wasn't clear to me that your opinion leaned toward registering with the AMBA bus. Now that this point has been clarified I will go back to the AMBA interface for my next submission. Is there anything else not AMBA releated that you'd like to see modified? Thanks, Mathieu Since you seem to have ignored my comments, this is as far as I'm looking at your submission, and you can consider the entire submission NAK'd by me. Thanks. -- FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly improving, and getting towards what was expected from it. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC PATCH 01/11] coresight: add CoreSight core layer framework
On 30 May 2014 11:25, Rob Herring robherri...@gmail.com wrote: On Fri, May 30, 2014 at 8:43 AM, mathieu.poir...@linaro.org wrote: From: Pratik Patel prat...@codeaurora.org CoreSight components are compliant with the ARM CoreSight architecture specification and can be connected in various topologies to suite a particular SoCs tracing needs. These trace components can generally be classified as sources, links and sinks. Trace data produced by one or more sources flows through the intermediate links connecting the source to the currently selected sink. CoreSight framework provides an interface for the CoreSight trace drivers to register themselves with. It's intended to build up a topological view of the CoreSight components and configure the right series of components on user input via debugfs. For eg., when enabling a source, framework builds up a path consisting of all the components connecting the source to the currently selected sink and enables all of them. Framework also supports switching between available sinks and also provides status information to user space applications through sysfs interface. Signed-off-by: Pratik Patel prat...@codeaurora.org Signed-off-by: Panchaxari Prasannamurthy panchaxari.prasannamur...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- .../devicetree/bindings/arm/coresight.txt | 138 drivers/Kconfig| 2 + drivers/Makefile | 1 + drivers/coresight/Kconfig | 9 + drivers/coresight/Makefile | 5 + drivers/coresight/coresight-priv.h | 46 ++ drivers/coresight/coresight.c | 739 + drivers/coresight/of_coresight.c | 124 include/linux/coresight.h | 181 + include/linux/of_coresight.h | 27 + 10 files changed, 1272 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight.txt create mode 100644 drivers/coresight/Kconfig create mode 100644 drivers/coresight/Makefile create mode 100644 drivers/coresight/coresight-priv.h create mode 100644 drivers/coresight/coresight.c create mode 100644 drivers/coresight/of_coresight.c create mode 100644 include/linux/coresight.h create mode 100644 include/linux/of_coresight.h diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt new file mode 100644 index 000..3e21665 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -0,0 +1,138 @@ +* CoreSight Components + +CoreSight components are compliant with the ARM CoreSight architecture +specification and can be connected in various topologies to suite a particular +SoCs tracing needs. These trace components can generally be classified as sinks, +links and sources. Trace data produced by one or more sources flows through the +intermediate links connecting the source to the currently selected sink. Each +CoreSight component device should use these properties to describe its hardware +characteristcs. + +Required properties: + +- compatible : name of the component used for driver matching Where are the specific strings for components? Coresight is made of multiple components with each component needing a different driver. +- reg : physical base address and length of the register set(s) of the component +- coresight-id : unique integer identifier for the component compatible + reg is a unique id. Some coresight IP blocks like the replicator don't have a reg property - the coresight-id and coresight-name are the only way to identify them properly. +- coresight-name : unique descriptive name of the component compatible is a descriptive name. That is what ends up under /sys/kernel/debug/coresight/. Since there can be multiple entity of the same type it is easier and more convivial for users. For instance: coresight-etb-replicator and coresight-tpiu-replicator are easier to identify than coresight-replicator0 and coresight-replicator1. We need to keep coresight-id or coresight-name - I prefer the former. What is your take on this? +- coresight-nr-inports : number of input ports on the component + +coresight-outports, coresight-child-list and coresight-child-ports lists will +be of the same length and will have a one to one correspondence among the +elements at the same list index. + +coresight-default-sink must be specified for one of the sink devices that is +intended to be made the default sink. Other sink devices must not have this +specified. Not specifying this property on any of the sinks is invalid. Why do you need the default-sink in DT? Isn't the configuration going to depend on the user? Users can change this at will via debugfs. It's a default boot time configuration
Re: [RFC PATCH 02/11] coresight: add CoreSight TMC driver
Thanks for the review - please see comments in-lined. Mathieu On 3 June 2014 03:09, Linus Walleij linus.wall...@linaro.org wrote: On Fri, May 30, 2014 at 3:43 PM, mathieu.poir...@linaro.org wrote: +#define tmc_writel(drvdata, val, off) __raw_writel((val), drvdata-base + off) +#define tmc_readl(drvdata, off)__raw_readl(drvdata-base + off) Why not writel_relaxed()/readl_relaxed()? Done. Using __raw* accessors seem a bit thick. (Applies to all such defines.) +#define TMC_LOCK(drvdata) \ +do { \ + /* settle everything first */ \ + mb(); \ + tmc_writel(drvdata, 0x0, CORESIGHT_LAR);\ +} while (0) +#define TMC_UNLOCK(drvdata)\ +do { \ + tmc_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \ + /* make sure everyone sees this */ \ + mb(); \ +} while (0) Convert these to static inlines. No need for them to be #defines at all really. Done. +#define BYTES_PER_WORD 4 But please. Just using the number 4 everywhere is clear enough. +struct tmc_drvdata { + void __iomem*base; + struct device *dev; + struct coresight_device *csdev; + struct miscdevice miscdev; + struct clk *clk; + spinlock_t spinlock; + int read_count; Can this really be negative? It is useful for debugging, as an example see tmc_release(). If the count drops below '0' there is obviously a problem. Do you see a cost in keeping this as an 'int'? What do you advise here? + boolreading; + char*buf; + dma_addr_t paddr; + void __iomem*vaddr; + uint32_tsize; Use u32 + boolenable; + enum tmc_config_typeconfig_type; + uint32_ttrigger_cntr; Use u32 +}; This struct overall could use some kerneldoc. Would writing a comment for each field qualify? +static void tmc_flush_and_stop(struct tmc_drvdata *drvdata) +{ + int count; Why not call this variable i as per convention. + uint32_t ffcr; u32 + + ffcr = tmc_readl(drvdata, TMC_FFCR); + ffcr |= BIT(12); + tmc_writel(drvdata, ffcr, TMC_FFCR); + ffcr |= BIT(6); A bit unclear what bit 12 and 6 does. Either #define them or add comments. + tmc_writel(drvdata, ffcr, TMC_FFCR); + /* Ensure flush completes */ + for (count = TIMEOUT_US; BVAL(tmc_readl(drvdata, TMC_FFCR), 6) != 0 +count 0; count--) + udelay(1); + WARN(count == 0, timeout while flushing TMC, TMC_FFCR: %#x\n, +tmc_readl(drvdata, TMC_FFCR)); + + tmc_wait_for_ready(drvdata); +} + +static void __tmc_enable(struct tmc_drvdata *drvdata) +{ + tmc_writel(drvdata, 0x1, TMC_CTL); +} + +static void __tmc_disable(struct tmc_drvdata *drvdata) +{ + tmc_writel(drvdata, 0x0, TMC_CTL); +} I actually understand what bit 0 does in this register, but could also be #defined. +static void __tmc_etb_enable(struct tmc_drvdata *drvdata) +{ + /* Zero out the memory to help with debug */ + memset(drvdata-buf, 0, drvdata-size); + + TMC_UNLOCK(drvdata); + + tmc_writel(drvdata, TMC_MODE_CIRCULAR_BUFFER, TMC_MODE); + tmc_writel(drvdata, 0x133, TMC_FFCR); 0x133? Que ce que c'est? + tmc_writel(drvdata, drvdata-trigger_cntr, TMC_TRG); + __tmc_enable(drvdata); + + TMC_LOCK(drvdata); +} + +static void __tmc_etr_enable(struct tmc_drvdata *drvdata) +{ + uint32_t axictl; u32 + /* Zero out the memory to help with debug */ + memset(drvdata-vaddr, 0, drvdata-size); + + TMC_UNLOCK(drvdata); + + tmc_writel(drvdata, drvdata-size / BYTES_PER_WORD, TMC_RSZ); + tmc_writel(drvdata, TMC_MODE_CIRCULAR_BUFFER, TMC_MODE); + + axictl = tmc_readl(drvdata, TMC_AXICTL); + axictl |= (0xF 8); + tmc_writel(drvdata, axictl, TMC_AXICTL); + axictl = ~(0x1 7); + tmc_writel(drvdata, axictl, TMC_AXICTL); + axictl = (axictl ~0x3) | 0x2; + tmc_writel(drvdata, axictl, TMC_AXICTL); I don't understand these bits and shifts either. + tmc_writel(drvdata, drvdata-paddr, TMC_DBALO); + tmc_writel(drvdata, 0x0, TMC_DBAHI); + tmc_writel(drvdata, 0x133, TMC_FFCR); More magic... + tmc_writel(drvdata, drvdata-trigger_cntr,
[PATCH 9/9 v2] ARM: removing support for etb/etm in arch/arm/kernel/
From: Mathieu Poirier mathieu.poir...@linaro.org Removing minimal support for etb/etm to favour an implentation that is more flexible, extensible and capable of handling more platforms. Also removing the only client of the old driver. That code can easily be replaced by entries for etb/etm in the device tree. Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- arch/arm/include/asm/hardware/coresight.h | 157 --- arch/arm/kernel/Makefile | 1 - arch/arm/kernel/etm.c | 654 -- arch/arm/kernel/hw_breakpoint.c | 4 +- arch/arm/mach-omap2/Kconfig | 8 - arch/arm/mach-omap2/Makefile | 1 - arch/arm/mach-omap2/emu.c | 50 --- 7 files changed, 2 insertions(+), 873 deletions(-) delete mode 100644 arch/arm/include/asm/hardware/coresight.h delete mode 100644 arch/arm/kernel/etm.c delete mode 100644 arch/arm/mach-omap2/emu.c diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h deleted file mode 100644 index ad774f3..000 --- a/arch/arm/include/asm/hardware/coresight.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * linux/arch/arm/include/asm/hardware/coresight.h - * - * CoreSight components' registers - * - * Copyright (C) 2009 Nokia Corporation. - * Alexander Shishkin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __ASM_HARDWARE_CORESIGHT_H -#define __ASM_HARDWARE_CORESIGHT_H - -#define TRACER_ACCESSED_BIT0 -#define TRACER_RUNNING_BIT 1 -#define TRACER_CYCLE_ACC_BIT 2 -#define TRACER_ACCESSEDBIT(TRACER_ACCESSED_BIT) -#define TRACER_RUNNING BIT(TRACER_RUNNING_BIT) -#define TRACER_CYCLE_ACC BIT(TRACER_CYCLE_ACC_BIT) - -#define TRACER_TIMEOUT 1 - -#define etm_writel(t, v, x) \ - (writel_relaxed((v), (t)-etm_regs + (x))) -#define etm_readl(t, x) (readl_relaxed((t)-etm_regs + (x))) - -/* CoreSight Management Registers */ -#define CSMR_LOCKACCESS 0xfb0 -#define CSMR_LOCKSTATUS 0xfb4 -#define CSMR_AUTHSTATUS 0xfb8 -#define CSMR_DEVID 0xfc8 -#define CSMR_DEVTYPE 0xfcc -/* CoreSight Component Registers */ -#define CSCR_CLASS 0xff4 - -#define CS_LAR_KEY 0xc5acce55 - -/* ETM control register, ETM Architecture, 3.3.1 */ -#define ETMR_CTRL 0 -#define ETMCTRL_POWERDOWN 1 -#define ETMCTRL_PROGRAM(1 10) -#define ETMCTRL_PORTSEL(1 11) -#define ETMCTRL_DO_CONTEXTID (3 14) -#define ETMCTRL_PORTMASK1 (7 4) -#define ETMCTRL_PORTMASK2 (1 21) -#define ETMCTRL_PORTMASK (ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2) -#define ETMCTRL_PORTSIZE(x) x) 7) 4) | (!!((x) 8)) 21) -#define ETMCTRL_DO_CPRT(1 1) -#define ETMCTRL_DATAMASK (3 2) -#define ETMCTRL_DATA_DO_DATA (1 2) -#define ETMCTRL_DATA_DO_ADDR (1 3) -#define ETMCTRL_DATA_DO_BOTH (ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR) -#define ETMCTRL_BRANCH_OUTPUT (1 8) -#define ETMCTRL_CYCLEACCURATE (1 12) - -/* ETM configuration code register */ -#define ETMR_CONFCODE (0x04) - -/* ETM trace start/stop resource control register */ -#define ETMR_TRACESSCTRL (0x18) - -/* ETM trigger event register */ -#define ETMR_TRIGEVT (0x08) - -/* address access type register bits, ETM architecture, - * table 3-27 */ -/* - access type */ -#define ETMAAT_IFETCH 0 -#define ETMAAT_IEXEC 1 -#define ETMAAT_IEXECPASS 2 -#define ETMAAT_IEXECFAIL 3 -#define ETMAAT_DLOADSTORE 4 -#define ETMAAT_DLOAD 5 -#define ETMAAT_DSTORE 6 -/* - comparison access size */ -#define ETMAAT_JAVA(0 3) -#define ETMAAT_THUMB (1 3) -#define ETMAAT_ARM (3 3) -/* - data value comparison control */ -#define ETMAAT_NOVALCMP(0 5) -#define ETMAAT_VALMATCH(1 5) -#define ETMAAT_VALNOMATCH (3 5) -/* - exact match */ -#define ETMAAT_EXACTMATCH (1 7) -/* - context id comparator control */ -#define ETMAAT_IGNCONTEXTID(0 8) -#define ETMAAT_VALUE1 (1 8) -#define ETMAAT_VALUE2 (2 8) -#define ETMAAT_VALUE3 (3 8) -/* - security level control */ -#define ETMAAT_IGNSECURITY (0 10) -#define ETMAAT_NSONLY (1 10) -#define ETMAAT_SONLY (2 10) - -#define ETMR_COMP_VAL(x) (0x40 + (x) * 4) -#define ETMR_COMP_ACC_TYPE(x) (0x80 + (x) * 4) - -/* ETM status register, ETM Architecture, 3.3.2 */ -#define ETMR_STATUS(0x10) -#define ETMST_OVERFLOW BIT(0) -#define ETMST_PROGBIT BIT(1) -#define ETMST_STARTSTOPBIT(2) -#define ETMST_TRIGGER BIT(3) - -#define etm_progbit(t) (etm_readl((t), ETMR_STATUS) ETMST_PROGBIT) -#define etm_started(t) (etm_readl((t
[PATCH 7/9 v2] coresight: adding support for beagle and beagleXM
From: Mathieu Poirier mathieu.poir...@linaro.org Currently supporting ETM and ETB. Support for TPIU and SDTI are yet to be added. Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- arch/arm/boot/dts/omap3-beagle-xm.dts | 28 arch/arm/boot/dts/omap3-beagle.dts| 28 2 files changed, 56 insertions(+) diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts index cf0be66..110ac3e 100644 --- a/arch/arm/boot/dts/omap3-beagle-xm.dts +++ b/arch/arm/boot/dts/omap3-beagle-xm.dts @@ -145,6 +145,34 @@ }; }; }; + + etb: etb@5401b000 { + compatible = arm,coresight-etb, arm,primecell; + reg = 0x5401b000 0x1000; + + coresight-default-sink; + clocks = emu_src_ck; + clock-names = apb_pclk; + port { + etb_in: endpoint { + slave-mode; + remote-endpoint = etm_out; + }; + }; + }; + + etm@5401 { + compatible = arm,coresight-etm, arm,primecell; + reg = 0x5401 0x1000; + + clocks = emu_src_ck; + clock-names = apb_pclk; + port { + etm_out: endpoint { + remote-endpoint = etb_in; + }; + }; + }; }; omap3_pmx_wkup { diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts index 3c3e6da..dfd9a92 100644 --- a/arch/arm/boot/dts/omap3-beagle.dts +++ b/arch/arm/boot/dts/omap3-beagle.dts @@ -140,6 +140,34 @@ }; }; }; + + etb: etb@54000 { + compatible = arm,coresight-etb, arm,primecell; + reg = 0x5401b000 0x1000; + + coresight-default-sink; + clocks = emu_src_ck; + clock-names = apb_pclk; + port { + etb_in: endpoint { + slave-mode; + remote-endpoint = etm_out; + }; + }; + }; + + etm@5401 { + compatible = arm,coresight-etm, arm,primecell; + reg = 0x5401 0x1000; + + clocks = emu_src_ck; + clock-names = apb_pclk; + port { + etm_out: endpoint { + remote-endpoint = etb_in; + }; + }; + }; }; omap3_pmx_wkup { -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/9 v2] coresight-tmc: add CoreSight TMC driver
From: Pratik Patel prat...@codeaurora.org This driver manages CoreSight TMC (Trace Memory Controller) which can act as a link or a sink depending upon its configuration. It can present itself as an ETF (Embedded Trace FIFO) or ETR (Embedded Trace Router). ETF when configured in circular buffer mode acts as a trace collection sink. When configured in HW fifo mode it acts as link. ETR always acts as a sink and can be used to route data to memory allocated in RAM. Signed-off-by: Pratik Patel prat...@codeaurora.org Signed-off-by: Panchaxari Prasannamurthy panchaxari.prasannamur...@linaro.org Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- drivers/coresight/Kconfig | 10 + drivers/coresight/Makefile| 1 + drivers/coresight/coresight-tmc.c | 791 ++ 3 files changed, 802 insertions(+) create mode 100644 drivers/coresight/coresight-tmc.c diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig index fdd4d08..48a78bb 100644 --- a/drivers/coresight/Kconfig +++ b/drivers/coresight/Kconfig @@ -8,3 +8,13 @@ menuconfig CORESIGHT the right series of components on user input via sysfs. It also provides status information to user space applications through the debugfs interface. + +if CORESIGHT + +config CORESIGHT_LINKS_AND_SINKS + bool CoreSight Link and Sink drivers + help + This enables support for CoreSight link and sink drivers that are + responsible for transporting and collecting the trace data + respectively. +endif diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile index 218e3b5..16e26c5 100644 --- a/drivers/coresight/Makefile +++ b/drivers/coresight/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o obj-$(CONFIG_OF) += of_coresight.o +obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c new file mode 100644 index 000..201cdac --- /dev/null +++ b/drivers/coresight/coresight-tmc.c @@ -0,0 +1,791 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include linux/kernel.h +#include linux/module.h +#include linux/init.h +#include linux/types.h +#include linux/device.h +#include linux/io.h +#include linux/err.h +#include linux/fs.h +#include linux/miscdevice.h +#include linux/uaccess.h +#include linux/slab.h +#include linux/dma-mapping.h +#include linux/delay.h +#include linux/spinlock.h +#include linux/clk.h +#include linux/of.h +#include linux/of_coresight.h +#include linux/coresight.h +#include linux/amba/bus.h + +#include coresight-priv.h + +#define TMC_RSZ(0x004) +#define TMC_STS(0x00C) +#define TMC_RRD(0x010) +#define TMC_RRP(0x014) +#define TMC_RWP(0x018) +#define TMC_TRG(0x01C) +#define TMC_CTL(0x020) +#define TMC_RWD(0x024) +#define TMC_MODE (0x028) +#define TMC_LBUFLEVEL (0x02C) +#define TMC_CBUFLEVEL (0x030) +#define TMC_BUFWM (0x034) +#define TMC_RRPHI (0x038) +#define TMC_RWPHI (0x03C) +#define TMC_AXICTL (0x110) +#define TMC_DBALO (0x118) +#define TMC_DBAHI (0x11C) +#define TMC_FFSR (0x300) +#define TMC_FFCR (0x304) +#define TMC_PSCR (0x308) +#define TMC_ITMISCOP0 (0xEE0) +#define TMC_ITTRFLIN (0xEE8) +#define TMC_ITATBDATA0 (0xEEC) +#define TMC_ITATBCTR2 (0xEF0) +#define TMC_ITATBCTR1 (0xEF4) +#define TMC_ITATBCTR0 (0xEF8) + +/** register description **/ +/* TMC_CTL - 0x020 */ +#define TMC_CTL_CAPT_ENBIT(0) +/* TMC_STS - 0x00C */ +#define TMC_STS_TRIGGERED BIT(1) +/* TMC_AXICTL - 0x110 */ +#define TMC_AXICTL_PROT_CTL_B0 BIT(0) +#define TMC_AXICTL_PROT_CTL_B1 BIT(1) +#define TMC_AXICTL_SCT_GAT_MODEBIT(7) +#define TMC_AXICTL_WR_BURST_LEN 0xF00 +/* TMC_FFCR - 0x304 */ +#define TMC_FFCR_EN_FMTBIT(0) +#define TMC_FFCR_EN_TI BIT(1) +#define TMC_FFCR_FON_FLIN BIT(4) +#define TMC_FFCR_FON_TRIG_EVT BIT(5) +#define TMC_FFCR_FLUSHMAN BIT(6) +#define TMC_FFCR_TRIGON_TRIGIN BIT(8) +#define TMC_FFCR_STOP_ON_FLUSH BIT(12) + +#define TMC_STS_TRIGGERED_BIT 2 +#define TMC_FFCR_FLUSHMAN_BIT 6 + +enum
[PATCH 0/9 v2] Coresight framework and drivers
From: Mathieu Poirier mathieu.poir...@linaro.org This set is addressing comments received after the May 30th submission[1]. More specifically: .All drivers have been converted to use the AMBA bus interface. .Debugfs entries are now created with a macro. .A header file was created for the ETM driver to allow for the reuse of constant definition. .Error path on some drivers have been corrected. .All types converted from uintX_t to uX. .All numeric constant have been replaced with #defines and comments added where necessary. .Removal of coresight-id and coresigh-name DT bindings. .Move all DT connections specification to use the generic graph bindings. .The removal of the replicator driver since it doesn't show on the AMBA bus. Drivers for enhanced replicators that have a configuration space can be added when the need arises. Regards, Mathieu [1]. http://thread.gmane.org/gmane.linux.kernel/1714785 Mathieu Poirier (3): coresight: adding support for beagle and beagleXM coresight: adding basic support for Vexpress TC2 ARM: removing support for etb/etm in arch/arm/kernel/ Pratik Patel (6): coresight: add CoreSight core layer framework coresight-tmc: add CoreSight TMC driver coresight-tpiu: add CoreSight TPIU driver coresight-etb: add CoreSight ETB driver coresight-funnel: add CoreSight Funnel driver coresight-etm: add CoreSight ETM/PTM driver .../devicetree/bindings/arm/coresight.txt | 141 ++ arch/arm/boot/dts/omap3-beagle-xm.dts | 28 + arch/arm/boot/dts/omap3-beagle.dts | 28 + arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 174 +++ arch/arm/include/asm/hardware/coresight.h | 157 -- arch/arm/include/asm/hardware/cp14.h | 540 +++ arch/arm/kernel/Makefile |1 - arch/arm/kernel/etm.c | 654 - arch/arm/kernel/hw_breakpoint.c|4 +- arch/arm/mach-omap2/Kconfig|8 - arch/arm/mach-omap2/Makefile |1 - arch/arm/mach-omap2/emu.c | 50 - drivers/Kconfig|2 + drivers/Makefile |1 + drivers/amba/bus.c |2 +- drivers/coresight/Kconfig | 39 + drivers/coresight/Makefile |8 + drivers/coresight/coresight-etb.c | 557 drivers/coresight/coresight-etm-cp14.c | 506 +++ drivers/coresight/coresight-etm.c | 1507 drivers/coresight/coresight-etm.h | 192 +++ drivers/coresight/coresight-funnel.c | 252 drivers/coresight/coresight-priv.h | 69 + drivers/coresight/coresight-tmc.c | 791 ++ drivers/coresight/coresight-tpiu.c | 223 +++ drivers/coresight/coresight.c | 680 + drivers/coresight/of_coresight.c | 207 +++ include/linux/amba/bus.h |1 + include/linux/coresight.h | 190 +++ include/linux/of_coresight.h | 27 + 30 files changed, 6166 insertions(+), 874 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/coresight.txt delete mode 100644 arch/arm/include/asm/hardware/coresight.h create mode 100644 arch/arm/include/asm/hardware/cp14.h delete mode 100644 arch/arm/kernel/etm.c delete mode 100644 arch/arm/mach-omap2/emu.c create mode 100644 drivers/coresight/Kconfig create mode 100644 drivers/coresight/Makefile create mode 100644 drivers/coresight/coresight-etb.c create mode 100644 drivers/coresight/coresight-etm-cp14.c create mode 100644 drivers/coresight/coresight-etm.c create mode 100644 drivers/coresight/coresight-etm.h create mode 100644 drivers/coresight/coresight-funnel.c create mode 100644 drivers/coresight/coresight-priv.h create mode 100644 drivers/coresight/coresight-tmc.c create mode 100644 drivers/coresight/coresight-tpiu.c create mode 100644 drivers/coresight/coresight.c create mode 100644 drivers/coresight/of_coresight.c create mode 100644 include/linux/coresight.h create mode 100644 include/linux/of_coresight.h -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 8/9 v2] coresight: adding basic support for Vexpress TC2
From: Mathieu Poirier mathieu.poir...@linaro.org Support for the 2 PTMs, 3 ETMs, funnel, TPIU and replicator connected to the ETB are included. Proper handling of the ITM and the replicator linked to it along with the CTIs and SWO are not included. Signed-off-by: Mathieu Poirier mathieu.poir...@linaro.org --- arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 174 + 1 file changed, 174 insertions(+) diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts index 15f98cb..390f2bb 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts @@ -334,6 +334,180 @@ }; }; + etb: etb@2001 { + compatible = arm,coresight-etb, arm,primecell; + reg = 0 0x2001 0 0x1000; + + coresight-default-sink; + clocks = oscclk6a; + clock-names = apb_pclk; + port { + etb_in_port: endpoint@0 { + slave-mode; + remote-endpoint = funnel_out_port0; + }; + }; + }; + + tpiu: tpiu@2003 { + compatible = arm,coresight-tpiu, arm,primecell; + reg = 0 0x2003 0 0x1000; + + clocks = oscclk6a; + clock-names = apb_pclk; + port { + tpiu_in_port: endpoint@0 { + slave-mode; + remote-endpoint = funnel_out_port1; + }; + }; + }; + + funnel { + compatible = arm,coresight-funnel, arm,primecell; + reg = 0 0x2004 0 0x1000; + + clocks = oscclk6a; + clock-names = apb_pclk; + ports { + #address-cells = 1; + #size-cells = 0; + + /* The funnel is connected to a replicator - since +* replicators are hardwired we simply treat the +* funnel as a multiple-in and multiple out component. +* The following two ports really belong to the +* repicator but configured as par of the funnel. +*/ + + /* replicator port */ + port@0 { + reg = 0; + funnel_out_port0: endpoint { + remote-endpoint = etb_in_port; + }; + }; + + /* replicator port */ + port@1 { + reg = 1; + funnel_out_port1: endpoint { + remote-endpoint = tpiu_in_port; + }; + }; + /* funnel ports */ + port@2 { + reg = 0; + funnel_in_port0: endpoint { + slave-mode; + remote-endpoint = ptm0_out_port; + }; + }; + + port@3 { + reg = 1; + funnel_in_port1: endpoint { + slave-mode; + remote-endpoint = ptm1_out_port; + }; + }; + + port@4 { + reg = 2; + funnel_in_port2: endpoint { + slave-mode; + remote-endpoint = etm0_out_port; + }; + }; + + port@5 { + reg = 4; + funnel_in_port4: endpoint { + slave-mode; + remote-endpoint = etm1_out_port; + }; + }; + + port@6 { + reg = 5; + funnel_in_port5: endpoint { + slave-mode; + remote-endpoint = etm2_out_port; + }; + }; +}; + }; + + ptm0: ptm@2201c000 { + compatible = arm,coresight-etm, arm,primecell; + reg = 0 0x2201c000 0 0x1000; + + cpu = cpu0; + clocks = oscclk6a; + clock-names = apb_pclk; + port