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) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Battery measurement code for Zipit Z2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2009 Peter Edwards <sweetlilmre@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/power_supply.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/z2_battery.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #define	Z2_DEFAULT_NAME	"Z2"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) struct z2_charger {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 	struct z2_battery_info		*info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 	int				bat_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	struct i2c_client		*client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	struct power_supply		*batt_ps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	struct power_supply_desc	batt_ps_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 	struct mutex			work_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	struct work_struct		bat_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) static unsigned long z2_read_bat(struct z2_charger *charger)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	int data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	data = i2c_smbus_read_byte_data(charger->client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 					charger->info->batt_I2C_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	if (data < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	return data * charger->info->batt_mult / charger->info->batt_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) static int z2_batt_get_property(struct power_supply *batt_ps,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 			    enum power_supply_property psp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 			    union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	struct z2_charger *charger = power_supply_get_drvdata(batt_ps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	struct z2_battery_info *info = charger->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	case POWER_SUPPLY_PROP_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 		val->intval = charger->bat_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	case POWER_SUPPLY_PROP_TECHNOLOGY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 		val->intval = info->batt_tech;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 		if (info->batt_I2C_reg >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 			val->intval = z2_read_bat(charger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 		if (info->max_voltage >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 			val->intval = info->max_voltage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 		if (info->min_voltage >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 			val->intval = info->min_voltage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	case POWER_SUPPLY_PROP_PRESENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 		val->intval = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	return 0;
^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) static void z2_batt_ext_power_changed(struct power_supply *batt_ps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	struct z2_charger *charger = power_supply_get_drvdata(batt_ps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	schedule_work(&charger->bat_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) static void z2_batt_update(struct z2_charger *charger)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	int old_status = charger->bat_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	struct z2_battery_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	info = charger->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	mutex_lock(&charger->work_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	charger->bat_status = (info->charge_gpio >= 0) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		(gpio_get_value(info->charge_gpio) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		POWER_SUPPLY_STATUS_CHARGING :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 		POWER_SUPPLY_STATUS_DISCHARGING) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 		POWER_SUPPLY_STATUS_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	if (old_status != charger->bat_status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 		pr_debug("%s: %i -> %i\n", charger->batt_ps->desc->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 				old_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 				charger->bat_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		power_supply_changed(charger->batt_ps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	mutex_unlock(&charger->work_lock);
^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 void z2_batt_work(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	struct z2_charger *charger;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	charger = container_of(work, struct z2_charger, bat_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	z2_batt_update(charger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static irqreturn_t z2_charge_switch_irq(int irq, void *devid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	struct z2_charger *charger = devid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	schedule_work(&charger->bat_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static int z2_batt_ps_init(struct z2_charger *charger, int props)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	enum power_supply_property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	struct z2_battery_info *info = charger->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	if (info->charge_gpio >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		props++;	/* POWER_SUPPLY_PROP_STATUS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	if (info->batt_tech >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 		props++;	/* POWER_SUPPLY_PROP_TECHNOLOGY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	if (info->batt_I2C_reg >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 		props++;	/* POWER_SUPPLY_PROP_VOLTAGE_NOW */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	if (info->max_voltage >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 		props++;	/* POWER_SUPPLY_PROP_VOLTAGE_MAX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	if (info->min_voltage >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 		props++;	/* POWER_SUPPLY_PROP_VOLTAGE_MIN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	prop = kcalloc(props, sizeof(*prop), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	if (!prop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	prop[i++] = POWER_SUPPLY_PROP_PRESENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	if (info->charge_gpio >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 		prop[i++] = POWER_SUPPLY_PROP_STATUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	if (info->batt_tech >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 		prop[i++] = POWER_SUPPLY_PROP_TECHNOLOGY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	if (info->batt_I2C_reg >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 		prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	if (info->max_voltage >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 		prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	if (info->min_voltage >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 		prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	if (!info->batt_name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 		dev_info(&charger->client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 				"Please consider setting proper battery "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 				"name in platform definition file, falling "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 				"back to name \" Z2_DEFAULT_NAME \"\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		charger->batt_ps_desc.name = Z2_DEFAULT_NAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		charger->batt_ps_desc.name = info->batt_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	charger->batt_ps_desc.properties	= prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	charger->batt_ps_desc.num_properties	= props;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	charger->batt_ps_desc.type		= POWER_SUPPLY_TYPE_BATTERY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	charger->batt_ps_desc.get_property	= z2_batt_get_property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	charger->batt_ps_desc.external_power_changed =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 						z2_batt_ext_power_changed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	charger->batt_ps_desc.use_for_apm	= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static int z2_batt_probe(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 				const struct i2c_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	int props = 1;	/* POWER_SUPPLY_PROP_PRESENT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	struct z2_charger *charger;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	struct z2_battery_info *info = client->dev.platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	struct power_supply_config psy_cfg = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	if (info == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 		dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 			"Please set platform device platform_data"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 			" to a valid z2_battery_info pointer!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	charger = kzalloc(sizeof(*charger), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	if (charger == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	charger->bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	charger->info = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	charger->client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	i2c_set_clientdata(client, charger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	psy_cfg.drv_data = charger;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	mutex_init(&charger->work_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		ret = gpio_request(info->charge_gpio, "BATT CHRG");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		ret = gpio_direction_input(info->charge_gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 			goto err2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		irq_set_irq_type(gpio_to_irq(info->charge_gpio),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 				 IRQ_TYPE_EDGE_BOTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 		ret = request_irq(gpio_to_irq(info->charge_gpio),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 				z2_charge_switch_irq, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 				"AC Detect", charger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 			goto err3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	ret = z2_batt_ps_init(charger, props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 		goto err3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 	INIT_WORK(&charger->bat_work, z2_batt_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	charger->batt_ps = power_supply_register(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 						 &charger->batt_ps_desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 						 &psy_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	if (IS_ERR(charger->batt_ps)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 		ret = PTR_ERR(charger->batt_ps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 		goto err4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	schedule_work(&charger->bat_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) err4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	kfree(charger->batt_ps_desc.properties);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) err3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 		free_irq(gpio_to_irq(info->charge_gpio), charger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) err2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 		gpio_free(info->charge_gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	kfree(charger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) static int z2_batt_remove(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	struct z2_charger *charger = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	struct z2_battery_info *info = charger->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	cancel_work_sync(&charger->bat_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	power_supply_unregister(charger->batt_ps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	kfree(charger->batt_ps_desc.properties);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 		free_irq(gpio_to_irq(info->charge_gpio), charger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 		gpio_free(info->charge_gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	kfree(charger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) static int z2_batt_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	struct z2_charger *charger = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	flush_work(&charger->bat_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) static int z2_batt_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 	struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 	struct z2_charger *charger = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	schedule_work(&charger->bat_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static const struct dev_pm_ops z2_battery_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	.suspend	= z2_batt_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	.resume		= z2_batt_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) #define	Z2_BATTERY_PM_OPS	(&z2_battery_pm_ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) #define	Z2_BATTERY_PM_OPS	(NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) static const struct i2c_device_id z2_batt_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 	{ "aer915", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	{ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) MODULE_DEVICE_TABLE(i2c, z2_batt_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) static struct i2c_driver z2_batt_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	.driver	= {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 		.name	= "z2-battery",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 		.pm	= Z2_BATTERY_PM_OPS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 	.probe		= z2_batt_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	.remove		= z2_batt_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	.id_table	= z2_batt_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) module_i2c_driver(z2_batt_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) MODULE_AUTHOR("Peter Edwards <sweetlilmre@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) MODULE_DESCRIPTION("Zipit Z2 battery driver");