On 16.09.2015 02:58, Andreas Dannenberg wrote: > A new optional device property called "ti,current-limit" is introduced > to allow disabling the D+/D- USB signal-based charger type auto- > detection algorithm used to set the input current limit and instead to > use a fixed input current limit. > > Signed-off-by: Andreas Dannenberg <dannenberg@xxxxxx> > --- > drivers/power/bq24257_charger.c | 102 +++++++++++++++++++++++++++++++--------- > 1 file changed, 81 insertions(+), 21 deletions(-) > > diff --git a/drivers/power/bq24257_charger.c b/drivers/power/bq24257_charger.c > index fdfe855..55e4ee4 100644 > --- a/drivers/power/bq24257_charger.c > +++ b/drivers/power/bq24257_charger.c > @@ -74,6 +74,7 @@ struct bq24257_init_data { > u8 ichg; /* charge current */ > u8 vbat; /* regulation voltage */ > u8 iterm; /* termination current */ > + u8 in_ilimit; /* input current limit */ > }; > > struct bq24257_state { > @@ -100,6 +101,8 @@ struct bq24257_device { > struct bq24257_state state; > > struct mutex lock; /* protect state data */ > + > + bool in_ilimit_autoset_disable; > }; > > static bool bq24257_is_volatile_reg(struct device *dev, unsigned int reg) > @@ -188,6 +191,12 @@ static const u32 bq24257_iterm_map[] = { > > #define BQ24257_ITERM_MAP_SIZE ARRAY_SIZE(bq24257_iterm_map) > > +static const u32 bq24257_iilimit_map[] = { Too many ii? bq24257_ilimit_map? Or is it a shortcut for "in_ilimit"? New fields have pattern like "in_ilimit*". Anyway it's a confusing so maybe use everywhere the same pattern? > + 100000, 150000, 500000, 900000, 1500000, 2000000 > +}; > + > +#define BQ24257_IILIMIT_MAP_SIZE ARRAY_SIZE(bq24257_iilimit_map) ditto: ILIMIT_MAP_SIZE? > + > static int bq24257_field_read(struct bq24257_device *bq, > enum bq24257_fields field_id) > { > @@ -479,24 +488,35 @@ static void bq24257_handle_state_change(struct bq24257_device *bq, > old_state = bq->state; > mutex_unlock(&bq->lock); > > - if (!new_state->power_good) { /* power removed */ > - cancel_delayed_work_sync(&bq->iilimit_setup_work); > - > - /* activate D+/D- port detection algorithm */ > - ret = bq24257_field_write(bq, F_DPDM_EN, 1); > - if (ret < 0) > - goto error; > + /* > + * Handle BQ2425x state changes observing whether the D+/D- based input > + * current limit autoset functionality is enabled. > + */ > + if (!new_state->power_good) { > + dev_dbg(bq->dev, "Power removed\n"); > + if (!bq->in_ilimit_autoset_disable) { > + cancel_delayed_work_sync(&bq->iilimit_setup_work); > > - reset_iilimit = true; > - } else if (!old_state.power_good) { /* power inserted */ > - config_iilimit = true; > - } else if (new_state->fault == FAULT_NO_BAT) { /* battery removed */ > - cancel_delayed_work_sync(&bq->iilimit_setup_work); > + /* activate D+/D- port detection algorithm */ > + ret = bq24257_field_write(bq, F_DPDM_EN, 1); > + if (ret < 0) > + goto error; > > - reset_iilimit = true; > - } else if (old_state.fault == FAULT_NO_BAT) { /* battery connected */ > - config_iilimit = true; > - } else if (new_state->fault == FAULT_TIMER) { /* safety timer expired */ > + reset_iilimit = true; > + } > + } else if (!old_state.power_good) { > + dev_dbg(bq->dev, "Power inserted\n"); > + config_iilimit = !bq->in_ilimit_autoset_disable; > + } else if (new_state->fault == FAULT_NO_BAT) { > + dev_warn(bq->dev, "Battery removed\n"); dev_warn? This wasn't here before... It's a bit too serious. Is removing a battery an error condition? Maybe user just unplugged it? dev_dbg or dev_info should be sufficient. BTW, it is useful to quickly find boot regressions with "dmesg -l warn,err". Removing a battery probably is not an error? > + if (!bq->in_ilimit_autoset_disable) { > + cancel_delayed_work_sync(&bq->iilimit_setup_work); > + reset_iilimit = true; > + } > + } else if (old_state.fault == FAULT_NO_BAT) { > + dev_warn(bq->dev, "Battery connected\n"); Definitely not a warn. Inserting a battery is not an error condition. > + config_iilimit = !bq->in_ilimit_autoset_disable; > + } else if (new_state->fault == FAULT_TIMER) { > dev_err(bq->dev, "Safety timer expired! Battery dead?\n"); > } Don't you have a schedule_delayed_work() call here which now will be executed always? Even when work was not INIT and nothing will cancel it? > > @@ -581,7 +601,16 @@ static int bq24257_hw_init(struct bq24257_device *bq) > bq->state = state; > mutex_unlock(&bq->lock); > > - if (!state.power_good) > + if (bq->in_ilimit_autoset_disable) { > + dev_dbg(bq->dev, "manually setting iilimit = %d\n", > + bq->init_data.in_ilimit); Nit, no actual difference but makes more sense to me because field is u8: "%u". > + > + /* program fixed input current limit */ > + ret = bq24257_field_write(bq, F_IILIMIT, > + bq->init_data.in_ilimit); > + if (ret < 0) > + return ret; > + } else if (!state.power_good) > /* activate D+/D- detection algorithm */ > ret = bq24257_field_write(bq, F_DPDM_EN, 1); > else if (state.fault != FAULT_NO_BAT) > @@ -659,6 +688,7 @@ static int bq24257_fw_probe(struct bq24257_device *bq) > int ret; > u32 property; > > + /* Required properties */ > ret = device_property_read_u32(bq->dev, "ti,charge-current", &property); > if (ret < 0) > return ret; > @@ -682,6 +712,24 @@ static int bq24257_fw_probe(struct bq24257_device *bq) > bq->init_data.iterm = bq24257_find_idx(property, bq24257_iterm_map, > BQ24257_ITERM_MAP_SIZE); > > + /* Optional properties. If not provided use reasonable default. */ > + ret = device_property_read_u32(bq->dev, "ti,current-limit", > + &property); > + if (ret < 0) > + /* > + * Explicitly set a default value which will be needed for > + * devices that don't support the automatic setting of the input > + * current limit through the charger type detection mechanism. > + */ > + bq->init_data.in_ilimit = IILIMIT_500; > + else { > + bq->in_ilimit_autoset_disable = true; > + bq->init_data.in_ilimit = > + bq24257_find_idx(property, > + bq24257_iilimit_map, > + BQ24257_IILIMIT_MAP_SIZE); > + } > + > return 0; > } > > @@ -740,8 +788,6 @@ static int bq24257_probe(struct i2c_client *client, > > i2c_set_clientdata(client, bq); > > - INIT_DELAYED_WORK(&bq->iilimit_setup_work, bq24257_iilimit_setup_work); > - > if (!dev->platform_data) { > ret = bq24257_fw_probe(bq); > if (ret < 0) { > @@ -752,6 +798,18 @@ static int bq24257_probe(struct i2c_client *client, > return -ENODEV; > } > > + /* > + * The BQ24250 doesn't support the D+/D- based charger type detection > + * used for the automatic setting of the input current limit setting so > + * explicitly disable that feature. > + */ > + if (bq->chip == BQ24250) > + bq->in_ilimit_autoset_disable = true; > + > + if (!bq->in_ilimit_autoset_disable) In most places you have quite obfuscated negation of "autoset_disable"... So maybe just "bq->in_ilimit_autoset" or "bq->in_ilimit_autoset_enable" and the negation won't be needed? It could be more readable. Best regards, Krzysztof -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html