Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

power: supply: smb347-charger: Implement device-tree support

This patch adds device-tree support to the SMB347 charger driver. All
legacy platform data now can be parsed from DT. Because of that and since
SMB347 is an I2C client driver, the IRQ number can be passed automatically
through client's IRQ variable if it's defined in DT. There is no need to
map GPIO to IRQ manually in the case of DT.

This patch is based on the original work made by:
Jonghwa Lee <jonghwa3.lee@samsung.com>
Link: https://patchwork.kernel.org/patch/4284731/

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>

authored by

David Heidelberg and committed by
Sebastian Reichel
364bec75 00cda13e

+137 -14
+137 -14
drivers/power/supply/smb347-charger.c
··· 1180 1180 return smb347_volatile_reg(dev, reg); 1181 1181 } 1182 1182 1183 + static void smb347_dt_parse_pdata(struct device_node *np, 1184 + struct smb347_charger_platform_data *pdata) 1185 + { 1186 + pdata->soft_temp_limit_compensation = 1187 + SMB347_SOFT_TEMP_COMPENSATE_DEFAULT; 1188 + /* 1189 + * These properties come from the battery info, still we need to 1190 + * pre-initialize the values. See smb347_get_battery_info() below. 1191 + */ 1192 + pdata->soft_cold_temp_limit = SMB347_TEMP_USE_DEFAULT; 1193 + pdata->hard_cold_temp_limit = SMB347_TEMP_USE_DEFAULT; 1194 + pdata->soft_hot_temp_limit = SMB347_TEMP_USE_DEFAULT; 1195 + pdata->hard_hot_temp_limit = SMB347_TEMP_USE_DEFAULT; 1196 + 1197 + /* Charging constraints */ 1198 + of_property_read_u32(np, "summit,fast-voltage-threshold-microvolt", 1199 + &pdata->pre_to_fast_voltage); 1200 + of_property_read_u32(np, "summit,mains-current-limit-microamp", 1201 + &pdata->mains_current_limit); 1202 + of_property_read_u32(np, "summit,usb-current-limit-microamp", 1203 + &pdata->usb_hc_current_limit); 1204 + 1205 + /* For thermometer monitoring */ 1206 + of_property_read_u32(np, "summit,chip-temperature-threshold-celsius", 1207 + &pdata->chip_temp_threshold); 1208 + of_property_read_u32(np, "summit,soft-compensation-method", 1209 + &pdata->soft_temp_limit_compensation); 1210 + of_property_read_u32(np, "summit,charge-current-compensation-microamp", 1211 + &pdata->charge_current_compensation); 1212 + 1213 + /* Supported charging mode */ 1214 + pdata->use_mains = 1215 + of_property_read_bool(np, "summit,enable-mains-charging"); 1216 + pdata->use_usb = 1217 + of_property_read_bool(np, "summit,enable-usb-charging"); 1218 + pdata->use_usb_otg = 1219 + of_property_read_bool(np, "summit,enable-otg-charging"); 1220 + 1221 + /* Select charging control */ 1222 + of_property_read_u32(np, "summit,enable-charge-control", 1223 + &pdata->enable_control); 1224 + 1225 + /* Interrupt support is optional */ 1226 + if (!of_find_property(np, "interrupts", NULL)) 1227 + pdata->irq_gpio = -1; 1228 + } 1229 + 1230 + static int smb347_get_battery_info(struct smb347_charger *smb) 1231 + { 1232 + struct smb347_charger_platform_data *pdata = (void *)smb->pdata; 1233 + struct power_supply_battery_info info = {}; 1234 + struct power_supply *supply; 1235 + int err; 1236 + 1237 + if (smb->mains) 1238 + supply = smb->mains; 1239 + else 1240 + supply = smb->usb; 1241 + 1242 + err = power_supply_get_battery_info(supply, &info); 1243 + if (err == -ENXIO || err == -ENODEV) 1244 + return 0; 1245 + if (err) 1246 + return err; 1247 + 1248 + if (info.constant_charge_current_max_ua != -EINVAL) 1249 + pdata->max_charge_current = info.constant_charge_current_max_ua; 1250 + 1251 + if (info.constant_charge_voltage_max_uv != -EINVAL) 1252 + pdata->max_charge_voltage = info.constant_charge_voltage_max_uv; 1253 + 1254 + if (info.precharge_current_ua != -EINVAL) 1255 + pdata->pre_charge_current = info.precharge_current_ua; 1256 + 1257 + if (info.charge_term_current_ua != -EINVAL) 1258 + pdata->termination_current = info.charge_term_current_ua; 1259 + 1260 + if (info.temp_alert_min != INT_MIN) 1261 + pdata->soft_cold_temp_limit = info.temp_alert_min; 1262 + 1263 + if (info.temp_alert_max != INT_MAX) 1264 + pdata->soft_hot_temp_limit = info.temp_alert_max; 1265 + 1266 + if (info.temp_min != INT_MIN) 1267 + pdata->hard_cold_temp_limit = info.temp_min; 1268 + 1269 + if (info.temp_max != INT_MAX) 1270 + pdata->hard_hot_temp_limit = info.temp_max; 1271 + 1272 + /* Suspend when battery temperature is outside hard limits */ 1273 + if (pdata->hard_cold_temp_limit != SMB347_TEMP_USE_DEFAULT || 1274 + pdata->hard_hot_temp_limit != SMB347_TEMP_USE_DEFAULT) 1275 + pdata->suspend_on_hard_temp_limit = true; 1276 + 1277 + return 0; 1278 + } 1279 + 1280 + static struct smb347_charger_platform_data 1281 + *smb347_get_platdata(struct device *dev) 1282 + { 1283 + struct smb347_charger_platform_data *pdata; 1284 + 1285 + if (dev->of_node) { 1286 + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 1287 + if (pdata) 1288 + smb347_dt_parse_pdata(dev->of_node, pdata); 1289 + } else { 1290 + pdata = dev_get_platdata(dev); 1291 + } 1292 + 1293 + return pdata; 1294 + } 1295 + 1183 1296 static const struct regmap_config smb347_regmap = { 1184 1297 .reg_bits = 8, 1185 1298 .val_bits = 8, ··· 1329 1216 const struct i2c_device_id *id) 1330 1217 { 1331 1218 static char *battery[] = { "smb347-battery" }; 1332 - const struct smb347_charger_platform_data *pdata; 1333 1219 struct power_supply_config mains_usb_cfg = {}, battery_cfg = {}; 1334 1220 struct device *dev = &client->dev; 1335 1221 struct smb347_charger *smb; 1336 1222 int ret; 1337 1223 1338 - pdata = dev->platform_data; 1339 - if (!pdata) 1340 - return -EINVAL; 1341 - 1342 - if (!pdata->use_mains && !pdata->use_usb) 1343 - return -EINVAL; 1344 - 1345 1224 smb = devm_kzalloc(dev, sizeof(*smb), GFP_KERNEL); 1346 1225 if (!smb) 1347 1226 return -ENOMEM; 1227 + 1228 + smb->pdata = smb347_get_platdata(dev); 1229 + if (!smb->pdata) 1230 + return -ENODEV; 1231 + 1232 + if (!smb->pdata->use_mains && !smb->pdata->use_usb) 1233 + return -EINVAL; 1348 1234 1349 1235 i2c_set_clientdata(client, smb); 1350 1236 1351 1237 mutex_init(&smb->lock); 1352 1238 smb->dev = &client->dev; 1353 - smb->pdata = pdata; 1354 1239 1355 1240 smb->regmap = devm_regmap_init_i2c(client, &smb347_regmap); 1356 1241 if (IS_ERR(smb->regmap)) 1357 1242 return PTR_ERR(smb->regmap); 1358 1243 1359 - ret = smb347_hw_init(smb); 1360 - if (ret < 0) 1361 - return ret; 1362 - 1363 1244 mains_usb_cfg.supplied_to = battery; 1364 1245 mains_usb_cfg.num_supplicants = ARRAY_SIZE(battery); 1365 1246 mains_usb_cfg.drv_data = smb; 1247 + mains_usb_cfg.of_node = dev->of_node; 1366 1248 if (smb->pdata->use_mains) { 1367 1249 smb->mains = devm_power_supply_register(dev, &smb347_mains_desc, 1368 1250 &mains_usb_cfg); ··· 1378 1270 if (IS_ERR(smb->battery)) 1379 1271 return PTR_ERR(smb->battery); 1380 1272 1273 + ret = smb347_get_battery_info(smb); 1274 + if (ret) 1275 + return ret; 1276 + 1277 + ret = smb347_hw_init(smb); 1278 + if (ret < 0) 1279 + return ret; 1280 + 1381 1281 /* 1382 1282 * Interrupt pin is optional. If it is connected, we setup the 1383 1283 * interrupt support here. 1384 1284 */ 1385 - if (pdata->irq_gpio >= 0) { 1285 + if (smb->pdata->irq_gpio >= 0) { 1386 1286 ret = smb347_irq_init(smb, client); 1387 1287 if (ret < 0) { 1388 1288 dev_warn(dev, "failed to initialize IRQ: %d\n", ret); ··· 1418 1302 }; 1419 1303 MODULE_DEVICE_TABLE(i2c, smb347_id); 1420 1304 1305 + static const struct of_device_id smb3xx_of_match[] = { 1306 + { .compatible = "summit,smb347" }, 1307 + { }, 1308 + }; 1309 + MODULE_DEVICE_TABLE(of, smb3xx_of_match); 1310 + 1421 1311 static struct i2c_driver smb347_driver = { 1422 1312 .driver = { 1423 1313 .name = "smb347", 1314 + .of_match_table = smb3xx_of_match, 1424 1315 }, 1425 1316 .probe = smb347_probe, 1426 1317 .remove = smb347_remove,