int ltc294x_init(void) { struct i2c_client *client = <c2943_client; ltc2943_client.addr = LTC2943_ADDRESS; struct ltc294x_info *info = <c2943_info; int ret; u32 prescaler_exp; s32 r_sense; info->num_regs = LTC2943_NUM_REGS; /* r_sense can be negative, when sense+ is connected to the battery * instead of the sense-. This results in reversed measurements. */ info->r_sense = 20; // in mOhm prescaler_exp = LTC2943_MAX_PRESCALER_EXP; if (info->num_regs == LTC2943_NUM_REGS) { if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP) prescaler_exp = LTC2943_MAX_PRESCALER_EXP; info->Qlsb = ((340 * 50000) / r_sense) / (4096 / (1 << (2*prescaler_exp))); } else { if (prescaler_exp > LTC2941_MAX_PRESCALER_EXP) prescaler_exp = LTC2941_MAX_PRESCALER_EXP; info->Qlsb = ((85 * 50000) / r_sense) / (128 / (1 << prescaler_exp)); } info->client = client; info->supply_desc.type = POWER_SUPPLY_TYPE_BATTERY; info->supply_desc.properties = ltc294x_properties; if (info->num_regs >= LTC294X_REG_TEMPERATURE_LSB) info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties); else if (info->num_regs >= LTC294X_REG_CURRENT_LSB) info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties) - 1; else if (info->num_regs >= LTC294X_REG_VOLTAGE_LSB) info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties) - 2; else info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties) - 3; ret = ltc294x_reset(prescaler_exp); if (ret < 0) { dev_err(&client->dev, "Communication with chip failed\n"); goto fail_comm; } return 0; fail_comm: return ret; }
static int ltc294x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct power_supply_config psy_cfg = {}; struct ltc294x_info *info; int ret; int num; u32 prescaler_exp; s32 r_sense; struct device_node *np; mutex_lock(<c294x_lock); ret = idr_alloc(<c294x_id, client, 0, 0, GFP_KERNEL); mutex_unlock(<c294x_lock); if (ret < 0) goto fail_id; num = ret; info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); if (info == NULL) { ret = -ENOMEM; goto fail_info; } i2c_set_clientdata(client, info); info->num_regs = id->driver_data; info->supply_desc.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, num); if (!info->supply_desc.name) { ret = -ENOMEM; goto fail_name; } np = of_node_get(client->dev.of_node); /* r_sense can be negative, when sense+ is connected to the battery * instead of the sense-. This results in reversed measurements. */ ret = of_property_read_u32(np, "lltc,resistor-sense", &r_sense); if (ret < 0) { dev_err(&client->dev, "Could not find lltc,resistor-sense in devicetree\n"); goto fail_name; } info->r_sense = r_sense; ret = of_property_read_u32(np, "lltc,prescaler-exponent", &prescaler_exp); if (ret < 0) { dev_warn(&client->dev, "lltc,prescaler-exponent not in devicetree\n"); prescaler_exp = LTC2941_MAX_PRESCALER_EXP; } if (info->num_regs == LTC2943_NUM_REGS) { if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP) prescaler_exp = LTC2943_MAX_PRESCALER_EXP; info->Qlsb = ((340 * 50000) / r_sense) / (4096 / (1 << (2*prescaler_exp))); } else { if (prescaler_exp > LTC2941_MAX_PRESCALER_EXP) prescaler_exp = LTC2941_MAX_PRESCALER_EXP; info->Qlsb = ((85 * 50000) / r_sense) / (128 / (1 << prescaler_exp)); } info->client = client; info->id = num; info->supply_desc.type = POWER_SUPPLY_TYPE_BATTERY; info->supply_desc.properties = ltc294x_properties; if (info->num_regs >= LTC294X_REG_TEMPERATURE_LSB) info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties); else if (info->num_regs >= LTC294X_REG_CURRENT_LSB) info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties) - 1; else if (info->num_regs >= LTC294X_REG_VOLTAGE_LSB) info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties) - 2; else info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties) - 3; info->supply_desc.get_property = ltc294x_get_property; info->supply_desc.set_property = ltc294x_set_property; info->supply_desc.property_is_writeable = ltc294x_property_is_writeable; info->supply_desc.external_power_changed = NULL; psy_cfg.drv_data = info; INIT_DELAYED_WORK(&info->work, ltc294x_work); ret = ltc294x_reset(info, prescaler_exp); if (ret < 0) { dev_err(&client->dev, "Communication with chip failed\n"); goto fail_comm; } info->supply = power_supply_register(&client->dev, &info->supply_desc, &psy_cfg); if (IS_ERR(info->supply)) { dev_err(&client->dev, "failed to register ltc2941\n"); ret = PTR_ERR(info->supply); goto fail_register; } else { schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ); } return 0; fail_register: kfree(info->supply_desc.name); fail_comm: fail_name: fail_info: mutex_lock(<c294x_lock); idr_remove(<c294x_id, num); mutex_unlock(<c294x_lock); fail_id: return ret; }
static int ltc294x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ltc294x_platform_data *platform_data; struct ltc294x_info *info; int ret; u32 prescaler_exp; u8 status; info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); if (info == NULL) return -ENOMEM; i2c_set_clientdata(client, info); platform_data = client->dev.platform_data; info->id = (enum ltc294x_id)id->driver_data; info->supply.name = platform_data->name; /* r_sense can be negative, when sense+ is connected to the battery * instead of the sense-. This results in reversed measurements. */ info->r_sense = platform_data->r_sense; prescaler_exp = platform_data->prescaler_exp; if (info->id == LTC2943_ID) { if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP) prescaler_exp = LTC2943_MAX_PRESCALER_EXP; info->Qlsb = ((340 * 50000) / info->r_sense) / (4096 / (1 << (2*prescaler_exp))); } else { if (prescaler_exp > LTC2941_MAX_PRESCALER_EXP) prescaler_exp = LTC2941_MAX_PRESCALER_EXP; info->Qlsb = ((85 * 50000) / info->r_sense) / (128 / (1 << prescaler_exp)); } /* Read status register to check for LTC2942 */ if (info->id == LTC2941_ID || info->id == LTC2942_ID) { ret = ltc294x_read_regs(client, LTC294X_REG_STATUS, &status, 1); if (ret < 0) { dev_err(&client->dev, "Could not read status register\n"); return ret; } if (status & LTC2941_REG_STATUS_CHIP_ID) info->id = LTC2941_ID; else info->id = LTC2942_ID; } info->client = client; info->supply.type = POWER_SUPPLY_TYPE_BATTERY; info->supply.properties = ltc294x_properties; switch (info->id) { case LTC2944_ID: case LTC2943_ID: info->supply.num_properties = ARRAY_SIZE(ltc294x_properties); break; case LTC2942_ID: info->supply.num_properties = ARRAY_SIZE(ltc294x_properties) - 1; break; case LTC2941_ID: default: info->supply.num_properties = ARRAY_SIZE(ltc294x_properties) - 3; break; } info->supply.get_property = ltc294x_get_property; info->supply.set_property = ltc294x_set_property; info->supply.property_is_writeable = ltc294x_property_is_writeable; info->supply.external_power_changed = NULL; INIT_DELAYED_WORK(&info->work, ltc294x_work); ret = ltc294x_reset(info, prescaler_exp); if (ret < 0) { dev_err(&client->dev, "Communication with chip failed\n"); return ret; } ret = power_supply_register(&client->dev, &info->supply); if (ret) { dev_err(&client->dev, "failed to register ltc2941\n"); return ret; } else { schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ); } return 0; }