Merge branch 'i2c/for-4.15' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:
 "This contains two bigger than usual tree-wide changes this time. They
  all have proper acks, caused no merge conflicts in linux-next where
  they have been for a while. They are namely:

   - to-gpiod conversion of the i2c-gpio driver and its users (touching
     arch/* and drivers/mfd/*)

   - adding a sbs-manager based on I2C core updates to SMBus alerts
     (touching drivers/power/*)

  Other notable changes:

   - i2c_boardinfo can now carry a dev_name to be used when the device
     is created. This is because some devices in ACPI world need fixed
     names to find the regulators.

   - the designware driver got a long discussed overhaul of its PM
     handling. img-scb and davinci got PM support, too.

   - at24 driver has way better OF support. And it has a new maintainer.
     Thanks Bartosz for stepping up!

  The rest is regular driver updates and fixes"

* 'i2c/for-4.15' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (55 commits)
  ARM: sa1100: simpad: Correct I2C GPIO offsets
  i2c: aspeed: Deassert reset in probe
  eeprom: at24: Add OF device ID table
  MAINTAINERS: new maintainer for AT24 driver
  i2c: nuc900: remove platform_data, too
  i2c: thunderx: Remove duplicate NULL check
  i2c: taos-evm: Remove duplicate NULL check
  i2c: Make i2c_unregister_device() NULL-aware
  i2c: xgene-slimpro: Support v2
  i2c: mpc: remove useless variable initialization
  i2c: omap: Trigger bus recovery in lockup case
  i2c: gpio: Add support for named gpios in DT
  dt-bindings: i2c: i2c-gpio: Add support for named gpios
  i2c: gpio: Local vars in probe
  i2c: gpio: Augment all boardfiles to use open drain
  i2c: gpio: Enforce open drain through gpiolib
  gpio: Make it possible for consumers to enforce open drain
  i2c: gpio: Convert to use descriptors
  power: supply: sbs-message: fix some code style issues
  power: supply: sbs-battery: remove unchecked return var
  ...
This commit is contained in:
Linus Torvalds 2017-11-14 17:52:21 -08:00
commit 4008e6a9bc
70 changed files with 1685 additions and 600 deletions

View file

@ -184,6 +184,20 @@ config CHARGER_SBS
help
Say Y to include support for SBS compilant battery chargers.
config MANAGER_SBS
tristate "Smart Battery System Manager"
depends on I2C && I2C_MUX && GPIOLIB
select I2C_SMBUS
help
Say Y here to include support for Smart Battery System Manager
ICs. The driver reports online and charging status via sysfs.
It presents itself also as I2C mux which allows to bind
smart battery driver to its ports.
Supported is for example LTC1760.
This driver can also be built as a module. If so, the module will be
called sbs-manager.
config BATTERY_BQ27XXX
tristate "BQ27xxx battery driver"
help

View file

@ -37,6 +37,7 @@ obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o
obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o
obj-$(CONFIG_CHARGER_SBS) += sbs-charger.o
obj-$(CONFIG_MANAGER_SBS) += sbs-manager.o
obj-$(CONFIG_BATTERY_BQ27XXX) += bq27xxx_battery.o
obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o
obj-$(CONFIG_BATTERY_BQ27XXX_HDQ) += bq27xxx_battery_hdq.o

View file

@ -177,10 +177,8 @@ static bool force_load;
static int sbs_read_word_data(struct i2c_client *client, u8 address)
{
struct sbs_info *chip = i2c_get_clientdata(client);
int retries = chip->i2c_retry_count;
s32 ret = 0;
int retries = 1;
retries = chip->i2c_retry_count;
while (retries > 0) {
ret = i2c_smbus_read_word_data(client, address);
@ -204,7 +202,7 @@ static int sbs_read_string_data(struct i2c_client *client, u8 address,
{
struct sbs_info *chip = i2c_get_clientdata(client);
s32 ret = 0, block_length = 0;
int retries_length = 1, retries_block = 1;
int retries_length, retries_block;
u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
retries_length = chip->i2c_retry_count;
@ -269,10 +267,8 @@ static int sbs_write_word_data(struct i2c_client *client, u8 address,
u16 value)
{
struct sbs_info *chip = i2c_get_clientdata(client);
int retries = chip->i2c_retry_count;
s32 ret = 0;
int retries = 1;
retries = chip->i2c_retry_count;
while (retries > 0) {
ret = i2c_smbus_write_word_data(client, address, value);
@ -321,16 +317,6 @@ static int sbs_get_battery_presence_and_health(
union power_supply_propval *val)
{
s32 ret;
struct sbs_info *chip = i2c_get_clientdata(client);
if (psp == POWER_SUPPLY_PROP_PRESENT && chip->gpio_detect) {
ret = gpiod_get_value_cansleep(chip->gpio_detect);
if (ret < 0)
return ret;
val->intval = ret;
chip->is_present = val->intval;
return ret;
}
/*
* Write to ManufacturerAccess with ManufacturerAccess command
@ -570,7 +556,7 @@ static int sbs_get_battery_serial_number(struct i2c_client *client,
if (ret < 0)
return ret;
ret = sprintf(sbs_serial, "%04x", ret);
sprintf(sbs_serial, "%04x", ret);
val->strval = sbs_serial;
return 0;
@ -598,6 +584,19 @@ static int sbs_get_property(struct power_supply *psy,
struct sbs_info *chip = power_supply_get_drvdata(psy);
struct i2c_client *client = chip->client;
if (chip->gpio_detect) {
ret = gpiod_get_value_cansleep(chip->gpio_detect);
if (ret < 0)
return ret;
if (psp == POWER_SUPPLY_PROP_PRESENT) {
val->intval = ret;
chip->is_present = val->intval;
return 0;
}
if (ret == 0)
return -ENODATA;
}
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_HEALTH:

View file

@ -0,0 +1,445 @@
/*
* Driver for SBS compliant Smart Battery System Managers
*
* The device communicates via i2c at address 0x0a and multiplexes access to up
* to four smart batteries at address 0x0b.
*
* Via sysfs interface the online state and charge type are presented.
*
* Datasheet SBSM: http://sbs-forum.org/specs/sbsm100b.pdf
* Datasheet LTC1760: http://cds.linear.com/docs/en/datasheet/1760fb.pdf
*
* Karl-Heinz Schneider <karl-heinz@schneider-inet.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/power_supply.h>
#include <linux/property.h>
#define SBSM_MAX_BATS 4
#define SBSM_RETRY_CNT 3
/* registers addresses */
#define SBSM_CMD_BATSYSSTATE 0x01
#define SBSM_CMD_BATSYSSTATECONT 0x02
#define SBSM_CMD_BATSYSINFO 0x04
#define SBSM_CMD_LTC 0x3c
#define SBSM_MASK_BAT_SUPPORTED GENMASK(3, 0)
#define SBSM_MASK_CHARGE_BAT GENMASK(7, 4)
#define SBSM_BIT_AC_PRESENT BIT(0)
#define SBSM_BIT_TURBO BIT(7)
#define SBSM_SMB_BAT_OFFSET 11
struct sbsm_data {
struct i2c_client *client;
struct i2c_mux_core *muxc;
struct power_supply *psy;
u8 cur_chan; /* currently selected channel */
struct gpio_chip chip;
bool is_ltc1760; /* special capabilities */
unsigned int supported_bats;
unsigned int last_state;
unsigned int last_state_cont;
};
static enum power_supply_property sbsm_props[] = {
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_CHARGE_TYPE,
};
static int sbsm_read_word(struct i2c_client *client, u8 address)
{
int reg, retries;
for (retries = SBSM_RETRY_CNT; retries > 0; retries--) {
reg = i2c_smbus_read_word_data(client, address);
if (reg >= 0)
break;
}
if (reg < 0) {
dev_err(&client->dev, "failed to read register 0x%02x\n",
address);
}
return reg;
}
static int sbsm_write_word(struct i2c_client *client, u8 address, u16 word)
{
int ret, retries;
for (retries = SBSM_RETRY_CNT; retries > 0; retries--) {
ret = i2c_smbus_write_word_data(client, address, word);
if (ret >= 0)
break;
}
if (ret < 0)
dev_err(&client->dev, "failed to write to register 0x%02x\n",
address);
return ret;
}
static int sbsm_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct sbsm_data *data = power_supply_get_drvdata(psy);
int regval = 0;
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
regval = sbsm_read_word(data->client, SBSM_CMD_BATSYSSTATECONT);
if (regval < 0)
return regval;
val->intval = !!(regval & SBSM_BIT_AC_PRESENT);
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
regval = sbsm_read_word(data->client, SBSM_CMD_BATSYSSTATE);
if (regval < 0)
return regval;
if ((regval & SBSM_MASK_CHARGE_BAT) == 0) {
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
return 0;
}
val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
if (data->is_ltc1760) {
/* charge mode fast if turbo is active */
regval = sbsm_read_word(data->client, SBSM_CMD_LTC);
if (regval < 0)
return regval;
else if (regval & SBSM_BIT_TURBO)
val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
}
break;
default:
return -EINVAL;
}
return 0;
}
static int sbsm_prop_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
struct sbsm_data *data = power_supply_get_drvdata(psy);
return (psp == POWER_SUPPLY_PROP_CHARGE_TYPE) && data->is_ltc1760;
}
static int sbsm_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct sbsm_data *data = power_supply_get_drvdata(psy);
int ret = -EINVAL;
u16 regval;
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_TYPE:
/* write 1 to TURBO if type fast is given */
if (!data->is_ltc1760)
break;
regval = val->intval ==
POWER_SUPPLY_CHARGE_TYPE_FAST ? SBSM_BIT_TURBO : 0;
ret = sbsm_write_word(data->client, SBSM_CMD_LTC, regval);
break;
default:
break;
}
return ret;
}
/*
* Switch to battery
* Parameter chan is directly the content of SMB_BAT* nibble
*/
static int sbsm_select(struct i2c_mux_core *muxc, u32 chan)
{
struct sbsm_data *data = i2c_mux_priv(muxc);
struct device *dev = &data->client->dev;
int ret = 0;
u16 reg;
if (data->cur_chan == chan)
return ret;
/* chan goes from 1 ... 4 */
reg = 1 << BIT(SBSM_SMB_BAT_OFFSET + chan);
ret = sbsm_write_word(data->client, SBSM_CMD_BATSYSSTATE, reg);
if (ret)
dev_err(dev, "Failed to select channel %i\n", chan);
else
data->cur_chan = chan;
return ret;
}
static int sbsm_gpio_get_value(struct gpio_chip *gc, unsigned int off)
{
struct sbsm_data *data = gpiochip_get_data(gc);
int ret;
ret = sbsm_read_word(data->client, SBSM_CMD_BATSYSSTATE);
if (ret < 0)
return ret;
return ret & BIT(off);
}
/*
* This needs to be defined or the GPIO lib fails to register the pin.
* But the 'gpio' is always an input.
*/
static int sbsm_gpio_direction_input(struct gpio_chip *gc, unsigned int off)
{
return 0;
}
static int sbsm_do_alert(struct device *dev, void *d)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
if (!client || client->addr != 0x0b)
return 0;
device_lock(dev);
if (client->dev.driver) {
driver = to_i2c_driver(client->dev.driver);
if (driver->alert)
driver->alert(client, I2C_PROTOCOL_SMBUS_ALERT, 0);
else
dev_warn(&client->dev, "no driver alert()!\n");
} else {
dev_dbg(&client->dev, "alert with no driver\n");
}
device_unlock(dev);
return -EBUSY;
}
static void sbsm_alert(struct i2c_client *client, enum i2c_alert_protocol prot,
unsigned int d)
{
struct sbsm_data *sbsm = i2c_get_clientdata(client);
int ret, i, irq_bat = 0, state = 0;
ret = sbsm_read_word(sbsm->client, SBSM_CMD_BATSYSSTATE);
if (ret >= 0) {
irq_bat = ret ^ sbsm->last_state;
sbsm->last_state = ret;
state = ret;
}
ret = sbsm_read_word(sbsm->client, SBSM_CMD_BATSYSSTATECONT);
if ((ret >= 0) &&
((ret ^ sbsm->last_state_cont) & SBSM_BIT_AC_PRESENT)) {
irq_bat |= sbsm->supported_bats & state;
power_supply_changed(sbsm->psy);
}
sbsm->last_state_cont = ret;
for (i = 0; i < SBSM_MAX_BATS; i++) {
if (irq_bat & BIT(i)) {
device_for_each_child(&sbsm->muxc->adapter[i]->dev,
NULL, sbsm_do_alert);
}
}
}
static int sbsm_gpio_setup(struct sbsm_data *data)
{
struct gpio_chip *gc = &data->chip;
struct i2c_client *client = data->client;
struct device *dev = &client->dev;
int ret;
if (!device_property_present(dev, "gpio-controller"))
return 0;
ret = sbsm_read_word(client, SBSM_CMD_BATSYSSTATE);
if (ret < 0)
return ret;
data->last_state = ret;
ret = sbsm_read_word(client, SBSM_CMD_BATSYSSTATECONT);
if (ret < 0)
return ret;
data->last_state_cont = ret;
gc->get = sbsm_gpio_get_value;
gc->direction_input = sbsm_gpio_direction_input;
gc->can_sleep = true;
gc->base = -1;
gc->ngpio = SBSM_MAX_BATS;
gc->label = client->name;
gc->parent = dev;
gc->owner = THIS_MODULE;
ret = devm_gpiochip_add_data(dev, gc, data);
if (ret) {
dev_err(dev, "devm_gpiochip_add_data failed: %d\n", ret);
return ret;
}
return ret;
}
static const struct power_supply_desc sbsm_default_psy_desc = {
.type = POWER_SUPPLY_TYPE_MAINS,
.properties = sbsm_props,
.num_properties = ARRAY_SIZE(sbsm_props),
.get_property = &sbsm_get_property,
.set_property = &sbsm_set_property,
.property_is_writeable = &sbsm_prop_is_writeable,
};
static int sbsm_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct sbsm_data *data;
struct device *dev = &client->dev;
struct power_supply_desc *psy_desc;
struct power_supply_config psy_cfg = {};
int ret = 0, i;
/* Device listens only at address 0x0a */
if (client->addr != 0x0a)
return -EINVAL;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EPFNOSUPPORT;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
i2c_set_clientdata(client, data);
data->client = client;
data->is_ltc1760 = !!strstr(id->name, "ltc1760");
ret = sbsm_read_word(client, SBSM_CMD_BATSYSINFO);
if (ret < 0)
return ret;
data->supported_bats = ret & SBSM_MASK_BAT_SUPPORTED;
data->muxc = i2c_mux_alloc(adapter, dev, SBSM_MAX_BATS, 0,
I2C_MUX_LOCKED, &sbsm_select, NULL);
if (!data->muxc) {
dev_err(dev, "failed to alloc i2c mux\n");
ret = -ENOMEM;
goto err_mux_alloc;
}
data->muxc->priv = data;
/* register muxed i2c channels. One for each supported battery */
for (i = 0; i < SBSM_MAX_BATS; ++i) {
if (data->supported_bats & BIT(i)) {
ret = i2c_mux_add_adapter(data->muxc, 0, i + 1, 0);
if (ret)
break;
}
}
if (ret) {
dev_err(dev, "failed to register i2c mux channel %d\n", i + 1);
goto err_mux_register;
}
psy_desc = devm_kmemdup(dev, &sbsm_default_psy_desc,
sizeof(struct power_supply_desc),
GFP_KERNEL);
if (!psy_desc) {
ret = -ENOMEM;
goto err_psy;
}
psy_desc->name = devm_kasprintf(dev, GFP_KERNEL, "sbsm-%s",
dev_name(&client->dev));
if (!psy_desc->name) {
ret = -ENOMEM;
goto err_psy;
}
ret = sbsm_gpio_setup(data);
if (ret < 0)
goto err_psy;
psy_cfg.drv_data = data;
psy_cfg.of_node = dev->of_node;
data->psy = devm_power_supply_register(dev, psy_desc, &psy_cfg);
if (IS_ERR(data->psy)) {
ret = PTR_ERR(data->psy);
dev_err(dev, "failed to register power supply %s\n",
psy_desc->name);
goto err_psy;
}
return 0;
err_psy:
err_mux_register:
i2c_mux_del_adapters(data->muxc);
err_mux_alloc:
return ret;
}
static int sbsm_remove(struct i2c_client *client)
{
struct sbsm_data *data = i2c_get_clientdata(client);
i2c_mux_del_adapters(data->muxc);
return 0;
}
static const struct i2c_device_id sbsm_ids[] = {
{ "sbs-manager", 0 },
{ "ltc1760", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, sbsm_ids);
#ifdef CONFIG_OF
static const struct of_device_id sbsm_dt_ids[] = {
{ .compatible = "sbs,sbs-manager" },
{ .compatible = "lltc,ltc1760" },
{ }
};
MODULE_DEVICE_TABLE(of, sbsm_dt_ids);
#endif
static struct i2c_driver sbsm_driver = {
.driver = {
.name = "sbsm",
.of_match_table = of_match_ptr(sbsm_dt_ids),
},
.probe = sbsm_probe,
.remove = sbsm_remove,
.alert = sbsm_alert,
.id_table = sbsm_ids
};
module_i2c_driver(sbsm_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Karl-Heinz Schneider <[email protected]>");
MODULE_DESCRIPTION("SBSM Smart Battery System Manager");