Commit f6d29536 authored by Wolfram Sang's avatar Wolfram Sang

Merge branch 'i2c/sbs-manager' into i2c/for-4.15

parents 4ee045f4 4cf419a2
...@@ -59,8 +59,8 @@ wants to support one of the below features, it should adapt the bindings below. ...@@ -59,8 +59,8 @@ wants to support one of the below features, it should adapt the bindings below.
interrupts used by the device. interrupts used by the device.
- interrupt-names - interrupt-names
"irq" and "wakeup" names are recognized by I2C core, other names are "irq", "wakeup" and "smbus_alert" names are recognized by I2C core,
left to individual drivers. other names are left to individual drivers.
- host-notify - host-notify
device uses SMBus host notify protocol instead of interrupt line. device uses SMBus host notify protocol instead of interrupt line.
......
Binding for sbs-manager
Required properties:
- compatible: "<vendor>,<part-number>", "sbs,sbs-charger" as fallback. The part
number compatible string might be used in order to take care of vendor
specific registers.
- reg: integer, i2c address of the device. Should be <0xa>.
Optional properties:
- gpio-controller: Marks the port as GPIO controller.
See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt.
- #gpio-cells: Should be <2>. The first cell is the pin number, the second cell
is used to specify optional parameters:
See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt.
From OS view the device is basically an i2c-mux used to communicate with up to
four smart battery devices at address 0xb. The driver actually implements this
behaviour. So standard i2c-mux nodes can be used to register up to four slave
batteries. Channels will be numerated starting from 1 to 4.
Example:
batman@a {
compatible = "lltc,ltc1760", "sbs,sbs-manager";
reg = <0x0a>;
#address-cells = <1>;
#size-cells = <0>;
gpio-controller;
#gpio-cells = <2>;
i2c@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
battery@b {
compatible = "ti,bq2060", "sbs,sbs-battery";
reg = <0x0b>;
sbs,battery-detect-gpios = <&batman 1 1>;
};
};
i2c@2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
battery@b {
compatible = "ti,bq2060", "sbs,sbs-battery";
reg = <0x0b>;
sbs,battery-detect-gpios = <&batman 2 1>;
};
};
i2c@3 {
#address-cells = <1>;
#size-cells = <0>;
reg = <3>;
battery@b {
compatible = "ti,bq2060", "sbs,sbs-battery";
reg = <0x0b>;
sbs,battery-detect-gpios = <&batman 3 1>;
};
};
};
...@@ -123,7 +123,6 @@ static struct i2c_adapter parport_adapter = { ...@@ -123,7 +123,6 @@ static struct i2c_adapter parport_adapter = {
/* SMBus alert support */ /* SMBus alert support */
static struct i2c_smbus_alert_setup alert_data = { static struct i2c_smbus_alert_setup alert_data = {
.alert_edge_triggered = 1,
}; };
static struct i2c_client *ara; static struct i2c_client *ara;
static struct lineop parport_ctrl_irq = { static struct lineop parport_ctrl_irq = {
......
...@@ -237,7 +237,6 @@ static void i2c_parport_attach(struct parport *port) ...@@ -237,7 +237,6 @@ static void i2c_parport_attach(struct parport *port)
/* Setup SMBus alert if supported */ /* Setup SMBus alert if supported */
if (adapter_parm[type].smbus_alert) { if (adapter_parm[type].smbus_alert) {
adapter->alert_data.alert_edge_triggered = 1;
adapter->ara = i2c_setup_smbus_alert(&adapter->adapter, adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,
&adapter->alert_data); &adapter->alert_data);
if (adapter->ara) if (adapter->ara)
......
...@@ -118,8 +118,6 @@ static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk) ...@@ -118,8 +118,6 @@ static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk)
static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c, static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
struct device_node *node) struct device_node *node)
{ {
u32 type;
if (!node) if (!node)
return -EINVAL; return -EINVAL;
...@@ -127,10 +125,6 @@ static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c, ...@@ -127,10 +125,6 @@ static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
if (!i2c->alert_data.irq) if (!i2c->alert_data.irq)
return -EINVAL; return -EINVAL;
type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq));
i2c->alert_data.alert_edge_triggered =
(type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0;
i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data); i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data);
if (!i2c->ara) if (!i2c->ara)
return -ENODEV; return -ENODEV;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-smbus.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/irqflags.h> #include <linux/irqflags.h>
...@@ -1269,6 +1270,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -1269,6 +1270,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
goto out_list; goto out_list;
} }
res = of_i2c_setup_smbus_alert(adap);
if (res)
goto out_reg;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
pm_runtime_no_callbacks(&adap->dev); pm_runtime_no_callbacks(&adap->dev);
...@@ -1300,6 +1305,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -1300,6 +1305,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
return 0; return 0;
out_reg:
init_completion(&adap->dev_released);
device_unregister(&adap->dev);
wait_for_completion(&adap->dev_released);
out_list: out_list:
mutex_lock(&core_lock); mutex_lock(&core_lock);
idr_remove(&i2c_adapter_idr, adap->nr); idr_remove(&i2c_adapter_idr, adap->nr);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-smbus.h>
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/smbus.h> #include <trace/events/smbus.h>
...@@ -592,3 +593,57 @@ s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, ...@@ -592,3 +593,57 @@ s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
return i; return i;
} }
EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated); EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated);
/**
* i2c_setup_smbus_alert - Setup SMBus alert support
* @adapter: the target adapter
* @setup: setup data for the SMBus alert handler
* Context: can sleep
*
* Setup handling of the SMBus alert protocol on a given I2C bus segment.
*
* Handling can be done either through our IRQ handler, or by the
* adapter (from its handler, periodic polling, or whatever).
*
* NOTE that if we manage the IRQ, we *MUST* know if it's level or
* edge triggered in order to hand it to the workqueue correctly.
* If triggering the alert seems to wedge the system, you probably
* should have said it's level triggered.
*
* This returns the ara client, which should be saved for later use with
* i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL
* to indicate an error.
*/
struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
struct i2c_smbus_alert_setup *setup)
{
struct i2c_board_info ara_board_info = {
I2C_BOARD_INFO("smbus_alert", 0x0c),
.platform_data = setup,
};
return i2c_new_device(adapter, &ara_board_info);
}
EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF)
int of_i2c_setup_smbus_alert(struct i2c_adapter *adapter)
{
struct i2c_client *client;
int irq;
irq = of_property_match_string(adapter->dev.of_node, "interrupt-names",
"smbus_alert");
if (irq == -EINVAL || irq == -ENODATA)
return 0;
else if (irq < 0)
return irq;
client = i2c_setup_smbus_alert(adapter, NULL);
if (!client)
return -ENODEV;
return 0;
}
EXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert);
#endif
...@@ -21,12 +21,11 @@ ...@@ -21,12 +21,11 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
struct i2c_smbus_alert { struct i2c_smbus_alert {
unsigned int alert_edge_triggered:1;
int irq;
struct work_struct alert; struct work_struct alert;
struct i2c_client *ara; /* Alert response address */ struct i2c_client *ara; /* Alert response address */
}; };
...@@ -72,13 +71,12 @@ static int smbus_do_alert(struct device *dev, void *addrp) ...@@ -72,13 +71,12 @@ static int smbus_do_alert(struct device *dev, void *addrp)
* The alert IRQ handler needs to hand work off to a task which can issue * The alert IRQ handler needs to hand work off to a task which can issue
* SMBus calls, because those sleeping calls can't be made in IRQ context. * SMBus calls, because those sleeping calls can't be made in IRQ context.
*/ */
static void smbus_alert(struct work_struct *work) static irqreturn_t smbus_alert(int irq, void *d)
{ {
struct i2c_smbus_alert *alert; struct i2c_smbus_alert *alert = d;
struct i2c_client *ara; struct i2c_client *ara;
unsigned short prev_addr = 0; /* Not a valid address */ unsigned short prev_addr = 0; /* Not a valid address */
alert = container_of(work, struct i2c_smbus_alert, alert);
ara = alert->ara; ara = alert->ara;
for (;;) { for (;;) {
...@@ -115,21 +113,17 @@ static void smbus_alert(struct work_struct *work) ...@@ -115,21 +113,17 @@ static void smbus_alert(struct work_struct *work)
prev_addr = data.addr; prev_addr = data.addr;
} }
/* We handled all alerts; re-enable level-triggered IRQs */ return IRQ_HANDLED;
if (!alert->alert_edge_triggered)
enable_irq(alert->irq);
} }
static irqreturn_t smbalert_irq(int irq, void *d) static void smbalert_work(struct work_struct *work)
{ {
struct i2c_smbus_alert *alert = d; struct i2c_smbus_alert *alert;
/* Disable level-triggered IRQs until we handle them */ alert = container_of(work, struct i2c_smbus_alert, alert);
if (!alert->alert_edge_triggered)
disable_irq_nosync(irq); smbus_alert(0, alert);
schedule_work(&alert->alert);
return IRQ_HANDLED;
} }
/* Setup SMBALERT# infrastructure */ /* Setup SMBALERT# infrastructure */
...@@ -139,28 +133,35 @@ static int smbalert_probe(struct i2c_client *ara, ...@@ -139,28 +133,35 @@ static int smbalert_probe(struct i2c_client *ara,
struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev); struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev);
struct i2c_smbus_alert *alert; struct i2c_smbus_alert *alert;
struct i2c_adapter *adapter = ara->adapter; struct i2c_adapter *adapter = ara->adapter;
int res; int res, irq;
alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert), alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
GFP_KERNEL); GFP_KERNEL);
if (!alert) if (!alert)
return -ENOMEM; return -ENOMEM;
alert->alert_edge_triggered = setup->alert_edge_triggered; if (setup) {
alert->irq = setup->irq; irq = setup->irq;
INIT_WORK(&alert->alert, smbus_alert); } else {
irq = of_irq_get_byname(adapter->dev.of_node, "smbus_alert");
if (irq <= 0)
return irq;
}
INIT_WORK(&alert->alert, smbalert_work);
alert->ara = ara; alert->ara = ara;
if (setup->irq > 0) { if (irq > 0) {
res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq, res = devm_request_threaded_irq(&ara->dev, irq,
0, "smbus_alert", alert); NULL, smbus_alert,
IRQF_SHARED | IRQF_ONESHOT,
"smbus_alert", alert);
if (res) if (res)
return res; return res;
} }
i2c_set_clientdata(ara, alert); i2c_set_clientdata(ara, alert);
dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n", dev_info(&adapter->dev, "supports SMBALERT#\n");
setup->alert_edge_triggered ? "edge" : "level");
return 0; return 0;
} }
...@@ -189,38 +190,6 @@ static struct i2c_driver smbalert_driver = { ...@@ -189,38 +190,6 @@ static struct i2c_driver smbalert_driver = {
.id_table = smbalert_ids, .id_table = smbalert_ids,
}; };
/**
* i2c_setup_smbus_alert - Setup SMBus alert support
* @adapter: the target adapter
* @setup: setup data for the SMBus alert handler
* Context: can sleep
*
* Setup handling of the SMBus alert protocol on a given I2C bus segment.
*
* Handling can be done either through our IRQ handler, or by the
* adapter (from its handler, periodic polling, or whatever).
*
* NOTE that if we manage the IRQ, we *MUST* know if it's level or
* edge triggered in order to hand it to the workqueue correctly.
* If triggering the alert seems to wedge the system, you probably
* should have said it's level triggered.
*
* This returns the ara client, which should be saved for later use with
* i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL
* to indicate an error.
*/
struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
struct i2c_smbus_alert_setup *setup)
{
struct i2c_board_info ara_board_info = {
I2C_BOARD_INFO("smbus_alert", 0x0c),
.platform_data = setup,
};
return i2c_new_device(adapter, &ara_board_info);
}
EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
/** /**
* i2c_handle_smbus_alert - Handle an SMBus alert * i2c_handle_smbus_alert - Handle an SMBus alert
* @ara: the ARA client on the relevant adapter * @ara: the ARA client on the relevant adapter
......
...@@ -246,36 +246,6 @@ static irqreturn_t pca954x_irq_handler(int irq, void *dev_id) ...@@ -246,36 +246,6 @@ static irqreturn_t pca954x_irq_handler(int irq, void *dev_id)
return handled ? IRQ_HANDLED : IRQ_NONE; return handled ? IRQ_HANDLED : IRQ_NONE;
} }
static void pca954x_irq_mask(struct irq_data *idata)
{
struct pca954x *data = irq_data_get_irq_chip_data(idata);
unsigned int pos = idata->hwirq;
unsigned long flags;
raw_spin_lock_irqsave(&data->lock, flags);
data->irq_mask &= ~BIT(pos);
if (!data->irq_mask)
disable_irq(data->client->irq);
raw_spin_unlock_irqrestore(&data->lock, flags);
}
static void pca954x_irq_unmask(struct irq_data *idata)
{
struct pca954x *data = irq_data_get_irq_chip_data(idata);
unsigned int pos = idata->hwirq;
unsigned long flags;
raw_spin_lock_irqsave(&data->lock, flags);
if (!data->irq_mask)
enable_irq(data->client->irq);
data->irq_mask |= BIT(pos);
raw_spin_unlock_irqrestore(&data->lock, flags);
}
static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
{ {
if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW) if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW)
...@@ -285,8 +255,6 @@ static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) ...@@ -285,8 +255,6 @@ static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
static struct irq_chip pca954x_irq_chip = { static struct irq_chip pca954x_irq_chip = {
.name = "i2c-mux-pca954x", .name = "i2c-mux-pca954x",
.irq_mask = pca954x_irq_mask,
.irq_unmask = pca954x_irq_unmask,
.irq_set_type = pca954x_irq_set_type, .irq_set_type = pca954x_irq_set_type,
}; };
...@@ -294,7 +262,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) ...@@ -294,7 +262,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc)
{ {
struct pca954x *data = i2c_mux_priv(muxc); struct pca954x *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client; struct i2c_client *client = data->client;
int c, err, irq; int c, irq;
if (!data->chip->has_irq || client->irq <= 0) if (!data->chip->has_irq || client->irq <= 0)
return 0; return 0;
...@@ -309,29 +277,31 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) ...@@ -309,29 +277,31 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc)
for (c = 0; c < data->chip->nchans; c++) { for (c = 0; c < data->chip->nchans; c++) {
irq = irq_create_mapping(data->irq, c); irq = irq_create_mapping(data->irq, c);
if (!irq) {
dev_err(&client->dev, "failed irq create map\n");
return -EINVAL;
}
irq_set_chip_data(irq, data); irq_set_chip_data(irq, data);
irq_set_chip_and_handler(irq, &pca954x_irq_chip, irq_set_chip_and_handler(irq, &pca954x_irq_chip,
handle_simple_irq); handle_simple_irq);
} }
err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL, return 0;
pca954x_irq_handler, }
IRQF_ONESHOT | IRQF_SHARED,
"pca954x", data);
if (err)
goto err_req_irq;
disable_irq(data->client->irq); static void pca954x_cleanup(struct i2c_mux_core *muxc)
{
struct pca954x *data = i2c_mux_priv(muxc);
int c, irq;
return 0; if (data->irq) {
err_req_irq: for (c = 0; c < data->chip->nchans; c++) {
for (c = 0; c < data->chip->nchans; c++) { irq = irq_find_mapping(data->irq, c);
irq = irq_find_mapping(data->irq, c); irq_dispose_mapping(irq);
irq_dispose_mapping(irq); }
irq_domain_remove(data->irq);
} }
irq_domain_remove(data->irq); i2c_mux_del_adapters(muxc);
return err;
} }
/* /*
...@@ -391,7 +361,7 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -391,7 +361,7 @@ static int pca954x_probe(struct i2c_client *client,
ret = pca954x_irq_setup(muxc); ret = pca954x_irq_setup(muxc);
if (ret) if (ret)
goto fail_del_adapters; goto fail_cleanup;
/* Now create an adapter for each channel */ /* Now create an adapter for each channel */
for (num = 0; num < data->chip->nchans; num++) { for (num = 0; num < data->chip->nchans; num++) {
...@@ -414,7 +384,16 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -414,7 +384,16 @@ static int pca954x_probe(struct i2c_client *client,
ret = i2c_mux_add_adapter(muxc, force, num, class); ret = i2c_mux_add_adapter(muxc, force, num, class);
if (ret) if (ret)
goto fail_del_adapters; goto fail_cleanup;
}
if (data->irq) {
ret = devm_request_threaded_irq(&client->dev, data->client->irq,
NULL, pca954x_irq_handler,
IRQF_ONESHOT | IRQF_SHARED,
"pca954x", data);
if (ret)
goto fail_cleanup;
} }
dev_info(&client->dev, dev_info(&client->dev,
...@@ -424,26 +403,16 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -424,26 +403,16 @@ static int pca954x_probe(struct i2c_client *client,
return 0; return 0;
fail_del_adapters: fail_cleanup:
i2c_mux_del_adapters(muxc); pca954x_cleanup(muxc);
return ret; return ret;
} }
static int pca954x_remove(struct i2c_client *client) static int pca954x_remove(struct i2c_client *client)
{ {
struct i2c_mux_core *muxc = i2c_get_clientdata(client); struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct pca954x *data = i2c_mux_priv(muxc);
int c, irq;
if (data->irq) { pca954x_cleanup(muxc);
for (c = 0; c < data->chip->nchans; c++) {
irq = irq_find_mapping(data->irq, c);
irq_dispose_mapping(irq);
}
irq_domain_remove(data->irq);
}
i2c_mux_del_adapters(muxc);
return 0; return 0;
} }
......
...@@ -184,6 +184,20 @@ config CHARGER_SBS ...@@ -184,6 +184,20 @@ config CHARGER_SBS
help help
Say Y to include support for SBS compilant battery chargers. 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 config BATTERY_BQ27XXX
tristate "BQ27xxx battery driver" tristate "BQ27xxx battery driver"
help help
......
...@@ -36,6 +36,7 @@ obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o ...@@ -36,6 +36,7 @@ obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o
obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o
obj-$(CONFIG_CHARGER_SBS) += sbs-charger.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) += bq27xxx_battery.o
obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o
obj-$(CONFIG_BATTERY_BQ27XXX_HDQ) += bq27xxx_battery_hdq.o obj-$(CONFIG_BATTERY_BQ27XXX_HDQ) += bq27xxx_battery_hdq.o
......
...@@ -177,10 +177,8 @@ static bool force_load; ...@@ -177,10 +177,8 @@ static bool force_load;
static int sbs_read_word_data(struct i2c_client *client, u8 address) static int sbs_read_word_data(struct i2c_client *client, u8 address)
{ {
struct sbs_info *chip = i2c_get_clientdata(client); struct sbs_info *chip = i2c_get_clientdata(client);
int retries = chip->i2c_retry_count;
s32 ret = 0; s32 ret = 0;
int retries = 1;
retries = chip->i2c_retry_count;
while (retries > 0) { while (retries > 0) {
ret = i2c_smbus_read_word_data(client, address); ret = i2c_smbus_read_word_data(client, address);
...@@ -204,7 +202,7 @@ static int sbs_read_string_data(struct i2c_client *client, u8 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); struct sbs_info *chip = i2c_get_clientdata(client);
s32 ret = 0, block_length = 0; 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]; u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
retries_length = chip->i2c_retry_count; retries_length = chip->i2c_retry_count;
...@@ -269,10 +267,8 @@ static int sbs_write_word_data(struct i2c_client *client, u8 address, ...@@ -269,10 +267,8 @@ static int sbs_write_word_data(struct i2c_client *client, u8 address,
u16 value) u16 value)
{ {
struct sbs_info *chip = i2c_get_clientdata(client); struct sbs_info *chip = i2c_get_clientdata(client);
int retries = chip->i2c_retry_count;
s32 ret = 0; s32 ret = 0;
int retries = 1;
retries = chip->i2c_retry_count;
while (retries > 0) { while (retries > 0) {
ret = i2c_smbus_write_word_data(client, address, value); ret = i2c_smbus_write_word_data(client, address, value);
...@@ -321,16 +317,6 @@ static int sbs_get_battery_presence_and_health( ...@@ -321,16 +317,6 @@ static int sbs_get_battery_presence_and_health(
union power_supply_propval *val) union power_supply_propval *val)
{ {
s32 ret; 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 * Write to ManufacturerAccess with ManufacturerAccess command
...@@ -570,7 +556,7 @@ static int sbs_get_battery_serial_number(struct i2c_client *client, ...@@ -570,7 +556,7 @@ static int sbs_get_battery_serial_number(struct i2c_client *client,
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = sprintf(sbs_serial, "%04x", ret); sprintf(sbs_serial, "%04x", ret);
val->strval = sbs_serial; val->strval = sbs_serial;
return 0; return 0;
...@@ -598,6 +584,19 @@ static int sbs_get_property(struct power_supply *psy, ...@@ -598,6 +584,19 @@ static int sbs_get_property(struct power_supply *psy,
struct sbs_info *chip = power_supply_get_drvdata(psy); struct sbs_info *chip = power_supply_get_drvdata(psy);
struct i2c_client *client = chip->client; 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) { switch (psp) {
case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_HEALTH: case POWER_SUPPLY_PROP_HEALTH:
......
This diff is collapsed.
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
* properly set. * properly set.
*/ */
struct i2c_smbus_alert_setup { struct i2c_smbus_alert_setup {
unsigned int alert_edge_triggered:1;
int irq; int irq;
}; };
...@@ -50,4 +49,13 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, ...@@ -50,4 +49,13 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
struct i2c_smbus_alert_setup *setup); struct i2c_smbus_alert_setup *setup);
int i2c_handle_smbus_alert(struct i2c_client *ara); int i2c_handle_smbus_alert(struct i2c_client *ara);
#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF)
int of_i2c_setup_smbus_alert(struct i2c_adapter *adap);
#else
static inline int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
{
return 0;
}
#endif
#endif /* _LINUX_I2C_SMBUS_H */ #endif /* _LINUX_I2C_SMBUS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment