.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) ST-Ericsson AB 2012 |
---|
3 | 4 | * |
---|
.. | .. |
---|
8 | 9 | * battery management is not used and the supported code is available in this |
---|
9 | 10 | * driver. |
---|
10 | 11 | * |
---|
11 | | - * License Terms: GNU General Public License v2 |
---|
12 | 12 | * Author: |
---|
13 | 13 | * Johan Palsson <johan.palsson@stericsson.com> |
---|
14 | 14 | * Karl Komierowski <karl.komierowski@stericsson.com> |
---|
.. | .. |
---|
32 | 32 | #include <linux/mfd/abx500.h> |
---|
33 | 33 | #include <linux/mfd/abx500/ab8500.h> |
---|
34 | 34 | #include <linux/mfd/abx500/ab8500-bm.h> |
---|
35 | | -#include <linux/mfd/abx500/ab8500-gpadc.h> |
---|
| 35 | +#include <linux/iio/consumer.h> |
---|
36 | 36 | #include <linux/kernel.h> |
---|
37 | 37 | |
---|
38 | 38 | #define MILLI_TO_MICRO 1000 |
---|
.. | .. |
---|
182 | 182 | * @bat_cap: Structure for battery capacity specific parameters |
---|
183 | 183 | * @avg_cap: Average capacity filter |
---|
184 | 184 | * @parent: Pointer to the struct ab8500 |
---|
185 | | - * @gpadc: Pointer to the struct gpadc |
---|
| 185 | + * @main_bat_v: ADC channel for the main battery voltage |
---|
186 | 186 | * @bm: Platform specific battery management information |
---|
187 | 187 | * @fg_psy: Structure that holds the FG specific battery properties |
---|
188 | 188 | * @fg_wq: Work queue for running the FG algorithm |
---|
.. | .. |
---|
224 | 224 | struct ab8500_fg_battery_capacity bat_cap; |
---|
225 | 225 | struct ab8500_fg_avg_cap avg_cap; |
---|
226 | 226 | struct ab8500 *parent; |
---|
227 | | - struct ab8500_gpadc *gpadc; |
---|
| 227 | + struct iio_channel *main_bat_v; |
---|
228 | 228 | struct abx500_bm_data *bm; |
---|
229 | 229 | struct power_supply *fg_psy; |
---|
230 | 230 | struct workqueue_struct *fg_wq; |
---|
.. | .. |
---|
653 | 653 | |
---|
654 | 654 | /* |
---|
655 | 655 | * negative value for Discharging |
---|
656 | | - * convert 2's compliment into decimal |
---|
| 656 | + * convert 2's complement into decimal |
---|
657 | 657 | */ |
---|
658 | 658 | if (high & 0x10) |
---|
659 | 659 | val = (low | (high << 8) | 0xFFFFE000); |
---|
.. | .. |
---|
781 | 781 | if (ret < 0) |
---|
782 | 782 | goto exit; |
---|
783 | 783 | |
---|
784 | | - /* Check for sign bit in case of negative value, 2's compliment */ |
---|
| 784 | + /* Check for sign bit in case of negative value, 2's complement */ |
---|
785 | 785 | if (high & 0x10) |
---|
786 | 786 | val = (low | (med << 8) | (high << 16) | 0xFFE00000); |
---|
787 | 787 | else |
---|
.. | .. |
---|
829 | 829 | */ |
---|
830 | 830 | static int ab8500_fg_bat_voltage(struct ab8500_fg *di) |
---|
831 | 831 | { |
---|
832 | | - int vbat; |
---|
| 832 | + int vbat, ret; |
---|
833 | 833 | static int prev; |
---|
834 | 834 | |
---|
835 | | - vbat = ab8500_gpadc_convert(di->gpadc, MAIN_BAT_V); |
---|
836 | | - if (vbat < 0) { |
---|
| 835 | + ret = iio_read_channel_processed(di->main_bat_v, &vbat); |
---|
| 836 | + if (ret < 0) { |
---|
837 | 837 | dev_err(di->dev, |
---|
838 | | - "%s gpadc conversion failed, using previous value\n", |
---|
| 838 | + "%s ADC conversion failed, using previous value\n", |
---|
839 | 839 | __func__); |
---|
840 | 840 | return prev; |
---|
841 | 841 | } |
---|
.. | .. |
---|
1542 | 1542 | ab8500_fg_discharge_state_to(di, |
---|
1543 | 1543 | AB8500_FG_DISCHARGE_INITMEASURING); |
---|
1544 | 1544 | |
---|
1545 | | - /* Intentional fallthrough */ |
---|
| 1545 | + fallthrough; |
---|
1546 | 1546 | case AB8500_FG_DISCHARGE_INITMEASURING: |
---|
1547 | 1547 | /* |
---|
1548 | 1548 | * Discard a number of samples during startup. |
---|
.. | .. |
---|
1572 | 1572 | ab8500_fg_discharge_state_to(di, |
---|
1573 | 1573 | AB8500_FG_DISCHARGE_RECOVERY); |
---|
1574 | 1574 | |
---|
1575 | | - /* Intentional fallthrough */ |
---|
| 1575 | + fallthrough; |
---|
1576 | 1576 | |
---|
1577 | 1577 | case AB8500_FG_DISCHARGE_RECOVERY: |
---|
1578 | 1578 | sleep_time = di->bm->fg_params->recovery_sleep_timer; |
---|
.. | .. |
---|
2221 | 2221 | ab8500_fg_update_cap_scalers(di); |
---|
2222 | 2222 | queue_work(di->fg_wq, &di->fg_work); |
---|
2223 | 2223 | break; |
---|
2224 | | - }; |
---|
| 2224 | + } |
---|
2225 | 2225 | default: |
---|
2226 | 2226 | break; |
---|
2227 | | - }; |
---|
| 2227 | + } |
---|
2228 | 2228 | break; |
---|
2229 | 2229 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
---|
2230 | 2230 | switch (ext->desc->type) { |
---|
.. | .. |
---|
2331 | 2331 | if (ret) { |
---|
2332 | 2332 | dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_MAX_TIME_REG\n", __func__); |
---|
2333 | 2333 | goto out; |
---|
2334 | | - }; |
---|
| 2334 | + } |
---|
2335 | 2335 | |
---|
2336 | 2336 | ret = abx500_set_register_interruptible(di->dev, AB8500_RTC, |
---|
2337 | 2337 | AB8505_RTC_PCUT_FLAG_TIME_REG, di->bm->fg_params->pcut_flag_time); |
---|
.. | .. |
---|
2339 | 2339 | if (ret) { |
---|
2340 | 2340 | dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_FLAG_TIME_REG\n", __func__); |
---|
2341 | 2341 | goto out; |
---|
2342 | | - }; |
---|
| 2342 | + } |
---|
2343 | 2343 | |
---|
2344 | 2344 | ret = abx500_set_register_interruptible(di->dev, AB8500_RTC, |
---|
2345 | 2345 | AB8505_RTC_PCUT_RESTART_REG, di->bm->fg_params->pcut_max_restart); |
---|
.. | .. |
---|
2347 | 2347 | if (ret) { |
---|
2348 | 2348 | dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_RESTART_REG\n", __func__); |
---|
2349 | 2349 | goto out; |
---|
2350 | | - }; |
---|
| 2350 | + } |
---|
2351 | 2351 | |
---|
2352 | 2352 | ret = abx500_set_register_interruptible(di->dev, AB8500_RTC, |
---|
2353 | 2353 | AB8505_RTC_PCUT_DEBOUNCE_REG, di->bm->fg_params->pcut_debounce_time); |
---|
.. | .. |
---|
2355 | 2355 | if (ret) { |
---|
2356 | 2356 | dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_DEBOUNCE_REG\n", __func__); |
---|
2357 | 2357 | goto out; |
---|
2358 | | - }; |
---|
| 2358 | + } |
---|
2359 | 2359 | |
---|
2360 | 2360 | ret = abx500_set_register_interruptible(di->dev, AB8500_RTC, |
---|
2361 | 2361 | AB8505_RTC_PCUT_CTL_STATUS_REG, di->bm->fg_params->pcut_enable); |
---|
.. | .. |
---|
2363 | 2363 | if (ret) { |
---|
2364 | 2364 | dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_CTL_STATUS_REG\n", __func__); |
---|
2365 | 2365 | goto out; |
---|
2366 | | - }; |
---|
| 2366 | + } |
---|
2367 | 2367 | } |
---|
2368 | 2368 | out: |
---|
2369 | 2369 | return ret; |
---|
.. | .. |
---|
2399 | 2399 | struct ab8500_fg *di = container_of(work, struct ab8500_fg, |
---|
2400 | 2400 | fg_reinit_work.work); |
---|
2401 | 2401 | |
---|
2402 | | - if (di->flags.calibrate == false) { |
---|
| 2402 | + if (!di->flags.calibrate) { |
---|
2403 | 2403 | dev_dbg(di->dev, "Resetting FG state machine to init.\n"); |
---|
2404 | 2404 | ab8500_fg_clear_cap_samples(di); |
---|
2405 | 2405 | ab8500_fg_calc_cap_discharge_voltage(di, true); |
---|
.. | .. |
---|
2541 | 2541 | ret = kobject_init_and_add(&di->fg_kobject, |
---|
2542 | 2542 | &ab8500_fg_ktype, |
---|
2543 | 2543 | NULL, "battery"); |
---|
2544 | | - if (ret < 0) |
---|
| 2544 | + if (ret < 0) { |
---|
| 2545 | + kobject_put(&di->fg_kobject); |
---|
2545 | 2546 | dev_err(di->dev, "failed to create sysfs entry\n"); |
---|
| 2547 | + } |
---|
2546 | 2548 | |
---|
2547 | 2549 | return ret; |
---|
2548 | 2550 | } |
---|
.. | .. |
---|
2575 | 2577 | const char *buf, size_t count) |
---|
2576 | 2578 | { |
---|
2577 | 2579 | int ret; |
---|
2578 | | - long unsigned reg_value; |
---|
| 2580 | + int reg_value; |
---|
2579 | 2581 | struct power_supply *psy = dev_get_drvdata(dev); |
---|
2580 | 2582 | struct ab8500_fg *di = power_supply_get_drvdata(psy); |
---|
2581 | 2583 | |
---|
2582 | | - reg_value = simple_strtoul(buf, NULL, 10); |
---|
| 2584 | + if (kstrtoint(buf, 10, ®_value)) |
---|
| 2585 | + goto fail; |
---|
2583 | 2586 | |
---|
2584 | 2587 | if (reg_value > 0x7F) { |
---|
2585 | 2588 | dev_err(dev, "Incorrect parameter, echo 0 (1.98s) - 127 (15.625ms) for flagtime\n"); |
---|
.. | .. |
---|
2629 | 2632 | struct power_supply *psy = dev_get_drvdata(dev); |
---|
2630 | 2633 | struct ab8500_fg *di = power_supply_get_drvdata(psy); |
---|
2631 | 2634 | |
---|
2632 | | - reg_value = simple_strtoul(buf, NULL, 10); |
---|
| 2635 | + if (kstrtoint(buf, 10, ®_value)) |
---|
| 2636 | + goto fail; |
---|
| 2637 | + |
---|
2633 | 2638 | if (reg_value > 0x7F) { |
---|
2634 | 2639 | dev_err(dev, "Incorrect parameter, echo 0 (0.0s) - 127 (1.98s) for maxtime\n"); |
---|
2635 | 2640 | goto fail; |
---|
.. | .. |
---|
2677 | 2682 | struct power_supply *psy = dev_get_drvdata(dev); |
---|
2678 | 2683 | struct ab8500_fg *di = power_supply_get_drvdata(psy); |
---|
2679 | 2684 | |
---|
2680 | | - reg_value = simple_strtoul(buf, NULL, 10); |
---|
| 2685 | + if (kstrtoint(buf, 10, ®_value)) |
---|
| 2686 | + goto fail; |
---|
| 2687 | + |
---|
2681 | 2688 | if (reg_value > 0xF) { |
---|
2682 | 2689 | dev_err(dev, "Incorrect parameter, echo 0 - 15 for number of restart\n"); |
---|
2683 | 2690 | goto fail; |
---|
.. | .. |
---|
2770 | 2777 | struct power_supply *psy = dev_get_drvdata(dev); |
---|
2771 | 2778 | struct ab8500_fg *di = power_supply_get_drvdata(psy); |
---|
2772 | 2779 | |
---|
2773 | | - reg_value = simple_strtoul(buf, NULL, 10); |
---|
| 2780 | + if (kstrtoint(buf, 10, ®_value)) |
---|
| 2781 | + goto fail; |
---|
| 2782 | + |
---|
2774 | 2783 | if (reg_value > 0x1) { |
---|
2775 | 2784 | dev_err(dev, "Incorrect parameter, echo 0/1 to disable/enable Pcut feature\n"); |
---|
2776 | 2785 | goto fail; |
---|
.. | .. |
---|
2842 | 2851 | struct power_supply *psy = dev_get_drvdata(dev); |
---|
2843 | 2852 | struct ab8500_fg *di = power_supply_get_drvdata(psy); |
---|
2844 | 2853 | |
---|
2845 | | - reg_value = simple_strtoul(buf, NULL, 10); |
---|
| 2854 | + if (kstrtoint(buf, 10, ®_value)) |
---|
| 2855 | + goto fail; |
---|
| 2856 | + |
---|
2846 | 2857 | if (reg_value > 0x7) { |
---|
2847 | 2858 | dev_err(dev, "Incorrect parameter, echo 0 to 7 for debounce setting\n"); |
---|
2848 | 2859 | goto fail; |
---|
.. | .. |
---|
3057 | 3068 | /* get parent data */ |
---|
3058 | 3069 | di->dev = &pdev->dev; |
---|
3059 | 3070 | di->parent = dev_get_drvdata(pdev->dev.parent); |
---|
3060 | | - di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); |
---|
| 3071 | + |
---|
| 3072 | + di->main_bat_v = devm_iio_channel_get(&pdev->dev, "main_bat_v"); |
---|
| 3073 | + if (IS_ERR(di->main_bat_v)) { |
---|
| 3074 | + if (PTR_ERR(di->main_bat_v) == -ENODEV) |
---|
| 3075 | + return -EPROBE_DEFER; |
---|
| 3076 | + dev_err(&pdev->dev, "failed to get main battery ADC channel\n"); |
---|
| 3077 | + return PTR_ERR(di->main_bat_v); |
---|
| 3078 | + } |
---|
3061 | 3079 | |
---|
3062 | 3080 | psy_cfg.supplied_to = supply_interface; |
---|
3063 | 3081 | psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); |
---|
.. | .. |
---|
3142 | 3160 | /* Register primary interrupt handlers */ |
---|
3143 | 3161 | for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq_th); i++) { |
---|
3144 | 3162 | irq = platform_get_irq_byname(pdev, ab8500_fg_irq_th[i].name); |
---|
| 3163 | + if (irq < 0) { |
---|
| 3164 | + ret = irq; |
---|
| 3165 | + goto free_irq_th; |
---|
| 3166 | + } |
---|
| 3167 | + |
---|
3145 | 3168 | ret = request_irq(irq, ab8500_fg_irq_th[i].isr, |
---|
3146 | 3169 | IRQF_SHARED | IRQF_NO_SUSPEND, |
---|
3147 | 3170 | ab8500_fg_irq_th[i].name, di); |
---|
.. | .. |
---|
3149 | 3172 | if (ret != 0) { |
---|
3150 | 3173 | dev_err(di->dev, "failed to request %s IRQ %d: %d\n", |
---|
3151 | 3174 | ab8500_fg_irq_th[i].name, irq, ret); |
---|
3152 | | - goto free_irq; |
---|
| 3175 | + goto free_irq_th; |
---|
3153 | 3176 | } |
---|
3154 | 3177 | dev_dbg(di->dev, "Requested %s IRQ %d: %d\n", |
---|
3155 | 3178 | ab8500_fg_irq_th[i].name, irq, ret); |
---|
.. | .. |
---|
3157 | 3180 | |
---|
3158 | 3181 | /* Register threaded interrupt handler */ |
---|
3159 | 3182 | irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name); |
---|
| 3183 | + if (irq < 0) { |
---|
| 3184 | + ret = irq; |
---|
| 3185 | + goto free_irq_th; |
---|
| 3186 | + } |
---|
| 3187 | + |
---|
3160 | 3188 | ret = request_threaded_irq(irq, NULL, ab8500_fg_irq_bh[0].isr, |
---|
3161 | 3189 | IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, |
---|
3162 | 3190 | ab8500_fg_irq_bh[0].name, di); |
---|
.. | .. |
---|
3164 | 3192 | if (ret != 0) { |
---|
3165 | 3193 | dev_err(di->dev, "failed to request %s IRQ %d: %d\n", |
---|
3166 | 3194 | ab8500_fg_irq_bh[0].name, irq, ret); |
---|
3167 | | - goto free_irq; |
---|
| 3195 | + goto free_irq_th; |
---|
3168 | 3196 | } |
---|
3169 | 3197 | dev_dbg(di->dev, "Requested %s IRQ %d: %d\n", |
---|
3170 | 3198 | ab8500_fg_irq_bh[0].name, irq, ret); |
---|
.. | .. |
---|
3203 | 3231 | return ret; |
---|
3204 | 3232 | |
---|
3205 | 3233 | free_irq: |
---|
3206 | | - power_supply_unregister(di->fg_psy); |
---|
3207 | | - |
---|
3208 | 3234 | /* We also have to free all registered irqs */ |
---|
3209 | | - for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq_th); i++) { |
---|
| 3235 | + irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name); |
---|
| 3236 | + free_irq(irq, di); |
---|
| 3237 | +free_irq_th: |
---|
| 3238 | + while (--i >= 0) { |
---|
| 3239 | + /* Last assignment of i from primary interrupt handlers */ |
---|
3210 | 3240 | irq = platform_get_irq_byname(pdev, ab8500_fg_irq_th[i].name); |
---|
3211 | 3241 | free_irq(irq, di); |
---|
3212 | 3242 | } |
---|
3213 | | - irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name); |
---|
3214 | | - free_irq(irq, di); |
---|
| 3243 | + |
---|
| 3244 | + power_supply_unregister(di->fg_psy); |
---|
3215 | 3245 | free_inst_curr_wq: |
---|
3216 | 3246 | destroy_workqueue(di->fg_wq); |
---|
3217 | 3247 | return ret; |
---|