in supply/ucs1002_power.c [535:671]
static int ucs1002_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct device *dev = &client->dev;
struct power_supply_config charger_config = {};
const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
struct regulator_config regulator_config = {};
int irq_a_det, irq_alert, ret;
struct ucs1002_info *info;
unsigned int regval;
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->regmap = devm_regmap_init_i2c(client, ®map_config);
ret = PTR_ERR_OR_ZERO(info->regmap);
if (ret) {
dev_err(dev, "Regmap initialization failed: %d\n", ret);
return ret;
}
info->client = client;
irq_a_det = of_irq_get_byname(dev->of_node, "a_det");
irq_alert = of_irq_get_byname(dev->of_node, "alert");
charger_config.of_node = dev->of_node;
charger_config.drv_data = info;
ret = regmap_read(info->regmap, UCS1002_REG_PRODUCT_ID, ®val);
if (ret) {
dev_err(dev, "Failed to read product ID: %d\n", ret);
return ret;
}
if (regval != UCS1002_PRODUCT_ID) {
dev_err(dev,
"Product ID does not match (0x%02x != 0x%02x)\n",
regval, UCS1002_PRODUCT_ID);
return -ENODEV;
}
/* Enable charge rationing by default */
ret = regmap_update_bits(info->regmap, UCS1002_REG_GENERAL_CFG,
F_RATION_EN, F_RATION_EN);
if (ret) {
dev_err(dev, "Failed to read general config: %d\n", ret);
return ret;
}
/*
* Ignore the M1, M2, PWR_EN, and EM_EN pin states. Set active
* mode selection to BC1.2 CDP.
*/
ret = regmap_update_bits(info->regmap, UCS1002_REG_SWITCH_CFG,
V_SET_ACTIVE_MODE_MASK | F_PIN_IGNORE,
V_SET_ACTIVE_MODE_BC12_CDP | F_PIN_IGNORE);
if (ret) {
dev_err(dev, "Failed to configure default mode: %d\n", ret);
return ret;
}
/*
* Be safe and set initial current limit to 500mA
*/
ret = ucs1002_set_max_current(info, 500000);
if (ret) {
dev_err(dev, "Failed to set max current default: %d\n", ret);
return ret;
}
info->charger = devm_power_supply_register(dev, &ucs1002_charger_desc,
&charger_config);
ret = PTR_ERR_OR_ZERO(info->charger);
if (ret) {
dev_err(dev, "Failed to register power supply: %d\n", ret);
return ret;
}
ret = regmap_read(info->regmap, UCS1002_REG_PIN_STATUS, ®val);
if (ret) {
dev_err(dev, "Failed to read pin status: %d\n", ret);
return ret;
}
info->regulator_descriptor =
devm_kmemdup(dev, &ucs1002_regulator_descriptor,
sizeof(ucs1002_regulator_descriptor),
GFP_KERNEL);
if (!info->regulator_descriptor)
return -ENOMEM;
info->regulator_descriptor->enable_is_inverted = !(regval & F_SEL_PIN);
regulator_config.dev = dev;
regulator_config.of_node = dev->of_node;
regulator_config.regmap = info->regmap;
regulator_config.driver_data = info;
info->rdev = devm_regulator_register(dev, info->regulator_descriptor,
®ulator_config);
ret = PTR_ERR_OR_ZERO(info->rdev);
if (ret) {
dev_err(dev, "Failed to register VBUS regulator: %d\n", ret);
return ret;
}
info->health = POWER_SUPPLY_HEALTH_GOOD;
INIT_DELAYED_WORK(&info->health_poll, ucs1002_health_poll);
if (irq_a_det > 0) {
ret = devm_request_threaded_irq(dev, irq_a_det, NULL,
ucs1002_charger_irq,
IRQF_ONESHOT,
"ucs1002-a_det", info);
if (ret) {
dev_err(dev, "Failed to request A_DET threaded irq: %d\n",
ret);
return ret;
}
}
if (irq_alert > 0) {
ret = devm_request_irq(dev, irq_alert, ucs1002_alert_irq,
0,"ucs1002-alert", info);
if (ret) {
dev_err(dev, "Failed to request ALERT threaded irq: %d\n",
ret);
return ret;
}
}
return 0;
}