Re: [PATCH v4 4/8] power: supply: Add support for mp2733 battery charger

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Mon, Oct 24, 2022 at 03:27:53PM +0200, Saravanan Sekar wrote:
> mp2733 is updated version of mp2629 battery charge management
> which supports USB fast-charge and higher range of input voltage.
> 
> Signed-off-by: Saravanan Sekar <sravanhome@xxxxxxxxx>
> Reviewed-by: Andy Shevchenko <andy.shevchenko@xxxxxxxxx>
> ---

Acked-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxx>

-- Sebastian

>  drivers/power/supply/mp2629_charger.c | 223 ++++++++++++++++++++++----
>  1 file changed, 192 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/power/supply/mp2629_charger.c b/drivers/power/supply/mp2629_charger.c
> index bf9c27b463a8..9e4111aace4b 100644
> --- a/drivers/power/supply/mp2629_charger.c
> +++ b/drivers/power/supply/mp2629_charger.c
> @@ -30,12 +30,15 @@
>  #define MP2629_REG_INTERRUPT		0x0b
>  #define MP2629_REG_STATUS		0x0c
>  #define MP2629_REG_FAULT		0x0d
> +#define MP2629_REG_FAST_CHARGE		0x17
>  
>  #define MP2629_MASK_INPUT_TYPE		GENMASK(7, 5)
>  #define MP2629_MASK_CHARGE_TYPE		GENMASK(4, 3)
>  #define MP2629_MASK_CHARGE_CTRL		GENMASK(5, 4)
>  #define MP2629_MASK_WDOG_CTRL		GENMASK(5, 4)
>  #define MP2629_MASK_IMPEDANCE		GENMASK(7, 4)
> +#define MP2733_MASK_FAST_CHARGE		GENMASK(2, 1)
> +#define MP2733_MASK_FAST_CHARGE_RESET	BIT(0)
>  
>  #define MP2629_INPUTSOURCE_CHANGE	GENMASK(7, 5)
>  #define MP2629_CHARGING_CHANGE		GENMASK(4, 3)
> @@ -62,6 +65,17 @@ enum mp2629_source_type {
>  	MP2629_SOURCE_TYPE_OTG = 7,
>  };
>  
> +enum mp2733_source_type {
> +	MP2733_SOURCE_TYPE_NO_INPUT,
> +	MP2733_SOURCE_TYPE_NON_STD,
> +	MP2733_SOURCE_TYPE_APPLE_1p0,
> +	MP2733_SOURCE_TYPE_APPLE_2p1,
> +	MP2733_SOURCE_TYPE_APPLE_2p4,
> +	MP2733_SOURCE_TYPE_SDP,
> +	MP2733_SOURCE_TYPE_CDP,
> +	MP2733_SOURCE_TYPE_DCP,
> +};
> +
>  enum mp2629_field {
>  	INPUT_ILIM,
>  	INPUT_VLIM,
> @@ -72,11 +86,30 @@ enum mp2629_field {
>  	MP2629_MAX_FIELD
>  };
>  
> +struct mp2629_prop {
> +	int reg;
> +	int mask;
> +	int min;
> +	int max;
> +	int step;
> +	int shift;
> +};
> +
> +struct mp2xx_chip_info {
> +	const struct reg_field *rfields;
> +	struct mp2629_prop *chip_props;
> +	bool has_impedance;
> +	bool has_fast_charge;
> +
> +	int (*mp2xx_get_usb_type)(unsigned int rval);
> +};
> +
>  struct mp2629_charger {
>  	struct device *dev;
>  	int status;
>  	int fault;
>  
> +	const struct mp2xx_chip_info *chip_info;
>  	struct regmap *regmap;
>  	struct regmap_field *regmap_fields[MP2629_MAX_FIELD];
>  	struct mutex lock;
> @@ -85,15 +118,6 @@ struct mp2629_charger {
>  	struct iio_channel *iiochan[MP2629_ADC_CHAN_END];
>  };
>  
> -struct mp2629_prop {
> -	int reg;
> -	int mask;
> -	int min;
> -	int max;
> -	int step;
> -	int shift;
> -};
> -
>  static enum power_supply_usb_type mp2629_usb_types[] = {
>  	POWER_SUPPLY_USB_TYPE_SDP,
>  	POWER_SUPPLY_USB_TYPE_DCP,
> @@ -126,7 +150,25 @@ static enum power_supply_property mp2629_charger_bat_props[] = {
>  	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
>  };
>  
> -static struct mp2629_prop props[] = {
> +static struct mp2629_prop mp2733_chip_props[] = {
> +	MP2629_PROPS(INPUT_ILIM, 100000, 3250000, 50000),
> +	MP2629_PROPS(INPUT_VLIM, 3800000, 15200000, 100000),
> +	MP2629_PROPS(CHARGE_ILIM, 320000, 4520000, 40000),
> +	MP2629_PROPS(CHARGE_VLIM, 3400000, 4670000, 10000),
> +	MP2629_PROPS(PRECHARGE, 120000, 720000, 40000),
> +	MP2629_PROPS(TERM_CURRENT, 80000, 680000, 40000),
> +};
> +
> +static const struct reg_field mp2733_reg_fields[] = {
> +	[INPUT_ILIM]	= REG_FIELD(MP2629_REG_INPUT_ILIM, 0, 5),
> +	[INPUT_VLIM]	= REG_FIELD(MP2629_REG_INPUT_VLIM, 0, 6),
> +	[CHARGE_ILIM]	= REG_FIELD(MP2629_REG_CHARGE_ILIM, 0, 6),
> +	[CHARGE_VLIM]	= REG_FIELD(MP2629_REG_CHARGE_VLIM, 1, 7),
> +	[PRECHARGE]	= REG_FIELD(MP2629_REG_PRECHARGE, 4, 7),
> +	[TERM_CURRENT]	= REG_FIELD(MP2629_REG_TERM_CURRENT, 0, 3),
> +};
> +
> +static struct mp2629_prop mp2629_chip_props[] = {
>  	MP2629_PROPS(INPUT_ILIM, 100000, 3250000, 50000),
>  	MP2629_PROPS(INPUT_VLIM, 3800000, 5300000, 100000),
>  	MP2629_PROPS(CHARGE_ILIM, 320000, 4520000, 40000),
> @@ -174,6 +216,7 @@ static int mp2629_get_prop(struct mp2629_charger *charger,
>  {
>  	int ret;
>  	unsigned int rval;
> +	struct mp2629_prop *props = charger->chip_info->chip_props;
>  
>  	ret = regmap_field_read(charger->regmap_fields[fld], &rval);
>  	if (ret)
> @@ -189,6 +232,7 @@ static int mp2629_set_prop(struct mp2629_charger *charger,
>  			   const union power_supply_propval *val)
>  {
>  	unsigned int rval;
> +	struct mp2629_prop *props = charger->chip_info->chip_props;
>  
>  	if (val->intval < props[fld].min || val->intval > props[fld].max)
>  		return -EINVAL;
> @@ -311,6 +355,16 @@ static int mp2629_charger_battery_get_prop(struct power_supply *psy,
>  		default:
>  			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
>  		}
> +
> +		if (charger->chip_info->has_fast_charge) {
> +			ret = regmap_read(charger->regmap,
> +					  MP2629_REG_FAST_CHARGE, &rval);
> +			if (ret)
> +				break;
> +
> +			if (rval & BIT(6))
> +				val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
> +		}
>  		break;
>  
>  	default:
> @@ -344,6 +398,40 @@ static int mp2629_charger_battery_set_prop(struct power_supply *psy,
>  	}
>  }
>  
> +static int mp2733_get_usb_type(unsigned int rval)
> +{
> +	switch (rval) {
> +	case MP2733_SOURCE_TYPE_APPLE_1p0:
> +	case MP2733_SOURCE_TYPE_APPLE_2p1:
> +	case MP2733_SOURCE_TYPE_APPLE_2p4:
> +		return POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID;
> +	case MP2733_SOURCE_TYPE_SDP:
> +		return POWER_SUPPLY_USB_TYPE_SDP;
> +	case MP2733_SOURCE_TYPE_CDP:
> +		return POWER_SUPPLY_USB_TYPE_CDP;
> +	case MP2733_SOURCE_TYPE_DCP:
> +		return POWER_SUPPLY_USB_TYPE_DCP;
> +	default:
> +		return POWER_SUPPLY_USB_TYPE_UNKNOWN;
> +	}
> +}
> +
> +static int mp2629_get_usb_type(unsigned int rval)
> +{
> +	switch (rval) {
> +	case MP2629_SOURCE_TYPE_SDP:
> +		return POWER_SUPPLY_USB_TYPE_SDP;
> +	case MP2629_SOURCE_TYPE_CDP:
> +		return POWER_SUPPLY_USB_TYPE_CDP;
> +	case MP2629_SOURCE_TYPE_DCP:
> +		return POWER_SUPPLY_USB_TYPE_DCP;
> +	case MP2629_SOURCE_TYPE_OTG:
> +		return POWER_SUPPLY_USB_TYPE_PD_DRP;
> +	default:
> +		return POWER_SUPPLY_USB_TYPE_UNKNOWN;
> +	}
> +}
> +
>  static int mp2629_charger_usb_get_prop(struct power_supply *psy,
>  				enum power_supply_property psp,
>  				union power_supply_propval *val)
> @@ -367,23 +455,7 @@ static int mp2629_charger_usb_get_prop(struct power_supply *psy,
>  			break;
>  
>  		rval = (rval & MP2629_MASK_INPUT_TYPE) >> 5;
> -		switch (rval) {
> -		case MP2629_SOURCE_TYPE_SDP:
> -			val->intval = POWER_SUPPLY_USB_TYPE_SDP;
> -			break;
> -		case MP2629_SOURCE_TYPE_CDP:
> -			val->intval = POWER_SUPPLY_USB_TYPE_CDP;
> -			break;
> -		case MP2629_SOURCE_TYPE_DCP:
> -			val->intval = POWER_SUPPLY_USB_TYPE_DCP;
> -			break;
> -		case MP2629_SOURCE_TYPE_OTG:
> -			val->intval = POWER_SUPPLY_USB_TYPE_PD_DRP;
> -			break;
> -		default:
> -			val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
> -			break;
> -		}
> +		val->intval = charger->chip_info->mp2xx_get_usb_type(rval);
>  		break;
>  
>  	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> @@ -550,11 +622,72 @@ static ssize_t batt_impedance_compensation_store(struct device *dev,
>  
>  static DEVICE_ATTR_RW(batt_impedance_compensation);
>  
> -static struct attribute *mp2629_charger_sysfs_attrs[] = {
> +static struct attribute *mp2xx_batt_imp_sysfs_attrs[] = {
> +	&dev_attr_batt_impedance_compensation.attr,
> +	NULL
> +};
> +ATTRIBUTE_GROUPS(mp2xx_batt_imp_sysfs);
> +
> +static ssize_t usb_fast_charge_show(struct device *dev,
> +				    struct device_attribute *attr,
> +				    char *buf)
> +{
> +	struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
> +	unsigned int rval;
> +	int ret;
> +
> +	ret = regmap_read(charger->regmap, MP2629_REG_INTERRUPT, &rval);
> +	if (ret)
> +		return ret;
> +
> +	return  sysfs_emit(buf, "USB DP %u:DM %u\n", !!(rval & BIT(2)),
> +			 !!(rval & BIT(1)));
> +}
> +
> +static ssize_t usb_fast_charge_store(struct device *dev,
> +				     struct device_attribute *attr,
> +				     const char *buf,
> +				     size_t count)
> +{
> +	struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
> +	unsigned int val;
> +	int ret;
> +
> +	ret = kstrtouint(buf, 10, &val);
> +	if (ret)
> +		return ret;
> +
> +	if (val > 3)
> +		return -ERANGE;
> +
> +	ret = regmap_update_bits(charger->regmap, MP2629_REG_INTERRUPT,
> +				 MP2733_MASK_FAST_CHARGE, val << 1);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(charger->regmap, MP2629_REG_INTERRUPT,
> +				 MP2733_MASK_FAST_CHARGE_RESET,
> +				 MP2733_MASK_FAST_CHARGE_RESET);
> +	if (ret)
> +		return ret;
> +
> +	return count;
> +}
> +
> +static DEVICE_ATTR_RW(usb_fast_charge);
> +
> +static struct attribute *mp2xx_fast_charge_sysfs_attrs[] = {
> +	&dev_attr_usb_fast_charge.attr,
> +	NULL
> +};
> +ATTRIBUTE_GROUPS(mp2xx_fast_charge_sysfs);
> +
> +static struct attribute *mp2xx_all_sysfs_attrs[] = {
> +	&dev_attr_usb_fast_charge.attr,
>  	&dev_attr_batt_impedance_compensation.attr,
>  	NULL
>  };
> -ATTRIBUTE_GROUPS(mp2629_charger_sysfs);
> +ATTRIBUTE_GROUPS(mp2xx_all_sysfs);
>  
>  static void mp2629_charger_disable(void *data)
>  {
> @@ -564,6 +697,23 @@ static void mp2629_charger_disable(void *data)
>  					MP2629_MASK_CHARGE_CTRL, 0);
>  }
>  
> +static const struct mp2xx_chip_info mp2xx_chip_info_tbl[] = {
> +	[CHIP_ID_MP2629] = {
> +		.rfields = mp2629_reg_fields,
> +		.chip_props = mp2629_chip_props,
> +		.has_impedance = 1,
> +
> +		.mp2xx_get_usb_type = mp2629_get_usb_type,
> +	},
> +	[CHIP_ID_MP2733] = {
> +		.rfields = mp2733_reg_fields,
> +		.chip_props = mp2733_chip_props,
> +		.has_fast_charge = 1,
> +
> +		.mp2xx_get_usb_type = mp2733_get_usb_type,
> +	},
> +};
> +
>  static int mp2629_charger_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> @@ -578,6 +728,7 @@ static int mp2629_charger_probe(struct platform_device *pdev)
>  
>  	charger->regmap = ddata->regmap;
>  	charger->dev = dev;
> +	charger->chip_info = &mp2xx_chip_info_tbl[ddata->chip_id];
>  	platform_set_drvdata(pdev, charger);
>  
>  	irq = platform_get_irq(to_platform_device(dev->parent), 0);
> @@ -586,7 +737,8 @@ static int mp2629_charger_probe(struct platform_device *pdev)
>  
>  	for (i = 0; i < MP2629_MAX_FIELD; i++) {
>  		charger->regmap_fields[i] = devm_regmap_field_alloc(dev,
> -					charger->regmap, mp2629_reg_fields[i]);
> +					charger->regmap,
> +					charger->chip_info->rfields[i]);
>  		if (IS_ERR(charger->regmap_fields[i])) {
>  			dev_err(dev, "regmap field alloc fail %d\n", i);
>  			return PTR_ERR(charger->regmap_fields[i]);
> @@ -613,7 +765,16 @@ static int mp2629_charger_probe(struct platform_device *pdev)
>  	}
>  
>  	psy_cfg.drv_data = charger;
> -	psy_cfg.attr_grp = mp2629_charger_sysfs_groups;
> +
> +	if (charger->chip_info->has_impedance &&
> +	    charger->chip_info->has_fast_charge) {
> +		psy_cfg.attr_grp = mp2xx_all_sysfs_groups;
> +	} else if (charger->chip_info->has_impedance) {
> +		psy_cfg.attr_grp = mp2xx_batt_imp_sysfs_groups;
> +	} else if (charger->chip_info->has_fast_charge) {
> +		psy_cfg.attr_grp = mp2xx_fast_charge_sysfs_groups;
> +	}
> +
>  	charger->battery = devm_power_supply_register(dev,
>  					 &mp2629_battery_desc, &psy_cfg);
>  	if (IS_ERR(charger->battery)) {
> -- 
> 2.32.0
> 

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux