in supply/qcom_smbb.c [831:1001]
static int smbb_charger_probe(struct platform_device *pdev)
{
struct power_supply_config bat_cfg = {};
struct power_supply_config usb_cfg = {};
struct power_supply_config dc_cfg = {};
struct smbb_charger *chg;
struct regulator_config config = { };
int rc, i;
chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
if (!chg)
return -ENOMEM;
chg->dev = &pdev->dev;
mutex_init(&chg->statlock);
chg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!chg->regmap) {
dev_err(&pdev->dev, "failed to locate regmap\n");
return -ENODEV;
}
rc = of_property_read_u32(pdev->dev.of_node, "reg", &chg->addr);
if (rc) {
dev_err(&pdev->dev, "missing or invalid 'reg' property\n");
return rc;
}
rc = regmap_read(chg->regmap, chg->addr + SMBB_MISC_REV2, &chg->revision);
if (rc) {
dev_err(&pdev->dev, "unable to read revision\n");
return rc;
}
chg->revision += 1;
if (chg->revision != 1 && chg->revision != 2 && chg->revision != 3) {
dev_err(&pdev->dev, "v%d hardware not supported\n", chg->revision);
return -ENODEV;
}
dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision);
chg->dc_disabled = of_property_read_bool(pdev->dev.of_node, "qcom,disable-dc");
for (i = 0; i < _ATTR_CNT; ++i) {
rc = smbb_charger_attr_parse(chg, i);
if (rc) {
dev_err(&pdev->dev, "failed to parse/apply settings\n");
return rc;
}
}
bat_cfg.drv_data = chg;
bat_cfg.of_node = pdev->dev.of_node;
chg->bat_psy = devm_power_supply_register(&pdev->dev,
&bat_psy_desc,
&bat_cfg);
if (IS_ERR(chg->bat_psy)) {
dev_err(&pdev->dev, "failed to register battery\n");
return PTR_ERR(chg->bat_psy);
}
usb_cfg.drv_data = chg;
usb_cfg.supplied_to = smbb_bif;
usb_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
chg->usb_psy = devm_power_supply_register(&pdev->dev,
&usb_psy_desc,
&usb_cfg);
if (IS_ERR(chg->usb_psy)) {
dev_err(&pdev->dev, "failed to register USB power supply\n");
return PTR_ERR(chg->usb_psy);
}
chg->edev = devm_extcon_dev_allocate(&pdev->dev, smbb_usb_extcon_cable);
if (IS_ERR(chg->edev)) {
dev_err(&pdev->dev, "failed to allocate extcon device\n");
return -ENOMEM;
}
rc = devm_extcon_dev_register(&pdev->dev, chg->edev);
if (rc < 0) {
dev_err(&pdev->dev, "failed to register extcon device\n");
return rc;
}
if (!chg->dc_disabled) {
dc_cfg.drv_data = chg;
dc_cfg.supplied_to = smbb_bif;
dc_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
chg->dc_psy = devm_power_supply_register(&pdev->dev,
&dc_psy_desc,
&dc_cfg);
if (IS_ERR(chg->dc_psy)) {
dev_err(&pdev->dev, "failed to register DC power supply\n");
return PTR_ERR(chg->dc_psy);
}
}
for (i = 0; i < ARRAY_SIZE(smbb_charger_irqs); ++i) {
int irq;
irq = platform_get_irq_byname(pdev, smbb_charger_irqs[i].name);
if (irq < 0)
return irq;
smbb_charger_irqs[i].handler(irq, chg);
rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
smbb_charger_irqs[i].handler, IRQF_ONESHOT,
smbb_charger_irqs[i].name, chg);
if (rc) {
dev_err(&pdev->dev, "failed to request irq '%s'\n",
smbb_charger_irqs[i].name);
return rc;
}
}
/*
* otg regulator is used to control VBUS voltage direction
* when USB switches between host and gadget mode
*/
chg->otg_rdesc.id = -1;
chg->otg_rdesc.name = "otg-vbus";
chg->otg_rdesc.ops = &smbb_chg_otg_ops;
chg->otg_rdesc.owner = THIS_MODULE;
chg->otg_rdesc.type = REGULATOR_VOLTAGE;
chg->otg_rdesc.supply_name = "usb-otg-in";
chg->otg_rdesc.of_match = "otg-vbus";
config.dev = &pdev->dev;
config.driver_data = chg;
chg->otg_reg = devm_regulator_register(&pdev->dev, &chg->otg_rdesc,
&config);
if (IS_ERR(chg->otg_reg))
return PTR_ERR(chg->otg_reg);
chg->jeita_ext_temp = of_property_read_bool(pdev->dev.of_node,
"qcom,jeita-extended-temp-range");
/* Set temperature range to [35%:70%] or [25%:80%] accordingly */
rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_BAT_BTC_CTRL,
BTC_CTRL_COLD_EXT | BTC_CTRL_HOT_EXT_N,
chg->jeita_ext_temp ?
BTC_CTRL_COLD_EXT :
BTC_CTRL_HOT_EXT_N);
if (rc) {
dev_err(&pdev->dev,
"unable to set %s temperature range\n",
chg->jeita_ext_temp ? "JEITA extended" : "normal");
return rc;
}
for (i = 0; i < ARRAY_SIZE(smbb_charger_setup); ++i) {
const struct reg_off_mask_default *r = &smbb_charger_setup[i];
if (r->rev_mask & BIT(chg->revision))
continue;
rc = regmap_update_bits(chg->regmap, chg->addr + r->offset,
r->mask, r->value);
if (rc) {
dev_err(&pdev->dev,
"unable to initializing charging, bailing\n");
return rc;
}
}
platform_set_drvdata(pdev, chg);
return 0;
}