2017-08-01 18:51:09

by Vinay Simha B N

[permalink] [raw]
Subject: [PATCH] power: smb347-charger: Summit SMB358 charger IC

Summit microelectronics' SMB358 charger chip has
almost the same register map and functionality.
voltage and current table are only differed.

SMB345 charger IC tested in nexus7

Cc: John Stultz <[email protected]>
Cc: Sumit Semwal <[email protected]>
Cc: Jonghwa Lee <[email protected]>
Cc: Chanwoo Choi <[email protected]>
Cc: Myungjoo Ham <[email protected]>
Signed-off-by: Vinay Simha BN <[email protected]>

---
v2:
* incorporated code review from Rob Herring
gpio line added for Enable charging control,
documentation bindings (vendor prefixes and unit suffixes)
---
.../bindings/power/supply/smb347_charger.txt | 73 +++++
drivers/power/supply/smb347-charger.c | 334 +++++++++++++--------
include/linux/power/smb347-charger.h | 4 +-
3 files changed, 283 insertions(+), 128 deletions(-)
create mode 100644 Documentation/devicetree/bindings/power/supply/smb347_charger.txt

diff --git a/Documentation/devicetree/bindings/power/supply/smb347_charger.txt b/Documentation/devicetree/bindings/power/supply/smb347_charger.txt
new file mode 100644
index 0000000..45da4ee
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/smb347_charger.txt
@@ -0,0 +1,73 @@
+smb347_charger bindings
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+[Required porperties]
+- compatible : "summit,smb345"
+ "summit,smb347"
+- reg : Slave address for i2c interface
+# At least one of following should be set
+ - enable-usb-charging
+ - enable-otg-charging
+ - enable-mains-charging
+
+[Optional properties]
+- interrupt-parent : The phandle for the interrupt controller
+- interrupts : Interrupt line index for mapping
+- en-gpio : Enable charging control
+ : If this is not specified it will use SW (i2c interface)
+
+# Charging constraints
+- max-chg-curr : microamps for charging Maximum current
+- max-chg-volt : microvolts for charging Maximum voltage
+- pre-chg-curr : microamps for Pre-charging current
+- term-curr : microamps for Charging cycle termination current
+- fast-volt-thershold : microvolts for Voltage threshold to transit to fast charge mode
+- mains-curr-limit : micromaps for Maximum input current from AC/DC input
+- usb-curr-limit : microamps for Maximum input current from USB input
+
+# Related thermometer monitoring (Degrees Celsius)
+- chip-temp-threshold : Chip temperature for thermal regulaton. <100, 130>
+- soft-cold-temp-limit : Cold battery temperature for soft alarm. <0, 15>*
+- soft-hot-temp-limit : Hot battery temperature for soft alarm. <40, 55>
+- hard-cold-temp-limit : Cold battery temperature for hard alarm. <0, 15>*
+- hard-hot-temp-limit : Hot battery temperature for hard alarm. <55, 65>
+(* The written temperature has +5'C offset. 0'C -> -5'C, 15'C -> 10'C)
+- soft-comp-method : Soft temperature limit compensation method
+ (Not defined) : Use default setting
+ <0> : Compensation none
+ <1> : Charge current compensation
+ <2> : Voltage compensation
+
+Example:
+ smb345@6a {
+ compatible = "summit,smb345";
+ reg = <0x6a>;
+ status = "okay";
+ interrupt-parent = <&tlmm_pinmux>;
+ interrupts = <23 IRQ_TYPE_EDGE_BOTH>;
+
+ max-chg-curr = <1800000>;
+ usb-curr-limit = <450000>;
+
+ chip-temp-thershold = <110>; /* celsius */
+
+ enable-usb-charging;
+ enable-otg-charging;
+ };
+
+ smb347@7f {
+ compatible = "summit,smb347";
+ reg = <0x7f>;
+ status = "okay";
+
+ max-chg-curr = <1800000>;
+ mains-curr-limit = <2000000>;
+ usb-curr-limit = <450000>;
+
+ chip-temp-thershold = <110>; /* celsius */
+
+ en-gpios = <&tlmm_pinmux 54 GPIO_ACTIVE_HIGH>;
+
+ enable-usb-charging;
+ enable-mains-charging;
+ };
diff --git a/drivers/power/supply/smb347-charger.c b/drivers/power/supply/smb347-charger.c
index 072c518..28666ab 100644
--- a/drivers/power/supply/smb347-charger.c
+++ b/drivers/power/supply/smb347-charger.c
@@ -124,6 +124,7 @@

/**
* struct smb347_charger - smb347 charger instance
+ * @id: smb charger id
* @lock: protects concurrent access to online variables
* @dev: pointer to device
* @regmap: pointer to driver regmap
@@ -136,7 +137,8 @@
* @pdata: pointer to platform data
*/
struct smb347_charger {
- struct mutex lock;
+ int id;
+ struct mutex lock; /* protects concurrent access */
struct device *dev;
struct regmap *regmap;
struct power_supply *mains;
@@ -145,61 +147,49 @@ struct smb347_charger {
bool mains_online;
bool usb_online;
bool charging_enabled;
- const struct smb347_charger_platform_data *pdata;
+ struct smb347_charger_platform_data *pdata;
+};
+
+enum smb_charger_chipid {
+ SMB345,
+ SMB347,
+ NUM_CHIP_TYPES,
};

/* Fast charge current in uA */
-static const unsigned int fcc_tbl[] = {
- 700000,
- 900000,
- 1200000,
- 1500000,
- 1800000,
- 2000000,
- 2200000,
- 2500000,
+static const unsigned int fcc_tbl[NUM_CHIP_TYPES][8] = {
+ [SMB345] = { 200000, 450000, 600000, 900000,
+ 1300000, 1500000, 1800000, 2000000 },
+ [SMB347] = { 700000, 900000, 1200000, 1500000,
+ 1800000, 2000000, 2200000, 2500000 },
};

/* Pre-charge current in uA */
-static const unsigned int pcc_tbl[] = {
- 100000,
- 150000,
- 200000,
- 250000,
+static const unsigned int pcc_tbl[NUM_CHIP_TYPES][4] = {
+ [SMB345] = { 150000, 250000, 350000, 450000 },
+ [SMB347] = { 100000, 150000, 200000, 250000 },
};

/* Termination current in uA */
-static const unsigned int tc_tbl[] = {
- 37500,
- 50000,
- 100000,
- 150000,
- 200000,
- 250000,
- 500000,
- 600000,
+static const unsigned int tc_tbl[NUM_CHIP_TYPES][8] = {
+ [SMB345] = { 30000, 40000, 60000, 80000,
+ 100000, 125000, 150000, 200000 },
+ [SMB347] = { 37500, 50000, 100000, 150000,
+ 200000, 250000, 500000, 600000 },
};

/* Input current limit in uA */
-static const unsigned int icl_tbl[] = {
- 300000,
- 500000,
- 700000,
- 900000,
- 1200000,
- 1500000,
- 1800000,
- 2000000,
- 2200000,
- 2500000,
+static const unsigned int icl_tbl[NUM_CHIP_TYPES][10] = {
+ [SMB345] = { 300000, 500000, 700000, 1000000, 1500000,
+ 1800000, 2000000, 2000000, 2000000, 2000000 },
+ [SMB347] = { 300000, 500000, 700000, 900000, 1200000,
+ 1500000, 1800000, 2000000, 2200000, 2500000 },
};

/* Charge current compensation in uA */
-static const unsigned int ccc_tbl[] = {
- 250000,
- 700000,
- 900000,
- 1200000,
+static const unsigned int ccc_tbl[NUM_CHIP_TYPES][4] = {
+ [SMB345] = { 200000, 450000, 600000, 900000 },
+ [SMB347] = { 250000, 700000, 900000, 1200000 },
};

/* Convert register value to current using lookup table */
@@ -354,10 +344,10 @@ static int smb347_start_stop_charging(struct smb347_charger *smb)

static int smb347_set_charge_current(struct smb347_charger *smb)
{
- int ret;
+ int ret, id = smb->id;

if (smb->pdata->max_charge_current) {
- ret = current_to_hw(fcc_tbl, ARRAY_SIZE(fcc_tbl),
+ ret = current_to_hw(fcc_tbl[id], ARRAY_SIZE(fcc_tbl[id]),
smb->pdata->max_charge_current);
if (ret < 0)
return ret;
@@ -370,7 +360,7 @@ static int smb347_set_charge_current(struct smb347_charger *smb)
}

if (smb->pdata->pre_charge_current) {
- ret = current_to_hw(pcc_tbl, ARRAY_SIZE(pcc_tbl),
+ ret = current_to_hw(pcc_tbl[id], ARRAY_SIZE(pcc_tbl[id]),
smb->pdata->pre_charge_current);
if (ret < 0)
return ret;
@@ -383,7 +373,7 @@ static int smb347_set_charge_current(struct smb347_charger *smb)
}

if (smb->pdata->termination_current) {
- ret = current_to_hw(tc_tbl, ARRAY_SIZE(tc_tbl),
+ ret = current_to_hw(tc_tbl[id], ARRAY_SIZE(tc_tbl[id]),
smb->pdata->termination_current);
if (ret < 0)
return ret;
@@ -399,10 +389,10 @@ static int smb347_set_charge_current(struct smb347_charger *smb)

static int smb347_set_current_limits(struct smb347_charger *smb)
{
- int ret;
+ int ret, id = smb->id;

if (smb->pdata->mains_current_limit) {
- ret = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl),
+ ret = current_to_hw(icl_tbl[id], ARRAY_SIZE(icl_tbl[id]),
smb->pdata->mains_current_limit);
if (ret < 0)
return ret;
@@ -415,7 +405,7 @@ static int smb347_set_current_limits(struct smb347_charger *smb)
}

if (smb->pdata->usb_hc_current_limit) {
- ret = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl),
+ ret = current_to_hw(icl_tbl[id], ARRAY_SIZE(icl_tbl[id]),
smb->pdata->usb_hc_current_limit);
if (ret < 0)
return ret;
@@ -440,9 +430,10 @@ static int smb347_set_voltage_limits(struct smb347_charger *smb)
ret = clamp_val(ret, 2400000, 3000000) - 2400000;
ret /= 200000;

- ret = regmap_update_bits(smb->regmap, CFG_FLOAT_VOLTAGE,
- CFG_FLOAT_VOLTAGE_THRESHOLD_MASK,
- ret << CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT);
+ ret = regmap_update_bits
+ (smb->regmap, CFG_FLOAT_VOLTAGE,
+ CFG_FLOAT_VOLTAGE_THRESHOLD_MASK,
+ ret << CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT);
if (ret < 0)
return ret;
}
@@ -467,7 +458,7 @@ static int smb347_set_temp_limits(struct smb347_charger *smb)
{
bool enable_therm_monitor = false;
int ret = 0;
- int val;
+ int val, id = smb->id;

if (smb->pdata->chip_temp_threshold) {
val = smb->pdata->chip_temp_threshold;
@@ -565,8 +556,9 @@ static int smb347_set_temp_limits(struct smb347_charger *smb)
}

if (smb->pdata->suspend_on_hard_temp_limit) {
- ret = regmap_update_bits(smb->regmap, CFG_SYSOK,
- CFG_SYSOK_SUSPEND_HARD_LIMIT_DISABLED, 0);
+ ret = regmap_update_bits
+ (smb->regmap, CFG_SYSOK,
+ CFG_SYSOK_SUSPEND_HARD_LIMIT_DISABLED, 0);
if (ret < 0)
return ret;
}
@@ -575,28 +567,31 @@ static int smb347_set_temp_limits(struct smb347_charger *smb)
SMB347_SOFT_TEMP_COMPENSATE_DEFAULT) {
val = smb->pdata->soft_temp_limit_compensation & 0x3;

- ret = regmap_update_bits(smb->regmap, CFG_THERM,
- CFG_THERM_SOFT_HOT_COMPENSATION_MASK,
- val << CFG_THERM_SOFT_HOT_COMPENSATION_SHIFT);
+ ret = regmap_update_bits
+ (smb->regmap, CFG_THERM,
+ CFG_THERM_SOFT_HOT_COMPENSATION_MASK,
+ val << CFG_THERM_SOFT_HOT_COMPENSATION_SHIFT);
if (ret < 0)
return ret;

- ret = regmap_update_bits(smb->regmap, CFG_THERM,
- CFG_THERM_SOFT_COLD_COMPENSATION_MASK,
- val << CFG_THERM_SOFT_COLD_COMPENSATION_SHIFT);
+ ret = regmap_update_bits
+ (smb->regmap, CFG_THERM,
+ CFG_THERM_SOFT_COLD_COMPENSATION_MASK,
+ val << CFG_THERM_SOFT_COLD_COMPENSATION_SHIFT);
if (ret < 0)
return ret;
}

if (smb->pdata->charge_current_compensation) {
- val = current_to_hw(ccc_tbl, ARRAY_SIZE(ccc_tbl),
+ val = current_to_hw(ccc_tbl[id], ARRAY_SIZE(ccc_tbl[id]),
smb->pdata->charge_current_compensation);
if (val < 0)
return val;

- ret = regmap_update_bits(smb->regmap, CFG_OTG,
- CFG_OTG_CC_COMPENSATION_MASK,
- (val & 0x3) << CFG_OTG_CC_COMPENSATION_SHIFT);
+ ret = regmap_update_bits
+ (smb->regmap, CFG_OTG,
+ CFG_OTG_CC_COMPENSATION_MASK,
+ (val & 0x3) << CFG_OTG_CC_COMPENSATION_SHIFT);
if (ret < 0)
return ret;
}
@@ -662,7 +657,8 @@ static int smb347_hw_init(struct smb347_charger *smb)
* support for driving VBUS. Otherwise we disable it.
*/
ret = regmap_update_bits(smb->regmap, CFG_OTHER, CFG_OTHER_RID_MASK,
- smb->pdata->use_usb_otg ? CFG_OTHER_RID_ENABLED_AUTO_OTG : 0);
+ smb->pdata->use_usb_otg ?
+ CFG_OTHER_RID_ENABLED_AUTO_OTG : 0);
if (ret < 0)
goto fail;

@@ -723,10 +719,12 @@ static irqreturn_t smb347_interrupt(int irq, void *data)
return IRQ_NONE;
}

- ret = regmap_read(smb->regmap, IRQSTAT_D, &irqstat_d);
- if (ret < 0) {
- dev_warn(smb->dev, "reading IRQSTAT_D failed\n");
- return IRQ_NONE;
+ if (smb->id != SMB345) {
+ ret = regmap_read(smb->regmap, IRQSTAT_D, &irqstat_d);
+ if (ret < 0) {
+ dev_warn(smb->dev, "reading IRQSTAT_D failed\n");
+ return IRQ_NONE;
+ }
}

ret = regmap_read(smb->regmap, IRQSTAT_E, &irqstat_e);
@@ -761,13 +759,15 @@ static irqreturn_t smb347_interrupt(int irq, void *data)
* If we got a charger timeout INT that means the charge
* full is not detected with in charge timeout value.
*/
- if (irqstat_d & IRQSTAT_D_CHARGE_TIMEOUT_IRQ) {
- dev_dbg(smb->dev, "total Charge Timeout INT received\n");
+ if (smb->id != SMB345) {
+ if (irqstat_d & IRQSTAT_D_CHARGE_TIMEOUT_IRQ) {
+ dev_dbg(smb->dev, "total Charge Timeout INT received\n");

- if (irqstat_d & IRQSTAT_D_CHARGE_TIMEOUT_STAT)
- dev_warn(smb->dev, "charging stopped due to timeout\n");
- power_supply_changed(smb->battery);
- handled = true;
+ if (irqstat_d & IRQSTAT_D_CHARGE_TIMEOUT_STAT)
+ dev_warn(smb->dev, "charging stopped due to timeout\n");
+ power_supply_changed(smb->battery);
+ handled = true;
+ }
}

/*
@@ -809,7 +809,7 @@ static int smb347_irq_set(struct smb347_charger *smb, bool enable)
goto fail;

ret = regmap_update_bits(smb->regmap, CFG_STATUS_IRQ, 0xff,
- enable ? (CFG_STATUS_IRQ_TERMINATION_OR_TAPER |
+ enable ? (CFG_STATUS_IRQ_TERMINATION_OR_TAPER |
CFG_STATUS_IRQ_CHARGE_TIMEOUT) : 0);
if (ret < 0)
goto fail;
@@ -834,22 +834,22 @@ static inline int smb347_irq_disable(struct smb347_charger *smb)
static int smb347_irq_init(struct smb347_charger *smb,
struct i2c_client *client)
{
- const struct smb347_charger_platform_data *pdata = smb->pdata;
- int ret, irq = gpio_to_irq(pdata->irq_gpio);
+ int ret;
+ unsigned long irqflags;

- ret = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name);
- if (ret < 0)
- goto fail;
+ irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING;
+
+ ret = devm_request_threaded_irq(smb->dev, client->irq, NULL,
+ smb347_interrupt, irqflags |
+ IRQF_ONESHOT,
+ client->name, smb);

- ret = request_threaded_irq(irq, NULL, smb347_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- client->name, smb);
if (ret < 0)
- goto fail_gpio;
+ goto out;

ret = smb347_set_writable(smb, true);
if (ret < 0)
- goto fail_irq;
+ goto out;

/*
* Configure the STAT output to be suitable for interrupts: disable
@@ -859,20 +859,10 @@ static int smb347_irq_init(struct smb347_charger *smb,
CFG_STAT_ACTIVE_HIGH | CFG_STAT_DISABLED,
CFG_STAT_DISABLED);
if (ret < 0)
- goto fail_readonly;
-
- smb347_set_writable(smb, false);
- client->irq = irq;
- return 0;
+ client->irq = 0;

-fail_readonly:
smb347_set_writable(smb, false);
-fail_irq:
- free_irq(irq, smb);
-fail_gpio:
- gpio_free(pdata->irq_gpio);
-fail:
- client->irq = 0;
+out:
return ret;
}

@@ -882,7 +872,7 @@ static int smb347_irq_init(struct smb347_charger *smb,
*/
static int get_const_charge_current(struct smb347_charger *smb)
{
- int ret, intval;
+ int ret, intval, id = smb->id;
unsigned int v;

if (!smb347_is_ps_online(smb))
@@ -897,10 +887,12 @@ static int get_const_charge_current(struct smb347_charger *smb)
* and we can detect which table to use from bit 5.
*/
if (v & 0x20) {
- intval = hw_to_current(fcc_tbl, ARRAY_SIZE(fcc_tbl), v & 7);
+ intval = hw_to_current(fcc_tbl[id],
+ ARRAY_SIZE(fcc_tbl[id]), v & 7);
} else {
v >>= 3;
- intval = hw_to_current(pcc_tbl, ARRAY_SIZE(pcc_tbl), v & 7);
+ intval = hw_to_current(pcc_tbl[id],
+ ARRAY_SIZE(pcc_tbl[id]), v & 7);
}

return intval;
@@ -947,16 +939,14 @@ static int smb347_mains_get_property(struct power_supply *psy,
ret = get_const_charge_voltage(smb);
if (ret < 0)
return ret;
- else
- val->intval = ret;
+ val->intval = ret;
break;

case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
ret = get_const_charge_current(smb);
if (ret < 0)
return ret;
- else
- val->intval = ret;
+ val->intval = ret;
break;

default:
@@ -988,16 +978,14 @@ static int smb347_usb_get_property(struct power_supply *psy,
ret = get_const_charge_voltage(smb);
if (ret < 0)
return ret;
- else
- val->intval = ret;
+ val->intval = ret;
break;

case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
ret = get_const_charge_current(smb);
if (ret < 0)
return ret;
- else
- val->intval = ret;
+ val->intval = ret;
break;

default:
@@ -1026,7 +1014,7 @@ static int smb347_get_charging_status(struct smb347_charger *smb)
return ret;

if ((val & STAT_C_CHARGER_ERROR) ||
- (val & STAT_C_HOLDOFF_STAT)) {
+ (val & STAT_C_HOLDOFF_STAT)) {
/*
* set to NOT CHARGING upon charger error
* or charging has stopped.
@@ -1049,7 +1037,7 @@ static int smb347_get_charging_status(struct smb347_charger *smb)
} else {
/*
* in this case no charger error or termination
- * occured but charging is not in progress!!!
+ * occurred but charging is not in progress!!!
*/
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
}
@@ -1178,6 +1166,75 @@ static bool smb347_readable_reg(struct device *dev, unsigned int reg)
return smb347_volatile_reg(dev, reg);
}

+static void smb347_dt_parse_pdata(struct device_node *np,
+ struct smb347_charger_platform_data *pdata)
+{
+ /* Charing constraints */
+ of_property_read_u32(np, "max-chg-curr", &pdata->max_charge_current);
+ of_property_read_u32(np, "max-chg-volt", &pdata->max_charge_voltage);
+ of_property_read_u32(np, "pre-chg-curr", &pdata->pre_charge_current);
+ of_property_read_u32(np, "term-curr", &pdata->termination_current);
+ of_property_read_u32(np, "fast-volt-threshold",
+ &pdata->pre_to_fast_voltage);
+ of_property_read_u32(np, "mains-curr-limit",
+ &pdata->mains_current_limit);
+ of_property_read_u32(np, "usb-curr-limit",
+ &pdata->usb_hc_current_limit);
+
+ /* For thermometer monitoring */
+ of_property_read_u32(np, "chip-temp-threshold",
+ &pdata->chip_temp_threshold);
+ if (of_property_read_u32(np, "soft-cold-temp-limit",
+ &pdata->soft_cold_temp_limit))
+ pdata->soft_cold_temp_limit = SMB347_TEMP_USE_DEFAULT;
+ if (of_property_read_u32(np, "soft-hot-temp-limit",
+ &pdata->soft_hot_temp_limit))
+ pdata->soft_hot_temp_limit = SMB347_TEMP_USE_DEFAULT;
+ if (of_property_read_u32(np, "hard-cold-temp-limit",
+ &pdata->hard_cold_temp_limit))
+ pdata->hard_cold_temp_limit = SMB347_TEMP_USE_DEFAULT;
+ if (of_property_read_u32(np, "hard-hot-temp-limit",
+ &pdata->hard_hot_temp_limit))
+ pdata->hard_hot_temp_limit = SMB347_TEMP_USE_DEFAULT;
+
+ /* Suspend when battery temperature is outside hard limits */
+ if ((pdata->hard_cold_temp_limit != SMB347_TEMP_USE_DEFAULT) ||
+ (pdata->hard_hot_temp_limit != SMB347_TEMP_USE_DEFAULT))
+ pdata->suspend_on_hard_temp_limit = true;
+
+ if (of_property_read_u32(np, "soft-comp-method",
+ &pdata->soft_temp_limit_compensation))
+ pdata->soft_temp_limit_compensation =
+ SMB347_SOFT_TEMP_COMPENSATE_DEFAULT;
+
+ of_property_read_u32(np, "chg-curr-comp",
+ &pdata->charge_current_compensation);
+
+ /* Supported charging mode */
+ pdata->use_mains = of_property_read_bool(np, "enable-mains-charging");
+ pdata->use_usb = of_property_read_bool(np, "enable-usb-charging");
+ pdata->use_usb_otg = of_property_read_bool(np, "enable-otg-charging");
+
+ /* If IRQ is enabled or not */
+ if (!of_get_property(np, "interrupts", NULL))
+ pdata->irq_gpio = -1;
+}
+
+static struct smb347_charger_platform_data
+ *smb347_get_platdata(struct device *dev)
+{
+ struct smb347_charger_platform_data *pdata = NULL;
+
+ if (dev->of_node) {
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ smb347_dt_parse_pdata(dev->of_node, pdata);
+ } else {
+ pdata = dev_get_platdata(dev);
+ }
+
+ return pdata;
+}
+
static const struct regmap_config smb347_regmap = {
.reg_bits = 8,
.val_bits = 8,
@@ -1210,32 +1267,34 @@ static const struct power_supply_desc smb347_battery_desc = {
.num_properties = ARRAY_SIZE(smb347_battery_properties),
};

+static char *battery[] = {
+ "smb347-battery",
+};
+
static int smb347_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- static char *battery[] = { "smb347-battery" };
- const struct smb347_charger_platform_data *pdata;
struct power_supply_config mains_usb_cfg = {}, battery_cfg = {};
struct device *dev = &client->dev;
struct smb347_charger *smb;
int ret;

- pdata = dev->platform_data;
- if (!pdata)
- return -EINVAL;
-
- if (!pdata->use_mains && !pdata->use_usb)
- return -EINVAL;
-
smb = devm_kzalloc(dev, sizeof(*smb), GFP_KERNEL);
if (!smb)
return -ENOMEM;

+ smb->pdata = smb347_get_platdata(dev);
+ if (IS_ERR_OR_NULL(smb->pdata))
+ return -ENODEV;
+
+ if (!smb->pdata->use_mains && !smb->pdata->use_usb)
+ return -EINVAL;
+
i2c_set_clientdata(client, smb);

mutex_init(&smb->lock);
+ smb->id = id->driver_data;
smb->dev = &client->dev;
- smb->pdata = pdata;

smb->regmap = devm_regmap_init_i2c(client, &smb347_regmap);
if (IS_ERR(smb->regmap))
@@ -1277,10 +1336,24 @@ static int smb347_probe(struct i2c_client *client,
}

/*
+ * EN - enable input can be controlled by i2c or gpio.
+ */
+ smb->pdata->en_gpio = devm_gpiod_get(dev, "en", GPIOD_OUT_HIGH);
+ if (IS_ERR(smb->pdata->en_gpio)) {
+ ret = PTR_ERR(smb->pdata->en_gpio);
+ dev_err(dev, "cannot get en-gpio %d\n", ret);
+ dev_dbg(smb->dev, "charging enable/disable in SW enabled\n");
+
+ smb->pdata->enable_control = SMB347_CHG_ENABLE_SW;
+ } else {
+ smb->pdata->enable_control = SMB347_CHG_ENABLE_PIN_ACTIVE_HIGH;
+ }
+
+ /*
* Interrupt pin is optional. If it is connected, we setup the
* interrupt support here.
*/
- if (pdata->irq_gpio >= 0) {
+ if (smb->pdata->irq_gpio >= 0) {
ret = smb347_irq_init(smb, client);
if (ret < 0) {
dev_warn(dev, "failed to initialize IRQ: %d\n", ret);
@@ -1297,11 +1370,8 @@ static int smb347_remove(struct i2c_client *client)
{
struct smb347_charger *smb = i2c_get_clientdata(client);

- if (client->irq) {
+ if (client->irq)
smb347_irq_disable(smb);
- free_irq(client->irq, smb);
- gpio_free(smb->pdata->irq_gpio);
- }

power_supply_unregister(smb->battery);
if (smb->pdata->use_usb)
@@ -1312,14 +1382,24 @@ static int smb347_remove(struct i2c_client *client)
}

static const struct i2c_device_id smb347_id[] = {
- { "smb347", 0 },
+ { "smb345", SMB345 },
+ { "smb347", SMB347 },
{ }
};
MODULE_DEVICE_TABLE(i2c, smb347_id);

+#ifdef CONFIG_OF
+static const struct of_device_id of_smb347_ids[] = {
+ { .compatible = "summit,smb345" },
+ { .compatible = "summit,smb347" },
+ {},
+};
+#endif
+
static struct i2c_driver smb347_driver = {
.driver = {
.name = "smb347",
+ .of_match_table = of_match_ptr(of_smb347_ids),
},
.probe = smb347_probe,
.remove = smb347_remove,
diff --git a/include/linux/power/smb347-charger.h b/include/linux/power/smb347-charger.h
index b3cb20d..7bdc709 100644
--- a/include/linux/power/smb347-charger.h
+++ b/include/linux/power/smb347-charger.h
@@ -47,7 +47,7 @@ enum smb347_chg_enable {
* @pre_charge_current: current (in uA) to use in pre-charging phase
* @termination_current: current (in uA) used to determine when the
* charging cycle terminates
- * @pre_to_fast_voltage: voltage (in uV) treshold used for transitioning to
+ * @pre_to_fast_voltage: voltage (in uV) threshold used for transitioning to
* pre-charge to fast charge mode
* @mains_current_limit: maximum input current drawn from AC/DC input (in uA)
* @usb_hc_current_limit: maximum input high current (in uA) drawn from USB
@@ -71,6 +71,7 @@ enum smb347_chg_enable {
* @use_usb: USB input can be used
* @use_usb_otg: USB OTG output can be used (not implemented yet)
* @irq_gpio: GPIO number used for interrupts (%-1 if not used)
+ * @en_gpio: GPIO used for Enable input
* @enable_control: how charging enable/disable is controlled
* (driver/pin controls)
*
@@ -111,6 +112,7 @@ struct smb347_charger_platform_data {
bool use_usb;
bool use_usb_otg;
int irq_gpio;
+ struct gpio_desc *en_gpio;
enum smb347_chg_enable enable_control;
};

--
2.1.2


2017-08-02 21:58:58

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] power: smb347-charger: Summit SMB358 charger IC

Hi Vinay,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.13-rc3 next-20170802]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Vinay-Simha-BN/power-smb347-charger-Summit-SMB358-charger-IC/20170802-054147
config: x86_64-randconfig-b0-08030519 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64

All errors (new ones prefixed by >>):

drivers/power/supply/smb347-charger.c: In function 'smb347_probe':
>> drivers/power/supply/smb347-charger.c:1341:24: error: implicit declaration of function 'devm_gpiod_get' [-Werror=implicit-function-declaration]
smb->pdata->en_gpio = devm_gpiod_get(dev, "en", GPIOD_OUT_HIGH);
^~~~~~~~~~~~~~
>> drivers/power/supply/smb347-charger.c:1341:50: error: 'GPIOD_OUT_HIGH' undeclared (first use in this function)
smb->pdata->en_gpio = devm_gpiod_get(dev, "en", GPIOD_OUT_HIGH);
^~~~~~~~~~~~~~
drivers/power/supply/smb347-charger.c:1341:50: note: each undeclared identifier is reported only once for each function it appears in
cc1: some warnings being treated as errors

vim +/devm_gpiod_get +1341 drivers/power/supply/smb347-charger.c

1273
1274 static int smb347_probe(struct i2c_client *client,
1275 const struct i2c_device_id *id)
1276 {
1277 struct power_supply_config mains_usb_cfg = {}, battery_cfg = {};
1278 struct device *dev = &client->dev;
1279 struct smb347_charger *smb;
1280 int ret;
1281
1282 smb = devm_kzalloc(dev, sizeof(*smb), GFP_KERNEL);
1283 if (!smb)
1284 return -ENOMEM;
1285
1286 smb->pdata = smb347_get_platdata(dev);
1287 if (IS_ERR_OR_NULL(smb->pdata))
1288 return -ENODEV;
1289
1290 if (!smb->pdata->use_mains && !smb->pdata->use_usb)
1291 return -EINVAL;
1292
1293 i2c_set_clientdata(client, smb);
1294
1295 mutex_init(&smb->lock);
1296 smb->id = id->driver_data;
1297 smb->dev = &client->dev;
1298
1299 smb->regmap = devm_regmap_init_i2c(client, &smb347_regmap);
1300 if (IS_ERR(smb->regmap))
1301 return PTR_ERR(smb->regmap);
1302
1303 ret = smb347_hw_init(smb);
1304 if (ret < 0)
1305 return ret;
1306
1307 mains_usb_cfg.supplied_to = battery;
1308 mains_usb_cfg.num_supplicants = ARRAY_SIZE(battery);
1309 mains_usb_cfg.drv_data = smb;
1310 if (smb->pdata->use_mains) {
1311 smb->mains = power_supply_register(dev, &smb347_mains_desc,
1312 &mains_usb_cfg);
1313 if (IS_ERR(smb->mains))
1314 return PTR_ERR(smb->mains);
1315 }
1316
1317 if (smb->pdata->use_usb) {
1318 smb->usb = power_supply_register(dev, &smb347_usb_desc,
1319 &mains_usb_cfg);
1320 if (IS_ERR(smb->usb)) {
1321 if (smb->pdata->use_mains)
1322 power_supply_unregister(smb->mains);
1323 return PTR_ERR(smb->usb);
1324 }
1325 }
1326
1327 battery_cfg.drv_data = smb;
1328 smb->battery = power_supply_register(dev, &smb347_battery_desc,
1329 &battery_cfg);
1330 if (IS_ERR(smb->battery)) {
1331 if (smb->pdata->use_usb)
1332 power_supply_unregister(smb->usb);
1333 if (smb->pdata->use_mains)
1334 power_supply_unregister(smb->mains);
1335 return PTR_ERR(smb->battery);
1336 }
1337
1338 /*
1339 * EN - enable input can be controlled by i2c or gpio.
1340 */
> 1341 smb->pdata->en_gpio = devm_gpiod_get(dev, "en", GPIOD_OUT_HIGH);
1342 if (IS_ERR(smb->pdata->en_gpio)) {
1343 ret = PTR_ERR(smb->pdata->en_gpio);
1344 dev_err(dev, "cannot get en-gpio %d\n", ret);
1345 dev_dbg(smb->dev, "charging enable/disable in SW enabled\n");
1346
1347 smb->pdata->enable_control = SMB347_CHG_ENABLE_SW;
1348 } else {
1349 smb->pdata->enable_control = SMB347_CHG_ENABLE_PIN_ACTIVE_HIGH;
1350 }
1351
1352 /*
1353 * Interrupt pin is optional. If it is connected, we setup the
1354 * interrupt support here.
1355 */
1356 if (smb->pdata->irq_gpio >= 0) {
1357 ret = smb347_irq_init(smb, client);
1358 if (ret < 0) {
1359 dev_warn(dev, "failed to initialize IRQ: %d\n", ret);
1360 dev_warn(dev, "disabling IRQ support\n");
1361 } else {
1362 smb347_irq_enable(smb);
1363 }
1364 }
1365
1366 return 0;
1367 }
1368

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (4.56 kB)
.config.gz (23.23 kB)
Download all attachments

2017-08-07 06:53:03

by Vinay Simha B N

[permalink] [raw]
Subject: Re: [PATCH] power: smb347-charger: Summit SMB358 charger IC

In the config attached. CONFIG_GPIOLIB is not set. please set and recompile

fyi,
devm_gpiod_get() declared in drivers/gpio/devres.c -> CONFIG_GPIOLIB

On Thu, Aug 3, 2017 at 3:28 AM, kbuild test robot <[email protected]> wrote:
>
> Hi Vinay,
>
> [auto build test ERROR on linus/master]
> [also build test ERROR on v4.13-rc3 next-20170802]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url: https://github.com/0day-ci/linux/commits/Vinay-Simha-BN/power-smb347-charger-Summit-SMB358-charger-IC/20170802-054147
> config: x86_64-randconfig-b0-08030519 (attached as .config)
> compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=x86_64
>
> All errors (new ones prefixed by >>):
>
> drivers/power/supply/smb347-charger.c: In function 'smb347_probe':
> >> drivers/power/supply/smb347-charger.c:1341:24: error: implicit declaration of function 'devm_gpiod_get' [-Werror=implicit-function-declaration]
> smb->pdata->en_gpio = devm_gpiod_get(dev, "en", GPIOD_OUT_HIGH);
> ^~~~~~~~~~~~~~
> >> drivers/power/supply/smb347-charger.c:1341:50: error: 'GPIOD_OUT_HIGH' undeclared (first use in this function)
> smb->pdata->en_gpio = devm_gpiod_get(dev, "en", GPIOD_OUT_HIGH);
> ^~~~~~~~~~~~~~
> drivers/power/supply/smb347-charger.c:1341:50: note: each undeclared identifier is reported only once for each function it appears in
> cc1: some warnings being treated as errors
>
> vim +/devm_gpiod_get +1341 drivers/power/supply/smb347-charger.c
>
> 1273
> 1274 static int smb347_probe(struct i2c_client *client,
> 1275 const struct i2c_device_id *id)
> 1276 {
> 1277 struct power_supply_config mains_usb_cfg = {}, battery_cfg = {};
> 1278 struct device *dev = &client->dev;
> 1279 struct smb347_charger *smb;
> 1280 int ret;
> 1281
> 1282 smb = devm_kzalloc(dev, sizeof(*smb), GFP_KERNEL);
> 1283 if (!smb)
> 1284 return -ENOMEM;
> 1285
> 1286 smb->pdata = smb347_get_platdata(dev);
> 1287 if (IS_ERR_OR_NULL(smb->pdata))
> 1288 return -ENODEV;
> 1289
> 1290 if (!smb->pdata->use_mains && !smb->pdata->use_usb)
> 1291 return -EINVAL;
> 1292
> 1293 i2c_set_clientdata(client, smb);
> 1294
> 1295 mutex_init(&smb->lock);
> 1296 smb->id = id->driver_data;
> 1297 smb->dev = &client->dev;
> 1298
> 1299 smb->regmap = devm_regmap_init_i2c(client, &smb347_regmap);
> 1300 if (IS_ERR(smb->regmap))
> 1301 return PTR_ERR(smb->regmap);
> 1302
> 1303 ret = smb347_hw_init(smb);
> 1304 if (ret < 0)
> 1305 return ret;
> 1306
> 1307 mains_usb_cfg.supplied_to = battery;
> 1308 mains_usb_cfg.num_supplicants = ARRAY_SIZE(battery);
> 1309 mains_usb_cfg.drv_data = smb;
> 1310 if (smb->pdata->use_mains) {
> 1311 smb->mains = power_supply_register(dev, &smb347_mains_desc,
> 1312 &mains_usb_cfg);
> 1313 if (IS_ERR(smb->mains))
> 1314 return PTR_ERR(smb->mains);
> 1315 }
> 1316
> 1317 if (smb->pdata->use_usb) {
> 1318 smb->usb = power_supply_register(dev, &smb347_usb_desc,
> 1319 &mains_usb_cfg);
> 1320 if (IS_ERR(smb->usb)) {
> 1321 if (smb->pdata->use_mains)
> 1322 power_supply_unregister(smb->mains);
> 1323 return PTR_ERR(smb->usb);
> 1324 }
> 1325 }
> 1326
> 1327 battery_cfg.drv_data = smb;
> 1328 smb->battery = power_supply_register(dev, &smb347_battery_desc,
> 1329 &battery_cfg);
> 1330 if (IS_ERR(smb->battery)) {
> 1331 if (smb->pdata->use_usb)
> 1332 power_supply_unregister(smb->usb);
> 1333 if (smb->pdata->use_mains)
> 1334 power_supply_unregister(smb->mains);
> 1335 return PTR_ERR(smb->battery);
> 1336 }
> 1337
> 1338 /*
> 1339 * EN - enable input can be controlled by i2c or gpio.
> 1340 */
> > 1341 smb->pdata->en_gpio = devm_gpiod_get(dev, "en", GPIOD_OUT_HIGH);
> 1342 if (IS_ERR(smb->pdata->en_gpio)) {
> 1343 ret = PTR_ERR(smb->pdata->en_gpio);
> 1344 dev_err(dev, "cannot get en-gpio %d\n", ret);
> 1345 dev_dbg(smb->dev, "charging enable/disable in SW enabled\n");
> 1346
> 1347 smb->pdata->enable_control = SMB347_CHG_ENABLE_SW;
> 1348 } else {
> 1349 smb->pdata->enable_control = SMB347_CHG_ENABLE_PIN_ACTIVE_HIGH;
> 1350 }
> 1351
> 1352 /*
> 1353 * Interrupt pin is optional. If it is connected, we setup the
> 1354 * interrupt support here.
> 1355 */
> 1356 if (smb->pdata->irq_gpio >= 0) {
> 1357 ret = smb347_irq_init(smb, client);
> 1358 if (ret < 0) {
> 1359 dev_warn(dev, "failed to initialize IRQ: %d\n", ret);
> 1360 dev_warn(dev, "disabling IRQ support\n");
> 1361 } else {
> 1362 smb347_irq_enable(smb);
> 1363 }
> 1364 }
> 1365
> 1366 return 0;
> 1367 }
> 1368
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all Intel Corporation




--
regards,
vinaysimha

2017-08-10 15:30:18

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH] power: smb347-charger: Summit SMB358 charger IC

On Wed, Aug 02, 2017 at 12:20:26AM +0530, Vinay Simha BN wrote:
> Summit microelectronics' SMB358 charger chip has
> almost the same register map and functionality.
> voltage and current table are only differed.
>
> SMB345 charger IC tested in nexus7
>
> Cc: John Stultz <[email protected]>
> Cc: Sumit Semwal <[email protected]>
> Cc: Jonghwa Lee <[email protected]>
> Cc: Chanwoo Choi <[email protected]>
> Cc: Myungjoo Ham <[email protected]>
> Signed-off-by: Vinay Simha BN <[email protected]>
>
> ---
> v2:
> * incorporated code review from Rob Herring
> gpio line added for Enable charging control,
> documentation bindings (vendor prefixes and unit suffixes)
> ---
> .../bindings/power/supply/smb347_charger.txt | 73 +++++

Please split binding to a separate patch.

> drivers/power/supply/smb347-charger.c | 334 +++++++++++++--------
> include/linux/power/smb347-charger.h | 4 +-
> 3 files changed, 283 insertions(+), 128 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/power/supply/smb347_charger.txt
>
> diff --git a/Documentation/devicetree/bindings/power/supply/smb347_charger.txt b/Documentation/devicetree/bindings/power/supply/smb347_charger.txt
> new file mode 100644
> index 0000000..45da4ee
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/supply/smb347_charger.txt
> @@ -0,0 +1,73 @@
> +smb347_charger bindings
> +~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +[Required porperties]
> +- compatible : "summit,smb345"
> + "summit,smb347"
> +- reg : Slave address for i2c interface
> +# At least one of following should be set
> + - enable-usb-charging
> + - enable-otg-charging
> + - enable-mains-charging

As I wrote last time, I don't think these belong in DT.

> +
> +[Optional properties]
> +- interrupt-parent : The phandle for the interrupt controller
> +- interrupts : Interrupt line index for mapping
> +- en-gpio : Enable charging control

enable-gpios

> + : If this is not specified it will use SW (i2c interface)
> +
> +# Charging constraints
> +- max-chg-curr : microamps for charging Maximum current
> +- max-chg-volt : microvolts for charging Maximum voltage
> +- pre-chg-curr : microamps for Pre-charging current
> +- term-curr : microamps for Charging cycle termination current
> +- fast-volt-thershold : microvolts for Voltage threshold to transit to fast charge mode
> +- mains-curr-limit : micromaps for Maximum input current from AC/DC input
> +- usb-curr-limit : microamps for Maximum input current from USB input

These are all properties of the battery, not the charger. See
.../power/supply/battery.txt.

> +
> +# Related thermometer monitoring (Degrees Celsius)
> +- chip-temp-threshold : Chip temperature for thermal regulaton. <100, 130>
> +- soft-cold-temp-limit : Cold battery temperature for soft alarm. <0, 15>*
> +- soft-hot-temp-limit : Hot battery temperature for soft alarm. <40, 55>
> +- hard-cold-temp-limit : Cold battery temperature for hard alarm. <0, 15>*
> +- hard-hot-temp-limit : Hot battery temperature for hard alarm. <55, 65>
> +(* The written temperature has +5'C offset. 0'C -> -5'C, 15'C -> 10'C)

These too should probably be common. If not they need vendor prefix and
unit suffix. See property-units.txt.

> +- soft-comp-method : Soft temperature limit compensation method
> + (Not defined) : Use default setting
> + <0> : Compensation none
> + <1> : Charge current compensation
> + <2> : Voltage compensation
> +
> +Example:
> + smb345@6a {
> + compatible = "summit,smb345";
> + reg = <0x6a>;
> + status = "okay";
> + interrupt-parent = <&tlmm_pinmux>;
> + interrupts = <23 IRQ_TYPE_EDGE_BOTH>;
> +
> + max-chg-curr = <1800000>;
> + usb-curr-limit = <450000>;
> +
> + chip-temp-thershold = <110>; /* celsius */
> +
> + enable-usb-charging;
> + enable-otg-charging;
> + };
> +
> + smb347@7f {

Isn't one example sufficient?

> + compatible = "summit,smb347";
> + reg = <0x7f>;
> + status = "okay";
> +
> + max-chg-curr = <1800000>;
> + mains-curr-limit = <2000000>;
> + usb-curr-limit = <450000>;
> +
> + chip-temp-thershold = <110>; /* celsius */
> +
> + en-gpios = <&tlmm_pinmux 54 GPIO_ACTIVE_HIGH>;
> +
> + enable-usb-charging;
> + enable-mains-charging;
> + };