| .. | .. |
|---|
| 1 | | -/* |
|---|
| 2 | | - * Fuel gauge driver for Maxim 17042 / 8966 / 8997 |
|---|
| 3 | | - * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. |
|---|
| 4 | | - * |
|---|
| 5 | | - * Copyright (C) 2011 Samsung Electronics |
|---|
| 6 | | - * MyungJoo Ham <myungjoo.ham@samsung.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 10 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 11 | | - * (at your option) any later version. |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 16 | | - * GNU General Public License for more details. |
|---|
| 17 | | - * |
|---|
| 18 | | - * You should have received a copy of the GNU General Public License |
|---|
| 19 | | - * along with this program; if not, write to the Free Software |
|---|
| 20 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 21 | | - * |
|---|
| 22 | | - * This driver is based on max17040_battery.c |
|---|
| 23 | | - */ |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
|---|
| 2 | +// |
|---|
| 3 | +// Fuel gauge driver for Maxim 17042 / 8966 / 8997 |
|---|
| 4 | +// Note that Maxim 8966 and 8997 are mfd and this is its subdevice. |
|---|
| 5 | +// |
|---|
| 6 | +// Copyright (C) 2011 Samsung Electronics |
|---|
| 7 | +// MyungJoo Ham <myungjoo.ham@samsung.com> |
|---|
| 8 | +// |
|---|
| 9 | +// This driver is based on max17040_battery.c |
|---|
| 24 | 10 | |
|---|
| 25 | 11 | #include <linux/acpi.h> |
|---|
| 26 | 12 | #include <linux/init.h> |
|---|
| .. | .. |
|---|
| 99 | 85 | POWER_SUPPLY_PROP_TEMP_MAX, |
|---|
| 100 | 86 | POWER_SUPPLY_PROP_HEALTH, |
|---|
| 101 | 87 | POWER_SUPPLY_PROP_SCOPE, |
|---|
| 88 | + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, |
|---|
| 89 | + // these two have to be at the end on the list |
|---|
| 102 | 90 | POWER_SUPPLY_PROP_CURRENT_NOW, |
|---|
| 103 | 91 | POWER_SUPPLY_PROP_CURRENT_AVG, |
|---|
| 104 | 92 | }; |
|---|
| .. | .. |
|---|
| 296 | 284 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: |
|---|
| 297 | 285 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) |
|---|
| 298 | 286 | ret = regmap_read(map, MAX17042_V_empty, &data); |
|---|
| 287 | + else if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055) |
|---|
| 288 | + ret = regmap_read(map, MAX17055_V_empty, &data); |
|---|
| 299 | 289 | else |
|---|
| 300 | 290 | ret = regmap_read(map, MAX17047_V_empty, &data); |
|---|
| 301 | 291 | if (ret < 0) |
|---|
| .. | .. |
|---|
| 426 | 416 | return -EINVAL; |
|---|
| 427 | 417 | } |
|---|
| 428 | 418 | break; |
|---|
| 419 | + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: |
|---|
| 420 | + ret = regmap_read(map, MAX17042_TTE, &data); |
|---|
| 421 | + if (ret < 0) |
|---|
| 422 | + return ret; |
|---|
| 423 | + |
|---|
| 424 | + val->intval = data * 5625 / 1000; |
|---|
| 425 | + break; |
|---|
| 429 | 426 | default: |
|---|
| 430 | 427 | return -EINVAL; |
|---|
| 431 | 428 | } |
|---|
| .. | .. |
|---|
| 528 | 525 | regmap_write(map, reg, value); |
|---|
| 529 | 526 | } |
|---|
| 530 | 527 | |
|---|
| 531 | | -static inline void max10742_unlock_model(struct max17042_chip *chip) |
|---|
| 528 | +static inline void max17042_unlock_model(struct max17042_chip *chip) |
|---|
| 532 | 529 | { |
|---|
| 533 | 530 | struct regmap *map = chip->regmap; |
|---|
| 534 | 531 | |
|---|
| .. | .. |
|---|
| 536 | 533 | regmap_write(map, MAX17042_MLOCKReg2, MODEL_UNLOCK2); |
|---|
| 537 | 534 | } |
|---|
| 538 | 535 | |
|---|
| 539 | | -static inline void max10742_lock_model(struct max17042_chip *chip) |
|---|
| 536 | +static inline void max17042_lock_model(struct max17042_chip *chip) |
|---|
| 540 | 537 | { |
|---|
| 541 | 538 | struct regmap *map = chip->regmap; |
|---|
| 542 | 539 | |
|---|
| .. | .. |
|---|
| 594 | 591 | if (!temp_data) |
|---|
| 595 | 592 | return -ENOMEM; |
|---|
| 596 | 593 | |
|---|
| 597 | | - max10742_unlock_model(chip); |
|---|
| 594 | + max17042_unlock_model(chip); |
|---|
| 598 | 595 | max17042_write_model_data(chip, MAX17042_MODELChrTbl, |
|---|
| 599 | 596 | table_size); |
|---|
| 600 | 597 | max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data, |
|---|
| .. | .. |
|---|
| 606 | 603 | temp_data, |
|---|
| 607 | 604 | table_size); |
|---|
| 608 | 605 | |
|---|
| 609 | | - max10742_lock_model(chip); |
|---|
| 606 | + max17042_lock_model(chip); |
|---|
| 610 | 607 | kfree(temp_data); |
|---|
| 611 | 608 | |
|---|
| 612 | 609 | return ret; |
|---|
| .. | .. |
|---|
| 644 | 641 | config->filter_cfg); |
|---|
| 645 | 642 | regmap_write(map, MAX17042_RelaxCFG, config->relax_cfg); |
|---|
| 646 | 643 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047 || |
|---|
| 647 | | - chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050) |
|---|
| 644 | + chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050 || |
|---|
| 645 | + chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055) |
|---|
| 648 | 646 | regmap_write(map, MAX17047_FullSOCThr, |
|---|
| 649 | 647 | config->full_soc_thresh); |
|---|
| 650 | 648 | } |
|---|
| .. | .. |
|---|
| 775 | 773 | |
|---|
| 776 | 774 | if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) |
|---|
| 777 | 775 | max17042_override_por(map, MAX17042_V_empty, config->vempty); |
|---|
| 776 | + if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055) |
|---|
| 777 | + max17042_override_por(map, MAX17055_V_empty, config->vempty); |
|---|
| 778 | 778 | else |
|---|
| 779 | 779 | max17042_override_por(map, MAX17047_V_empty, config->vempty); |
|---|
| 780 | 780 | max17042_override_por(map, MAX17042_TempNom, config->temp_nom); |
|---|
| .. | .. |
|---|
| 782 | 782 | max17042_override_por(map, MAX17042_FCTC, config->fctc); |
|---|
| 783 | 783 | max17042_override_por(map, MAX17042_RCOMP0, config->rcomp0); |
|---|
| 784 | 784 | max17042_override_por(map, MAX17042_TempCo, config->tcompc0); |
|---|
| 785 | | - if (chip->chip_type) { |
|---|
| 785 | + if (chip->chip_type && |
|---|
| 786 | + ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) || |
|---|
| 787 | + (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) || |
|---|
| 788 | + (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050))) { |
|---|
| 786 | 789 | max17042_override_por(map, MAX17042_EmptyTempCo, |
|---|
| 787 | 790 | config->empty_tempco); |
|---|
| 788 | 791 | max17042_override_por(map, MAX17042_K_empty0, |
|---|
| .. | .. |
|---|
| 872 | 875 | max17042_set_soc_threshold(chip, 1); |
|---|
| 873 | 876 | } |
|---|
| 874 | 877 | |
|---|
| 878 | + /* we implicitly handle all alerts via power_supply_changed */ |
|---|
| 879 | + regmap_clear_bits(chip->regmap, MAX17042_STATUS, |
|---|
| 880 | + 0xFFFF & ~(STATUS_POR_BIT | STATUS_BST_BIT)); |
|---|
| 881 | + |
|---|
| 875 | 882 | power_supply_changed(chip->battery); |
|---|
| 876 | 883 | return IRQ_HANDLED; |
|---|
| 877 | 884 | } |
|---|
| .. | .. |
|---|
| 951 | 958 | if (!pdata) |
|---|
| 952 | 959 | return pdata; |
|---|
| 953 | 960 | |
|---|
| 954 | | - if (chip->chip_type != MAXIM_DEVICE_TYPE_MAX17042) { |
|---|
| 961 | + if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) || |
|---|
| 962 | + (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) { |
|---|
| 955 | 963 | pdata->init_data = max17047_default_pdata_init_regs; |
|---|
| 956 | 964 | pdata->num_init_data = |
|---|
| 957 | 965 | ARRAY_SIZE(max17047_default_pdata_init_regs); |
|---|
| .. | .. |
|---|
| 1017 | 1025 | .num_properties = ARRAY_SIZE(max17042_battery_props) - 2, |
|---|
| 1018 | 1026 | }; |
|---|
| 1019 | 1027 | |
|---|
| 1028 | +static void max17042_stop_work(void *data) |
|---|
| 1029 | +{ |
|---|
| 1030 | + struct max17042_chip *chip = data; |
|---|
| 1031 | + |
|---|
| 1032 | + cancel_work_sync(&chip->work); |
|---|
| 1033 | +} |
|---|
| 1034 | + |
|---|
| 1020 | 1035 | static int max17042_probe(struct i2c_client *client, |
|---|
| 1021 | 1036 | const struct i2c_device_id *id) |
|---|
| 1022 | 1037 | { |
|---|
| 1023 | | - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
|---|
| 1038 | + struct i2c_adapter *adapter = client->adapter; |
|---|
| 1024 | 1039 | const struct power_supply_desc *max17042_desc = &max17042_psy_desc; |
|---|
| 1025 | 1040 | struct power_supply_config psy_cfg = {}; |
|---|
| 1026 | 1041 | const struct acpi_device_id *acpi_id = NULL; |
|---|
| .. | .. |
|---|
| 1123 | 1138 | regmap_read(chip->regmap, MAX17042_STATUS, &val); |
|---|
| 1124 | 1139 | if (val & STATUS_POR_BIT) { |
|---|
| 1125 | 1140 | INIT_WORK(&chip->work, max17042_init_worker); |
|---|
| 1141 | + ret = devm_add_action(&client->dev, max17042_stop_work, chip); |
|---|
| 1142 | + if (ret) |
|---|
| 1143 | + return ret; |
|---|
| 1126 | 1144 | schedule_work(&chip->work); |
|---|
| 1127 | 1145 | } else { |
|---|
| 1128 | 1146 | chip->init_complete = 1; |
|---|
| .. | .. |
|---|
| 1179 | 1197 | { .compatible = "maxim,max17042" }, |
|---|
| 1180 | 1198 | { .compatible = "maxim,max17047" }, |
|---|
| 1181 | 1199 | { .compatible = "maxim,max17050" }, |
|---|
| 1200 | + { .compatible = "maxim,max17055" }, |
|---|
| 1182 | 1201 | { }, |
|---|
| 1183 | 1202 | }; |
|---|
| 1184 | 1203 | MODULE_DEVICE_TABLE(of, max17042_dt_match); |
|---|
| .. | .. |
|---|
| 1188 | 1207 | { "max17042", MAXIM_DEVICE_TYPE_MAX17042 }, |
|---|
| 1189 | 1208 | { "max17047", MAXIM_DEVICE_TYPE_MAX17047 }, |
|---|
| 1190 | 1209 | { "max17050", MAXIM_DEVICE_TYPE_MAX17050 }, |
|---|
| 1210 | + { "max17055", MAXIM_DEVICE_TYPE_MAX17055 }, |
|---|
| 1191 | 1211 | { } |
|---|
| 1192 | 1212 | }; |
|---|
| 1193 | 1213 | MODULE_DEVICE_TABLE(i2c, max17042_id); |
|---|