Skip to content

Commit 0cd4f1f

Browse files
Dzmitry Sankouskisre
authored andcommitted
power: supply: max17042: add platform driver variant
Maxim PMICs may include fuel gauge with additional features, which is out of single Linux power supply driver scope. For example, in max77705 PMIC fuelgauge has additional registers, like IIN_REG, VSYS_REG, ISYS_REG. Those needed to measure PMIC input current, system voltage and current respectively. Those measurements cannot be bound to any of fuelgauge properties. The solution here add and option to use max17042 driver as a MFD sub device, thus allowing any additional functionality be implemented as another sub device. This will help to reduce code duplication in MFD fuel gauge drivers. Acked-by: Krzysztof Kozlowski <[email protected]> Signed-off-by: Dzmitry Sankouski <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sebastian Reichel <[email protected]>
1 parent bed41f0 commit 0cd4f1f

File tree

1 file changed

+141
-50
lines changed

1 file changed

+141
-50
lines changed

drivers/power/supply/max17042_battery.c

Lines changed: 141 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/i2c.h>
1717
#include <linux/delay.h>
1818
#include <linux/interrupt.h>
19+
#include <linux/platform_device.h>
1920
#include <linux/pm.h>
2021
#include <linux/mod_devicetable.h>
2122
#include <linux/power_supply.h>
@@ -52,13 +53,14 @@
5253
#define MAX17042_VMAX_TOLERANCE 50 /* 50 mV */
5354

5455
struct max17042_chip {
55-
struct i2c_client *client;
56+
struct device *dev;
5657
struct regmap *regmap;
5758
struct power_supply *battery;
5859
enum max170xx_chip_type chip_type;
5960
struct max17042_platform_data *pdata;
6061
struct work_struct work;
6162
int init_complete;
63+
int irq;
6264
};
6365

6466
static enum power_supply_property max17042_battery_props[] = {
@@ -573,11 +575,11 @@ static inline int max17042_model_data_compare(struct max17042_chip *chip,
573575
int i;
574576

575577
if (memcmp(data1, data2, size)) {
576-
dev_err(&chip->client->dev, "%s compare failed\n", __func__);
578+
dev_err(chip->dev, "%s compare failed\n", __func__);
577579
for (i = 0; i < size; i++)
578-
dev_info(&chip->client->dev, "0x%x, 0x%x",
580+
dev_info(chip->dev, "0x%x, 0x%x",
579581
data1[i], data2[i]);
580-
dev_info(&chip->client->dev, "\n");
582+
dev_info(chip->dev, "\n");
581583
return -EINVAL;
582584
}
583585
return 0;
@@ -812,14 +814,14 @@ static int max17042_init_chip(struct max17042_chip *chip)
812814
/* write cell characterization data */
813815
ret = max17042_init_model(chip);
814816
if (ret) {
815-
dev_err(&chip->client->dev, "%s init failed\n",
817+
dev_err(chip->dev, "%s init failed\n",
816818
__func__);
817819
return -EIO;
818820
}
819821

820822
ret = max17042_verify_model_lock(chip);
821823
if (ret) {
822-
dev_err(&chip->client->dev, "%s lock verify failed\n",
824+
dev_err(chip->dev, "%s lock verify failed\n",
823825
__func__);
824826
return -EIO;
825827
}
@@ -875,7 +877,7 @@ static irqreturn_t max17042_thread_handler(int id, void *dev)
875877
return IRQ_HANDLED;
876878

877879
if ((val & STATUS_SMN_BIT) || (val & STATUS_SMX_BIT)) {
878-
dev_dbg(&chip->client->dev, "SOC threshold INTR\n");
880+
dev_dbg(chip->dev, "SOC threshold INTR\n");
879881
max17042_set_soc_threshold(chip, 1);
880882
}
881883

@@ -907,7 +909,7 @@ static void max17042_init_worker(struct work_struct *work)
907909
static struct max17042_platform_data *
908910
max17042_get_of_pdata(struct max17042_chip *chip)
909911
{
910-
struct device *dev = &chip->client->dev;
912+
struct device *dev = chip->dev;
911913
struct device_node *np = dev->of_node;
912914
u32 prop;
913915
struct max17042_platform_data *pdata;
@@ -949,7 +951,7 @@ static struct max17042_reg_data max17047_default_pdata_init_regs[] = {
949951
static struct max17042_platform_data *
950952
max17042_get_default_pdata(struct max17042_chip *chip)
951953
{
952-
struct device *dev = &chip->client->dev;
954+
struct device *dev = chip->dev;
953955
struct max17042_platform_data *pdata;
954956
int ret, misc_cfg;
955957

@@ -990,7 +992,7 @@ max17042_get_default_pdata(struct max17042_chip *chip)
990992
static struct max17042_platform_data *
991993
max17042_get_pdata(struct max17042_chip *chip)
992994
{
993-
struct device *dev = &chip->client->dev;
995+
struct device *dev = chip->dev;
994996

995997
#ifdef CONFIG_OF
996998
if (dev->of_node)
@@ -1003,6 +1005,7 @@ max17042_get_pdata(struct max17042_chip *chip)
10031005
}
10041006

10051007
static const struct regmap_config max17042_regmap_config = {
1008+
.name = "max17042",
10061009
.reg_bits = 8,
10071010
.val_bits = 16,
10081011
.val_format_endian = REGMAP_ENDIAN_NATIVE,
@@ -1029,14 +1032,12 @@ static const struct power_supply_desc max17042_no_current_sense_psy_desc = {
10291032
.num_properties = ARRAY_SIZE(max17042_battery_props) - 2,
10301033
};
10311034

1032-
static int max17042_probe(struct i2c_client *client)
1035+
static int max17042_probe(struct i2c_client *client, struct device *dev, int irq,
1036+
enum max170xx_chip_type chip_type)
10331037
{
1034-
const struct i2c_device_id *id = i2c_client_get_device_id(client);
10351038
struct i2c_adapter *adapter = client->adapter;
10361039
const struct power_supply_desc *max17042_desc = &max17042_psy_desc;
10371040
struct power_supply_config psy_cfg = {};
1038-
const struct acpi_device_id *acpi_id = NULL;
1039-
struct device *dev = &client->dev;
10401041
struct max17042_chip *chip;
10411042
int ret;
10421043
int i;
@@ -1045,33 +1046,25 @@ static int max17042_probe(struct i2c_client *client)
10451046
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
10461047
return -EIO;
10471048

1048-
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
1049+
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
10491050
if (!chip)
10501051
return -ENOMEM;
10511052

1052-
chip->client = client;
1053-
if (id) {
1054-
chip->chip_type = id->driver_data;
1055-
} else {
1056-
acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
1057-
if (!acpi_id)
1058-
return -ENODEV;
1059-
1060-
chip->chip_type = acpi_id->driver_data;
1061-
}
1053+
chip->dev = dev;
1054+
chip->chip_type = chip_type;
10621055
chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config);
10631056
if (IS_ERR(chip->regmap)) {
1064-
dev_err(&client->dev, "Failed to initialize regmap\n");
1057+
dev_err(dev, "Failed to initialize regmap\n");
10651058
return -EINVAL;
10661059
}
10671060

10681061
chip->pdata = max17042_get_pdata(chip);
10691062
if (!chip->pdata) {
1070-
dev_err(&client->dev, "no platform data provided\n");
1063+
dev_err(dev, "no platform data provided\n");
10711064
return -EINVAL;
10721065
}
10731066

1074-
i2c_set_clientdata(client, chip);
1067+
dev_set_drvdata(dev, chip);
10751068
psy_cfg.drv_data = chip;
10761069
psy_cfg.of_node = dev->of_node;
10771070

@@ -1095,17 +1088,17 @@ static int max17042_probe(struct i2c_client *client)
10951088
regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007);
10961089
}
10971090

1098-
chip->battery = devm_power_supply_register(&client->dev, max17042_desc,
1091+
chip->battery = devm_power_supply_register(dev, max17042_desc,
10991092
&psy_cfg);
11001093
if (IS_ERR(chip->battery)) {
1101-
dev_err(&client->dev, "failed: power supply register\n");
1094+
dev_err(dev, "failed: power supply register\n");
11021095
return PTR_ERR(chip->battery);
11031096
}
11041097

1105-
if (client->irq) {
1098+
if (irq) {
11061099
unsigned int flags = IRQF_ONESHOT | IRQF_SHARED | IRQF_PROBE_SHARED;
11071100

1108-
ret = devm_request_threaded_irq(&client->dev, client->irq,
1101+
ret = devm_request_threaded_irq(dev, irq,
11091102
NULL,
11101103
max17042_thread_handler, flags,
11111104
chip->battery->desc->name,
@@ -1116,18 +1109,20 @@ static int max17042_probe(struct i2c_client *client)
11161109
CFG_ALRT_BIT_ENBL);
11171110
max17042_set_soc_threshold(chip, 1);
11181111
} else {
1119-
client->irq = 0;
1112+
irq = 0;
11201113
if (ret != -EBUSY)
1121-
dev_err(&client->dev, "Failed to get IRQ\n");
1114+
dev_err(dev, "Failed to get IRQ\n");
11221115
}
11231116
}
11241117
/* Not able to update the charge threshold when exceeded? -> disable */
1125-
if (!client->irq)
1118+
if (!irq)
11261119
regmap_write(chip->regmap, MAX17042_SALRT_Th, 0xff00);
11271120

1121+
chip->irq = irq;
1122+
11281123
regmap_read(chip->regmap, MAX17042_STATUS, &val);
11291124
if (val & STATUS_POR_BIT) {
1130-
ret = devm_work_autocancel(&client->dev, &chip->work,
1125+
ret = devm_work_autocancel(dev, &chip->work,
11311126
max17042_init_worker);
11321127
if (ret)
11331128
return ret;
@@ -1139,6 +1134,44 @@ static int max17042_probe(struct i2c_client *client)
11391134
return 0;
11401135
}
11411136

1137+
static int max17042_i2c_probe(struct i2c_client *client)
1138+
{
1139+
const struct i2c_device_id *id = i2c_client_get_device_id(client);
1140+
const struct acpi_device_id *acpi_id = NULL;
1141+
struct device *dev = &client->dev;
1142+
enum max170xx_chip_type chip_type;
1143+
1144+
if (id) {
1145+
chip_type = id->driver_data;
1146+
} else {
1147+
acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
1148+
if (!acpi_id)
1149+
return -ENODEV;
1150+
1151+
chip_type = acpi_id->driver_data;
1152+
}
1153+
1154+
return max17042_probe(client, dev, client->irq, chip_type);
1155+
}
1156+
1157+
static int max17042_platform_probe(struct platform_device *pdev)
1158+
{
1159+
struct device *dev = &pdev->dev;
1160+
struct i2c_client *i2c;
1161+
const struct platform_device_id *id;
1162+
int irq;
1163+
1164+
i2c = to_i2c_client(pdev->dev.parent);
1165+
if (!i2c)
1166+
return -EINVAL;
1167+
1168+
dev->of_node = dev->parent->of_node;
1169+
id = platform_get_device_id(pdev);
1170+
irq = platform_get_irq(pdev, 0);
1171+
1172+
return max17042_probe(i2c, dev, irq, id->driver_data);
1173+
}
1174+
11421175
#ifdef CONFIG_PM_SLEEP
11431176
static int max17042_suspend(struct device *dev)
11441177
{
@@ -1148,9 +1181,9 @@ static int max17042_suspend(struct device *dev)
11481181
* disable the irq and enable irq_wake
11491182
* capability to the interrupt line.
11501183
*/
1151-
if (chip->client->irq) {
1152-
disable_irq(chip->client->irq);
1153-
enable_irq_wake(chip->client->irq);
1184+
if (chip->irq) {
1185+
disable_irq(chip->irq);
1186+
enable_irq_wake(chip->irq);
11541187
}
11551188

11561189
return 0;
@@ -1160,9 +1193,9 @@ static int max17042_resume(struct device *dev)
11601193
{
11611194
struct max17042_chip *chip = dev_get_drvdata(dev);
11621195

1163-
if (chip->client->irq) {
1164-
disable_irq_wake(chip->client->irq);
1165-
enable_irq(chip->client->irq);
1196+
if (chip->irq) {
1197+
disable_irq_wake(chip->irq);
1198+
enable_irq(chip->irq);
11661199
/* re-program the SOC thresholds to 1% change */
11671200
max17042_set_soc_threshold(chip, 1);
11681201
}
@@ -1183,12 +1216,26 @@ MODULE_DEVICE_TABLE(acpi, max17042_acpi_match);
11831216
#endif
11841217

11851218
#ifdef CONFIG_OF
1186-
static const struct of_device_id max17042_dt_match[] = {
1187-
{ .compatible = "maxim,max17042" },
1188-
{ .compatible = "maxim,max17047" },
1189-
{ .compatible = "maxim,max17050" },
1190-
{ .compatible = "maxim,max17055" },
1191-
{ .compatible = "maxim,max77849-battery" },
1219+
/*
1220+
* Device may be instantiated through parent MFD device and device matching is done
1221+
* through platform_device_id.
1222+
*
1223+
* However if device's DT node contains proper clock compatible and driver is
1224+
* built as a module, then the *module* matching will be done trough DT aliases.
1225+
* This requires of_device_id table. In the same time this will not change the
1226+
* actual *device* matching so do not add .of_match_table.
1227+
*/
1228+
static const struct of_device_id max17042_dt_match[] __used = {
1229+
{ .compatible = "maxim,max17042",
1230+
.data = (void *) MAXIM_DEVICE_TYPE_MAX17042 },
1231+
{ .compatible = "maxim,max17047",
1232+
.data = (void *) MAXIM_DEVICE_TYPE_MAX17047 },
1233+
{ .compatible = "maxim,max17050",
1234+
.data = (void *) MAXIM_DEVICE_TYPE_MAX17050 },
1235+
{ .compatible = "maxim,max17055",
1236+
.data = (void *) MAXIM_DEVICE_TYPE_MAX17055 },
1237+
{ .compatible = "maxim,max77849-battery",
1238+
.data = (void *) MAXIM_DEVICE_TYPE_MAX17047 },
11921239
{ },
11931240
};
11941241
MODULE_DEVICE_TABLE(of, max17042_dt_match);
@@ -1204,17 +1251,61 @@ static const struct i2c_device_id max17042_id[] = {
12041251
};
12051252
MODULE_DEVICE_TABLE(i2c, max17042_id);
12061253

1254+
static const struct platform_device_id max17042_platform_id[] = {
1255+
{ "max17042", MAXIM_DEVICE_TYPE_MAX17042 },
1256+
{ "max17047", MAXIM_DEVICE_TYPE_MAX17047 },
1257+
{ "max17050", MAXIM_DEVICE_TYPE_MAX17050 },
1258+
{ "max17055", MAXIM_DEVICE_TYPE_MAX17055 },
1259+
{ "max77849-battery", MAXIM_DEVICE_TYPE_MAX17047 },
1260+
{ }
1261+
};
1262+
MODULE_DEVICE_TABLE(platform, max17042_platform_id);
1263+
12071264
static struct i2c_driver max17042_i2c_driver = {
12081265
.driver = {
12091266
.name = "max17042",
12101267
.acpi_match_table = ACPI_PTR(max17042_acpi_match),
12111268
.of_match_table = of_match_ptr(max17042_dt_match),
12121269
.pm = &max17042_pm_ops,
12131270
},
1214-
.probe = max17042_probe,
1271+
.probe = max17042_i2c_probe,
12151272
.id_table = max17042_id,
12161273
};
1217-
module_i2c_driver(max17042_i2c_driver);
1274+
1275+
static struct platform_driver max17042_platform_driver = {
1276+
.driver = {
1277+
.name = "max17042",
1278+
.acpi_match_table = ACPI_PTR(max17042_acpi_match),
1279+
.pm = &max17042_pm_ops,
1280+
},
1281+
.probe = max17042_platform_probe,
1282+
.id_table = max17042_platform_id,
1283+
};
1284+
1285+
static int __init max17042_init(void)
1286+
{
1287+
int ret;
1288+
1289+
ret = platform_driver_register(&max17042_platform_driver);
1290+
if (ret)
1291+
return ret;
1292+
1293+
ret = i2c_add_driver(&max17042_i2c_driver);
1294+
if (ret) {
1295+
platform_driver_unregister(&max17042_platform_driver);
1296+
return ret;
1297+
}
1298+
1299+
return 0;
1300+
}
1301+
module_init(max17042_init);
1302+
1303+
static void __exit max17042_exit(void)
1304+
{
1305+
i2c_del_driver(&max17042_i2c_driver);
1306+
platform_driver_unregister(&max17042_platform_driver);
1307+
}
1308+
module_exit(max17042_exit);
12181309

12191310
MODULE_AUTHOR("MyungJoo Ham <[email protected]>");
12201311
MODULE_DESCRIPTION("MAX17042 Fuel Gauge");

0 commit comments

Comments
 (0)