File Index
Files and directories
Sign in
FILE

bq257xx_charger.c

File preview with syntax highlighting.

linux-6.19.14/drivers/power/supply/bq257xx_charger.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * BQ257XX Battery Charger Driver
  4 * Copyright (C) 2025 Chris Morgan <macromorgan@hotmail.com>
  5 */
  6
  7#include <linux/bitfield.h>
  8#include <linux/i2c.h>
  9#include <linux/interrupt.h>
 10#include <linux/mfd/bq257xx.h>
 11#include <linux/platform_device.h>
 12#include <linux/power_supply.h>
 13#include <linux/property.h>
 14#include <linux/regmap.h>
 15
 16/* Forward declaration of driver data. */
 17struct bq257xx_chg;
 18
 19/**
 20 * struct bq257xx_chip_info - chip specific routines
 21 * @bq257xx_hw_init: init function for hw
 22 * @bq257xx_hw_shutdown: shutdown function for hw
 23 * @bq257xx_get_state: get and update state of hardware
 24 * @bq257xx_set_ichg: set maximum charge current (in uA)
 25 * @bq257xx_set_vbatreg: set maximum charge voltage (in uV)
 26 * @bq257xx_set_iindpm: set maximum input current (in uA)
 27 */
 28struct bq257xx_chip_info {
 29	int (*bq257xx_hw_init)(struct bq257xx_chg *pdata);
 30	void (*bq257xx_hw_shutdown)(struct bq257xx_chg *pdata);
 31	int (*bq257xx_get_state)(struct bq257xx_chg *pdata);
 32	int (*bq257xx_set_ichg)(struct bq257xx_chg *pdata, int ichg);
 33	int (*bq257xx_set_vbatreg)(struct bq257xx_chg *pdata, int vbatreg);
 34	int (*bq257xx_set_iindpm)(struct bq257xx_chg *pdata, int iindpm);
 35};
 36
 37/**
 38 * struct bq257xx_chg - driver data for charger
 39 * @chip: hw specific functions
 40 * @bq: parent MFD device
 41 * @charger: power supply device
 42 * @online: charger input is present
 43 * @fast_charge: charger is in fast charge mode
 44 * @pre_charge: charger is in pre-charge mode
 45 * @ov_fault: charger reports over voltage fault
 46 * @batoc_fault: charger reports battery over current fault
 47 * @oc_fault: charger reports over current fault
 48 * @usb_type: USB type reported from parent power supply
 49 * @supplied: Status of parent power supply
 50 * @iindpm_max: maximum input current limit (uA)
 51 * @vbat_max: maximum charge voltage (uV)
 52 * @ichg_max: maximum charge current (uA)
 53 * @vsys_min: minimum system voltage (uV)
 54 */
 55struct bq257xx_chg {
 56	const struct bq257xx_chip_info *chip;
 57	struct bq257xx_device *bq;
 58	struct power_supply *charger;
 59	bool online;
 60	bool fast_charge;
 61	bool pre_charge;
 62	bool ov_fault;
 63	bool batoc_fault;
 64	bool oc_fault;
 65	int usb_type;
 66	int supplied;
 67	u32 iindpm_max;
 68	u32 vbat_max;
 69	u32 ichg_max;
 70	u32 vsys_min;
 71};
 72
 73/**
 74 * bq25703_get_state() - Get the current state of the device
 75 * @pdata: driver platform data
 76 *
 77 * Get the current state of the charger. Check if the charger is
 78 * powered, what kind of charge state (if any) the device is in,
 79 * and if there are any active faults.
 80 *
 81 * Return: Returns 0 on success, or error on failure to read device.
 82 */
 83static int bq25703_get_state(struct bq257xx_chg *pdata)
 84{
 85	unsigned int reg;
 86	int ret;
 87
 88	ret = regmap_read(pdata->bq->regmap, BQ25703_CHARGER_STATUS, &reg);
 89	if (ret)
 90		return ret;
 91
 92	pdata->online = reg & BQ25703_STS_AC_STAT;
 93	pdata->fast_charge = reg & BQ25703_STS_IN_FCHRG;
 94	pdata->pre_charge = reg & BQ25703_STS_IN_PCHRG;
 95	pdata->ov_fault = reg & BQ25703_STS_FAULT_ACOV;
 96	pdata->batoc_fault = reg & BQ25703_STS_FAULT_BATOC;
 97	pdata->oc_fault = reg & BQ25703_STS_FAULT_ACOC;
 98
 99	return 0;
100}
101
102/**
103 * bq25703_get_min_vsys() - Get the minimum system voltage
104 * @pdata: driver platform data
105 * @intval: value for minimum voltage
106 *
107 * Return: Returns 0 on success or error on failure to read.
108 */
109static int bq25703_get_min_vsys(struct bq257xx_chg *pdata, int *intval)
110{
111	unsigned int reg;
112	int ret;
113
114	ret = regmap_read(pdata->bq->regmap, BQ25703_MIN_VSYS,
115			  &reg);
116	if (ret)
117		return ret;
118
119	reg = FIELD_GET(BQ25703_MINVSYS_MASK, reg);
120	*intval = (reg * BQ25703_MINVSYS_STEP_UV) + BQ25703_MINVSYS_MIN_UV;
121
122	return ret;
123}
124
125/**
126 * bq25703_set_min_vsys() - Set the minimum system voltage
127 * @pdata: driver platform data
128 * @vsys: voltage value to set in uV.
129 *
130 * This function takes a requested minimum system voltage value, clamps
131 * it between the minimum supported value by the charger and a user
132 * defined minimum system value, and then writes the value to the
133 * appropriate register.
134 *
135 * Return: Returns 0 on success or error if an error occurs.
136 */
137static int bq25703_set_min_vsys(struct bq257xx_chg *pdata, int vsys)
138{
139	unsigned int reg;
140	int vsys_min = pdata->vsys_min;
141
142	vsys = clamp(vsys, BQ25703_MINVSYS_MIN_UV, vsys_min);
143	reg = ((vsys - BQ25703_MINVSYS_MIN_UV) / BQ25703_MINVSYS_STEP_UV);
144	reg = FIELD_PREP(BQ25703_MINVSYS_MASK, reg);
145
146	return regmap_write(pdata->bq->regmap, BQ25703_MIN_VSYS,
147			    reg);
148}
149
150/**
151 * bq25703_get_cur() - Get the reported current from the battery
152 * @pdata: driver platform data
153 * @intval: value of reported battery current
154 *
155 * Read the reported current from the battery. Since value is always
156 * positive set sign to negative if discharging.
157 *
158 * Return: Returns 0 on success or error if unable to read value.
159 */
160static int bq25703_get_cur(struct bq257xx_chg *pdata, int *intval)
161{
162	unsigned int reg;
163	int ret;
164
165	ret = regmap_read(pdata->bq->regmap, BQ25703_ADCIBAT_CHG, &reg);
166	if (ret < 0)
167		return ret;
168
169	if (pdata->online)
170		*intval = FIELD_GET(BQ25703_ADCIBAT_CHG_MASK, reg) *
171			  BQ25703_ADCIBAT_CHG_STEP_UA;
172	else
173		*intval = -(FIELD_GET(BQ25703_ADCIBAT_DISCHG_MASK, reg) *
174			    BQ25703_ADCIBAT_DIS_STEP_UA);
175
176	return ret;
177}
178
179/**
180 * bq25703_get_ichg_cur() - Get the maximum reported charge current
181 * @pdata: driver platform data
182 * @intval: value of maximum reported charge current
183 *
184 * Get the maximum reported charge current from the battery.
185 *
186 * Return: Returns 0 on success or error if unable to read value.
187 */
188static int bq25703_get_ichg_cur(struct bq257xx_chg *pdata, int *intval)
189{
190	unsigned int reg;
191	int ret;
192
193	ret = regmap_read(pdata->bq->regmap, BQ25703_CHARGE_CURRENT, &reg);
194	if (ret)
195		return ret;
196
197	*intval = FIELD_GET(BQ25703_ICHG_MASK, reg) * BQ25703_ICHG_STEP_UA;
198
199	return ret;
200}
201
202/**
203 * bq25703_set_ichg_cur() - Set the maximum charge current
204 * @pdata: driver platform data
205 * @ichg: current value to set in uA.
206 *
207 * This function takes a requested maximum charge current value, clamps
208 * it between the minimum supported value by the charger and a user
209 * defined maximum charging value, and then writes the value to the
210 * appropriate register.
211 *
212 * Return: Returns 0 on success or error if an error occurs.
213 */
214static int bq25703_set_ichg_cur(struct bq257xx_chg *pdata, int ichg)
215{
216	unsigned int reg;
217	int ichg_max = pdata->ichg_max;
218
219	ichg = clamp(ichg, BQ25703_ICHG_MIN_UA, ichg_max);
220	reg = FIELD_PREP(BQ25703_ICHG_MASK, (ichg / BQ25703_ICHG_STEP_UA));
221
222	return regmap_write(pdata->bq->regmap, BQ25703_CHARGE_CURRENT,
223			    reg);
224}
225
226/**
227 * bq25703_get_chrg_volt() - Get the maximum set charge voltage
228 * @pdata: driver platform data
229 * @intval: maximum charge voltage value
230 *
231 * Return: Returns 0 on success or error if unable to read value.
232 */
233static int bq25703_get_chrg_volt(struct bq257xx_chg *pdata, int *intval)
234{
235	unsigned int reg;
236	int ret;
237
238	ret = regmap_read(pdata->bq->regmap, BQ25703_MAX_CHARGE_VOLT,
239			  &reg);
240	if (ret)
241		return ret;
242
243	*intval = FIELD_GET(BQ25703_MAX_CHARGE_VOLT_MASK, reg) *
244		  BQ25703_VBATREG_STEP_UV;
245
246	return ret;
247}
248
249/**
250 * bq25703_set_chrg_volt() - Set the maximum charge voltage
251 * @pdata: driver platform data
252 * @vbat: voltage value to set in uV.
253 *
254 * This function takes a requested maximum charge voltage value, clamps
255 * it between the minimum supported value by the charger and a user
256 * defined maximum charging value, and then writes the value to the
257 * appropriate register.
258 *
259 * Return: Returns 0 on success or error if an error occurs.
260 */
261static int bq25703_set_chrg_volt(struct bq257xx_chg *pdata, int vbat)
262{
263	unsigned int reg;
264	int vbat_max = pdata->vbat_max;
265
266	vbat = clamp(vbat, BQ25703_VBATREG_MIN_UV, vbat_max);
267
268	reg = FIELD_PREP(BQ25703_MAX_CHARGE_VOLT_MASK,
269			 (vbat / BQ25703_VBATREG_STEP_UV));
270
271	return regmap_write(pdata->bq->regmap, BQ25703_MAX_CHARGE_VOLT,
272			    reg);
273}
274
275/**
276 * bq25703_get_iindpm() - Get the maximum set input current
277 * @pdata: driver platform data
278 * @intval: maximum input current value
279 *
280 * Read the actual input current limit from the device into intval.
281 * This can differ from the value programmed due to some autonomous
282 * functions that may be enabled (but are not currently). This is why
283 * there is a different register used.
284 *
285 * Return: Returns 0 on success or error if unable to read register
286 * value.
287 */
288static int bq25703_get_iindpm(struct bq257xx_chg *pdata, int *intval)
289{
290	unsigned int reg;
291	int ret;
292
293	ret = regmap_read(pdata->bq->regmap, BQ25703_IIN_DPM, &reg);
294	if (ret)
295		return ret;
296
297	reg = FIELD_GET(BQ25703_IINDPM_MASK, reg);
298	*intval = (reg * BQ25703_IINDPM_STEP_UA) + BQ25703_IINDPM_OFFSET_UA;
299
300	return ret;
301}
302
303/**
304 * bq25703_set_iindpm() - Set the maximum input current
305 * @pdata: driver platform data
306 * @iindpm: current value in uA.
307 *
308 * This function takes a requested maximum input current value, clamps
309 * it between the minimum supported value by the charger and a user
310 * defined maximum input value, and then writes the value to the
311 * appropriate register.
312 *
313 * Return: Returns 0 on success or error if an error occurs.
314 */
315static int bq25703_set_iindpm(struct bq257xx_chg *pdata, int iindpm)
316{
317	unsigned int reg;
318	int iindpm_max = pdata->iindpm_max;
319
320	iindpm = clamp(iindpm, BQ25703_IINDPM_MIN_UA, iindpm_max);
321
322	reg = ((iindpm - BQ25703_IINDPM_OFFSET_UA) / BQ25703_IINDPM_STEP_UA);
323
324	return regmap_write(pdata->bq->regmap, BQ25703_IIN_HOST,
325			    FIELD_PREP(BQ25703_IINDPM_MASK, reg));
326}
327
328/**
329 * bq25703_get_vbat() - Get the reported voltage from the battery
330 * @pdata: driver platform data
331 * @intval: value of reported battery voltage
332 *
333 * Read value of battery voltage into intval.
334 *
335 * Return: Returns 0 on success or error if unable to read value.
336 */
337static int bq25703_get_vbat(struct bq257xx_chg *pdata, int *intval)
338{
339	unsigned int reg;
340	int ret;
341
342	ret = regmap_read(pdata->bq->regmap, BQ25703_ADCVSYSVBAT, &reg);
343	if (ret)
344		return ret;
345
346	reg = FIELD_GET(BQ25703_ADCVBAT_MASK, reg);
347	*intval = (reg * BQ25703_ADCVSYSVBAT_STEP) + BQ25703_ADCVSYSVBAT_OFFSET_UV;
348
349	return ret;
350}
351
352/**
353 * bq25703_hw_init() - Set all the required registers to init the charger
354 * @pdata: driver platform data
355 *
356 * Initialize the BQ25703 by first disabling the watchdog timer (which
357 * shuts off the charger in the absence of periodic writes). Then, set
358 * the charge current, charge voltage, minimum system voltage, and
359 * input current limit. Disable low power mode to allow ADCs and
360 * interrupts. Enable the ADC, start the ADC, set the ADC scale to
361 * full, and enable each individual ADC channel.
362 *
363 * Return: Returns 0 on success or error code on error.
364 */
365static int bq25703_hw_init(struct bq257xx_chg *pdata)
366{
367	struct regmap *regmap = pdata->bq->regmap;
368	int ret = 0;
369
370	regmap_update_bits(regmap, BQ25703_CHARGE_OPTION_0,
371			   BQ25703_WDTMR_ADJ_MASK,
372			   FIELD_PREP(BQ25703_WDTMR_ADJ_MASK,
373			   BQ25703_WDTMR_DISABLE));
374
375	ret = pdata->chip->bq257xx_set_ichg(pdata, pdata->ichg_max);
376	if (ret)
377		return ret;
378
379	ret = pdata->chip->bq257xx_set_vbatreg(pdata, pdata->vbat_max);
380	if (ret)
381		return ret;
382
383	ret = bq25703_set_min_vsys(pdata, pdata->vsys_min);
384	if (ret)
385		return ret;
386
387	ret = pdata->chip->bq257xx_set_iindpm(pdata, pdata->iindpm_max);
388	if (ret)
389		return ret;
390
391	/* Disable low power mode by writing 0 to the register. */
392	regmap_update_bits(regmap, BQ25703_CHARGE_OPTION_0,
393			   BQ25703_EN_LWPWR, 0);
394
395	/* Enable the ADC. */
396	regmap_update_bits(regmap, BQ25703_ADC_OPTION,
397			   BQ25703_ADC_CONV_EN, BQ25703_ADC_CONV_EN);
398
399	/* Start the ADC. */
400	regmap_update_bits(regmap, BQ25703_ADC_OPTION,
401			   BQ25703_ADC_START, BQ25703_ADC_START);
402
403	/* Set the scale of the ADC. */
404	regmap_update_bits(regmap, BQ25703_ADC_OPTION,
405			   BQ25703_ADC_FULL_SCALE, BQ25703_ADC_FULL_SCALE);
406
407	/* Enable each of the ADC channels available. */
408	regmap_update_bits(regmap, BQ25703_ADC_OPTION,
409			   BQ25703_ADC_CH_MASK,
410			   (BQ25703_ADC_CMPIN_EN | BQ25703_ADC_VBUS_EN |
411			   BQ25703_ADC_PSYS_EN | BQ25703_ADC_IIN_EN |
412			   BQ25703_ADC_IDCHG_EN | BQ25703_ADC_ICHG_EN |
413			   BQ25703_ADC_VSYS_EN | BQ25703_ADC_VBAT_EN));
414
415	return ret;
416}
417
418/**
419 * bq25703_hw_shutdown() - Set registers for shutdown
420 * @pdata: driver platform data
421 *
422 * Enable low power mode for the device while in shutdown.
423 */
424static void bq25703_hw_shutdown(struct bq257xx_chg *pdata)
425{
426	regmap_update_bits(pdata->bq->regmap, BQ25703_CHARGE_OPTION_0,
427			   BQ25703_EN_LWPWR, BQ25703_EN_LWPWR);
428}
429
430static int bq257xx_set_charger_property(struct power_supply *psy,
431		enum power_supply_property prop,
432		const union power_supply_propval *val)
433{
434	struct bq257xx_chg *pdata = power_supply_get_drvdata(psy);
435
436	switch (prop) {
437	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
438		return pdata->chip->bq257xx_set_iindpm(pdata, val->intval);
439
440	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
441		return pdata->chip->bq257xx_set_vbatreg(pdata, val->intval);
442
443	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
444		return pdata->chip->bq257xx_set_ichg(pdata, val->intval);
445
446	default:
447		break;
448	}
449
450	return -EINVAL;
451}
452
453static int bq257xx_get_charger_property(struct power_supply *psy,
454				enum power_supply_property psp,
455				union power_supply_propval *val)
456{
457	struct bq257xx_chg *pdata = power_supply_get_drvdata(psy);
458	int ret = 0;
459
460	ret = pdata->chip->bq257xx_get_state(pdata);
461	if (ret)
462		return ret;
463
464	switch (psp) {
465	case POWER_SUPPLY_PROP_STATUS:
466		if (!pdata->online)
467			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
468		else if (pdata->fast_charge || pdata->pre_charge)
469			val->intval = POWER_SUPPLY_STATUS_CHARGING;
470		else
471			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
472		break;
473
474	case POWER_SUPPLY_PROP_HEALTH:
475		if (pdata->ov_fault || pdata->batoc_fault)
476			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
477		else if (pdata->oc_fault)
478			val->intval = POWER_SUPPLY_HEALTH_OVERCURRENT;
479		else
480			val->intval = POWER_SUPPLY_HEALTH_GOOD;
481		break;
482
483	case POWER_SUPPLY_PROP_MANUFACTURER:
484		val->strval = "Texas Instruments";
485		break;
486
487	case POWER_SUPPLY_PROP_ONLINE:
488		val->intval = pdata->online;
489		break;
490
491	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
492		return bq25703_get_iindpm(pdata, &val->intval);
493
494	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
495		return bq25703_get_chrg_volt(pdata, &val->intval);
496
497	case POWER_SUPPLY_PROP_CURRENT_NOW:
498		return bq25703_get_cur(pdata, &val->intval);
499
500	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
501		return bq25703_get_vbat(pdata, &val->intval);
502
503	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
504		return bq25703_get_ichg_cur(pdata, &val->intval);
505
506	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
507		return bq25703_get_min_vsys(pdata, &val->intval);
508
509	case POWER_SUPPLY_PROP_USB_TYPE:
510		val->intval = pdata->usb_type;
511		break;
512
513	default:
514		return -EINVAL;
515	}
516
517	return ret;
518}
519
520static enum power_supply_property bq257xx_power_supply_props[] = {
521	POWER_SUPPLY_PROP_MANUFACTURER,
522	POWER_SUPPLY_PROP_STATUS,
523	POWER_SUPPLY_PROP_ONLINE,
524	POWER_SUPPLY_PROP_HEALTH,
525	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
526	POWER_SUPPLY_PROP_CURRENT_NOW,
527	POWER_SUPPLY_PROP_VOLTAGE_NOW,
528	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
529	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
530	POWER_SUPPLY_PROP_VOLTAGE_MIN,
531	POWER_SUPPLY_PROP_USB_TYPE,
532};
533
534static int bq257xx_property_is_writeable(struct power_supply *psy,
535					 enum power_supply_property prop)
536{
537	switch (prop) {
538	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
539	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
540	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
541		return true;
542	default:
543		return false;
544	}
545}
546
547/**
548 * bq257xx_external_power_changed() - Handler for external power change
549 * @psy: Power supply data
550 *
551 * When the external power into the charger is changed, check the USB
552 * type so that it can be reported. Additionally, update the max input
553 * current and max charging current to the value reported if it is a
554 * USB PD charger, otherwise use the default value. Note that each time
555 * a charger is removed the max charge current register is erased, so
556 * it must be set again each time the input changes or the device will
557 * not charge.
558 */
559static void bq257xx_external_power_changed(struct power_supply *psy)
560{
561	struct bq257xx_chg *pdata = power_supply_get_drvdata(psy);
562	union power_supply_propval val;
563	int ret;
564	int imax = pdata->iindpm_max;
565
566	pdata->chip->bq257xx_get_state(pdata);
567
568	pdata->supplied = power_supply_am_i_supplied(pdata->charger);
569	if (pdata->supplied < 0)
570		return;
571
572	if (pdata->supplied == 0)
573		goto out;
574
575	ret = power_supply_get_property_from_supplier(psy,
576						      POWER_SUPPLY_PROP_USB_TYPE,
577						      &val);
578	if (ret)
579		return;
580
581	pdata->usb_type = val.intval;
582
583	if ((pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD) ||
584	    (pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD_DRP) ||
585	    (pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD_PPS)) {
586		ret = power_supply_get_property_from_supplier(psy,
587							      POWER_SUPPLY_PROP_CURRENT_MAX,
588							      &val);
589		if (ret)
590			return;
591
592		if (val.intval)
593			imax = val.intval;
594	}
595
596	if (pdata->supplied) {
597		pdata->chip->bq257xx_set_ichg(pdata, pdata->ichg_max);
598		pdata->chip->bq257xx_set_iindpm(pdata, imax);
599		pdata->chip->bq257xx_set_vbatreg(pdata, pdata->vbat_max);
600	}
601
602out:
603	power_supply_changed(psy);
604}
605
606static irqreturn_t bq257xx_irq_handler_thread(int irq, void *private)
607{
608	struct bq257xx_chg *pdata = private;
609
610	bq257xx_external_power_changed(pdata->charger);
611	return IRQ_HANDLED;
612}
613
614static const struct power_supply_desc bq257xx_power_supply_desc = {
615	.name = "bq257xx-charger",
616	.type = POWER_SUPPLY_TYPE_USB,
617	.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) |
618		     BIT(POWER_SUPPLY_USB_TYPE_PD) |
619		     BIT(POWER_SUPPLY_USB_TYPE_PD_DRP) |
620		     BIT(POWER_SUPPLY_USB_TYPE_PD_PPS) |
621		     BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),
622	.properties = bq257xx_power_supply_props,
623	.num_properties = ARRAY_SIZE(bq257xx_power_supply_props),
624	.get_property = bq257xx_get_charger_property,
625	.set_property = bq257xx_set_charger_property,
626	.property_is_writeable = bq257xx_property_is_writeable,
627	.external_power_changed = bq257xx_external_power_changed,
628};
629
630static const struct bq257xx_chip_info bq25703_chip_info = {
631		.bq257xx_hw_init = &bq25703_hw_init,
632		.bq257xx_hw_shutdown = &bq25703_hw_shutdown,
633		.bq257xx_get_state = &bq25703_get_state,
634		.bq257xx_set_ichg = &bq25703_set_ichg_cur,
635		.bq257xx_set_vbatreg = &bq25703_set_chrg_volt,
636		.bq257xx_set_iindpm = &bq25703_set_iindpm,
637};
638
639/**
640 * bq257xx_parse_dt() - Parse the device tree for required properties
641 * @pdata: driver platform data
642 * @psy_cfg: power supply config data
643 * @dev: device struct
644 *
645 * Read the device tree to identify the minimum system voltage, the
646 * maximum charge current, the maximum charge voltage, and the maximum
647 * input current.
648 *
649 * Return: Returns 0 on success or error code on error.
650 */
651static int bq257xx_parse_dt(struct bq257xx_chg *pdata,
652		struct power_supply_config *psy_cfg, struct device *dev)
653{
654	struct power_supply_battery_info *bat_info;
655	int ret;
656
657	ret = power_supply_get_battery_info(pdata->charger,
658					    &bat_info);
659	if (ret)
660		return dev_err_probe(dev, ret,
661				     "Unable to get battery info\n");
662
663	if ((bat_info->voltage_min_design_uv <= 0) ||
664	    (bat_info->constant_charge_voltage_max_uv <= 0) ||
665	    (bat_info->constant_charge_current_max_ua <= 0))
666		return dev_err_probe(dev, -EINVAL,
667				     "Required bat info missing or invalid\n");
668
669	pdata->vsys_min = bat_info->voltage_min_design_uv;
670	pdata->vbat_max = bat_info->constant_charge_voltage_max_uv;
671	pdata->ichg_max = bat_info->constant_charge_current_max_ua;
672
673	power_supply_put_battery_info(pdata->charger, bat_info);
674
675	ret = device_property_read_u32(dev,
676				       "input-current-limit-microamp",
677				       &pdata->iindpm_max);
678	if (ret)
679		pdata->iindpm_max = BQ25703_IINDPM_DEFAULT_UA;
680
681	return 0;
682}
683
684static int bq257xx_charger_probe(struct platform_device *pdev)
685{
686	struct device *dev = &pdev->dev;
687	struct bq257xx_device *bq = dev_get_drvdata(pdev->dev.parent);
688	struct bq257xx_chg *pdata;
689	struct power_supply_config psy_cfg = { };
690	int ret;
691
692	device_set_of_node_from_dev(dev, pdev->dev.parent);
693
694	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
695	if (!pdata)
696		return -ENOMEM;
697
698	pdata->bq = bq;
699	pdata->chip = &bq25703_chip_info;
700
701	platform_set_drvdata(pdev, pdata);
702
703	psy_cfg.drv_data = pdata;
704	psy_cfg.fwnode = dev_fwnode(dev);
705
706	pdata->charger = devm_power_supply_register(dev,
707						    &bq257xx_power_supply_desc,
708						    &psy_cfg);
709	if (IS_ERR(pdata->charger))
710		return dev_err_probe(dev, PTR_ERR(pdata->charger),
711				     "Power supply register charger failed\n");
712
713	ret = bq257xx_parse_dt(pdata, &psy_cfg, dev);
714	if (ret)
715		return ret;
716
717	ret = pdata->chip->bq257xx_hw_init(pdata);
718	if (ret)
719		return dev_err_probe(dev, ret, "Cannot initialize the charger\n");
720
721	platform_set_drvdata(pdev, pdata);
722
723	if (bq->client->irq) {
724		ret = devm_request_threaded_irq(dev, bq->client->irq, NULL,
725						bq257xx_irq_handler_thread,
726						IRQF_TRIGGER_RISING |
727						IRQF_TRIGGER_FALLING |
728						IRQF_ONESHOT,
729						dev_name(&bq->client->dev), pdata);
730		if (ret < 0)
731			dev_err_probe(dev, ret, "Charger get irq failed\n");
732	}
733
734	return ret;
735}
736
737static void bq257xx_charger_shutdown(struct platform_device *pdev)
738{
739	struct bq257xx_chg *pdata = platform_get_drvdata(pdev);
740
741	pdata->chip->bq257xx_hw_shutdown(pdata);
742}
743
744static struct platform_driver bq257xx_chg_driver = {
745	.driver = {
746		.name = "bq257xx-charger",
747	},
748	.probe = bq257xx_charger_probe,
749	.shutdown = bq257xx_charger_shutdown,
750};
751module_platform_driver(bq257xx_chg_driver);
752
753MODULE_DESCRIPTION("bq257xx charger driver");
754MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>");
755MODULE_LICENSE("GPL");
~/ Read-only file preview.