Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2)  * Generic battery driver code using IIO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Copyright (C) 2012, Anish Kumar <anish198519851985@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * based on jz4740-battery.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * based on s3c_adc_battery.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * License.  See the file COPYING in the main directory of this archive for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/power_supply.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/jiffies.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/iio/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/iio/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <linux/power/generic-adc-battery.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #define JITTER_DEFAULT 10 /* hope 10ms is enough */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) enum gab_chan_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	GAB_VOLTAGE = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	GAB_CURRENT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	GAB_POWER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	GAB_MAX_CHAN_TYPE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)  * gab_chan_name suggests the standard channel names for commonly used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38)  * channel types.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) static const char *const gab_chan_name[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	[GAB_VOLTAGE]	= "voltage",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	[GAB_CURRENT]	= "current",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	[GAB_POWER]		= "power",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) struct gab {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	struct power_supply		*psy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	struct power_supply_desc	psy_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	struct iio_channel	*channel[GAB_MAX_CHAN_TYPE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	struct gab_platform_data	*pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	struct delayed_work bat_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	int	level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	int	status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	bool cable_plugged;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) static struct gab *to_generic_bat(struct power_supply *psy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	return power_supply_get_drvdata(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) static void gab_ext_power_changed(struct power_supply *psy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	struct gab *adc_bat = to_generic_bat(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	schedule_delayed_work(&adc_bat->bat_work, msecs_to_jiffies(0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) static const enum power_supply_property gab_props[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	POWER_SUPPLY_PROP_STATUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	POWER_SUPPLY_PROP_CHARGE_NOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	POWER_SUPPLY_PROP_CURRENT_NOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	POWER_SUPPLY_PROP_TECHNOLOGY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	POWER_SUPPLY_PROP_MODEL_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83)  * This properties are set based on the received platform data and this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84)  * should correspond one-to-one with enum chan_type.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) static const enum power_supply_property gab_dyn_props[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	POWER_SUPPLY_PROP_CURRENT_NOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	POWER_SUPPLY_PROP_POWER_NOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) static bool gab_charge_finished(struct gab *adc_bat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	struct gab_platform_data *pdata = adc_bat->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	bool ret = gpio_get_value(pdata->gpio_charge_finished);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	bool inv = pdata->gpio_inverted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	if (!gpio_is_valid(pdata->gpio_charge_finished))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	return ret ^ inv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static int gab_get_status(struct gab *adc_bat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	struct gab_platform_data *pdata = adc_bat->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	struct power_supply_info *bat_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	bat_info = &pdata->battery_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	if (adc_bat->level == bat_info->charge_full_design)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		return POWER_SUPPLY_STATUS_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	return adc_bat->status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static enum gab_chan_type gab_prop_to_chan(enum power_supply_property psp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	case POWER_SUPPLY_PROP_POWER_NOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 		return GAB_POWER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		return GAB_VOLTAGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	case POWER_SUPPLY_PROP_CURRENT_NOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 		return GAB_CURRENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 		WARN_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	return GAB_POWER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static int read_channel(struct gab *adc_bat, enum power_supply_property psp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		int *result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	int chan_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	chan_index = gab_prop_to_chan(psp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	ret = iio_read_channel_processed(adc_bat->channel[chan_index],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 			result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 		pr_err("read channel error\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static int gab_get_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		enum power_supply_property psp, union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	struct gab *adc_bat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	struct gab_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	struct power_supply_info *bat_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	adc_bat = to_generic_bat(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	if (!adc_bat) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 		dev_err(&psy->dev, "no battery infos ?!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	pdata = adc_bat->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	bat_info = &pdata->battery_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	case POWER_SUPPLY_PROP_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		val->intval = gab_get_status(adc_bat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		val->intval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	case POWER_SUPPLY_PROP_CHARGE_NOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		val->intval = pdata->cal_charge(result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	case POWER_SUPPLY_PROP_CURRENT_NOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	case POWER_SUPPLY_PROP_POWER_NOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 		ret = read_channel(adc_bat, psp, &result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		val->intval = result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	case POWER_SUPPLY_PROP_TECHNOLOGY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 		val->intval = bat_info->technology;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 		val->intval = bat_info->voltage_min_design;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		val->intval = bat_info->voltage_max_design;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		val->intval = bat_info->charge_full_design;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	case POWER_SUPPLY_PROP_MODEL_NAME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 		val->strval = bat_info->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static void gab_work(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	struct gab *adc_bat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	struct delayed_work *delayed_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	bool is_plugged;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	delayed_work = to_delayed_work(work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	adc_bat = container_of(delayed_work, struct gab, bat_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	status = adc_bat->status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	is_plugged = power_supply_am_i_supplied(adc_bat->psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	adc_bat->cable_plugged = is_plugged;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	if (!is_plugged)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		adc_bat->status =  POWER_SUPPLY_STATUS_DISCHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	else if (gab_charge_finished(adc_bat))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		adc_bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 		adc_bat->status = POWER_SUPPLY_STATUS_CHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	if (status != adc_bat->status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 		power_supply_changed(adc_bat->psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) static irqreturn_t gab_charged(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	struct gab *adc_bat = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	struct gab_platform_data *pdata = adc_bat->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	int delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	schedule_delayed_work(&adc_bat->bat_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 			msecs_to_jiffies(delay));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) static int gab_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	struct gab *adc_bat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	struct power_supply_desc *psy_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	struct power_supply_config psy_cfg = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	struct gab_platform_data *pdata = pdev->dev.platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	enum power_supply_property *properties;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	int chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	int index = ARRAY_SIZE(gab_props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	bool any = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	adc_bat = devm_kzalloc(&pdev->dev, sizeof(*adc_bat), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	if (!adc_bat) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 		dev_err(&pdev->dev, "failed to allocate memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	psy_cfg.drv_data = adc_bat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	psy_desc = &adc_bat->psy_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	psy_desc->name = pdata->battery_info.name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	/* bootup default values for the battery */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	adc_bat->cable_plugged = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	adc_bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	psy_desc->get_property = gab_get_property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	psy_desc->external_power_changed = gab_ext_power_changed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	adc_bat->pdata = pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	 * copying the static properties and allocating extra memory for holding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	 * the extra configurable properties received from platform data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	properties = kcalloc(ARRAY_SIZE(gab_props) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 			     ARRAY_SIZE(gab_chan_name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 			     sizeof(*properties),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 			     GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	if (!properties) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 		ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 		goto first_mem_fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	memcpy(properties, gab_props, sizeof(gab_props));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	 * getting channel from iio and copying the battery properties
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	 * based on the channel supported by consumer device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 		adc_bat->channel[chan] = iio_channel_get(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 							 gab_chan_name[chan]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 		if (IS_ERR(adc_bat->channel[chan])) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 			ret = PTR_ERR(adc_bat->channel[chan]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 			adc_bat->channel[chan] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 			/* copying properties for supported channels only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 			int index2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 			for (index2 = 0; index2 < index; index2++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 				if (properties[index2] == gab_dyn_props[chan])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 					break;	/* already known */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 			if (index2 == index)	/* really new */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 				properties[index++] = gab_dyn_props[chan];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 			any = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	/* none of the channels are supported so let's bail out */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 	if (!any) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 		ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		goto second_mem_fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	 * Total number of properties is equal to static properties
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	 * plus the dynamic properties.Some properties may not be set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	 * as come channels may be not be supported by the device.So
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 	 * we need to take care of that.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	psy_desc->properties = properties;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	psy_desc->num_properties = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 	adc_bat->psy = power_supply_register(&pdev->dev, psy_desc, &psy_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 	if (IS_ERR(adc_bat->psy)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 		ret = PTR_ERR(adc_bat->psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 		goto err_reg_fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 	INIT_DELAYED_WORK(&adc_bat->bat_work, gab_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 	if (gpio_is_valid(pdata->gpio_charge_finished)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 		int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 		ret = gpio_request(pdata->gpio_charge_finished, "charged");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 			goto gpio_req_fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 		irq = gpio_to_irq(pdata->gpio_charge_finished);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 		ret = request_any_context_irq(irq, gab_charged,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 				"battery charged", adc_bat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 		if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 			goto err_gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	platform_set_drvdata(pdev, adc_bat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	/* Schedule timer to check current status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	schedule_delayed_work(&adc_bat->bat_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 			msecs_to_jiffies(0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) err_gpio:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	gpio_free(pdata->gpio_charge_finished);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) gpio_req_fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 	power_supply_unregister(adc_bat->psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) err_reg_fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 		if (adc_bat->channel[chan])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 			iio_channel_release(adc_bat->channel[chan]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) second_mem_fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 	kfree(properties);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) first_mem_fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) static int gab_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 	int chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 	struct gab *adc_bat = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 	struct gab_platform_data *pdata = adc_bat->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 	power_supply_unregister(adc_bat->psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 	if (gpio_is_valid(pdata->gpio_charge_finished)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 		free_irq(gpio_to_irq(pdata->gpio_charge_finished), adc_bat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 		gpio_free(pdata->gpio_charge_finished);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 	for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 		if (adc_bat->channel[chan])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 			iio_channel_release(adc_bat->channel[chan]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 	kfree(adc_bat->psy_desc.properties);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	cancel_delayed_work_sync(&adc_bat->bat_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) static int __maybe_unused gab_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 	struct gab *adc_bat = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 	cancel_delayed_work_sync(&adc_bat->bat_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 	adc_bat->status = POWER_SUPPLY_STATUS_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) static int __maybe_unused gab_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	struct gab *adc_bat = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 	struct gab_platform_data *pdata = adc_bat->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	int delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 	delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	/* Schedule timer to check current status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 	schedule_delayed_work(&adc_bat->bat_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 			msecs_to_jiffies(delay));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) static SIMPLE_DEV_PM_OPS(gab_pm_ops, gab_suspend, gab_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) static struct platform_driver gab_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 	.driver		= {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 		.name	= "generic-adc-battery",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 		.pm	= &gab_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 	.probe		= gab_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 	.remove		= gab_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) module_platform_driver(gab_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) MODULE_AUTHOR("anish kumar <anish198519851985@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) MODULE_DESCRIPTION("generic battery driver using IIO");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) MODULE_LICENSE("GPL");