162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Power supply driver for the RICOH RN5T618 power management chip family 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020 Andreas Kemnade 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/device.h> 1062306a36Sopenharmony_ci#include <linux/bitops.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/iio/consumer.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/mfd/rn5t618.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <linux/power_supply.h> 1962306a36Sopenharmony_ci#include <linux/regmap.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define CHG_STATE_ADP_INPUT 0x40 2362306a36Sopenharmony_ci#define CHG_STATE_USB_INPUT 0x80 2462306a36Sopenharmony_ci#define CHG_STATE_MASK 0x1f 2562306a36Sopenharmony_ci#define CHG_STATE_CHG_OFF 0 2662306a36Sopenharmony_ci#define CHG_STATE_CHG_READY_VADP 1 2762306a36Sopenharmony_ci#define CHG_STATE_CHG_TRICKLE 2 2862306a36Sopenharmony_ci#define CHG_STATE_CHG_RAPID 3 2962306a36Sopenharmony_ci#define CHG_STATE_CHG_COMPLETE 4 3062306a36Sopenharmony_ci#define CHG_STATE_SUSPEND 5 3162306a36Sopenharmony_ci#define CHG_STATE_VCHG_OVER_VOL 6 3262306a36Sopenharmony_ci#define CHG_STATE_BAT_ERROR 7 3362306a36Sopenharmony_ci#define CHG_STATE_NO_BAT 8 3462306a36Sopenharmony_ci#define CHG_STATE_BAT_OVER_VOL 9 3562306a36Sopenharmony_ci#define CHG_STATE_BAT_TEMP_ERR 10 3662306a36Sopenharmony_ci#define CHG_STATE_DIE_ERR 11 3762306a36Sopenharmony_ci#define CHG_STATE_DIE_SHUTDOWN 12 3862306a36Sopenharmony_ci#define CHG_STATE_NO_BAT2 13 3962306a36Sopenharmony_ci#define CHG_STATE_CHG_READY_VUSB 14 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define GCHGDET_TYPE_MASK 0x30 4262306a36Sopenharmony_ci#define GCHGDET_TYPE_SDP 0x00 4362306a36Sopenharmony_ci#define GCHGDET_TYPE_CDP 0x10 4462306a36Sopenharmony_ci#define GCHGDET_TYPE_DCP 0x20 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define FG_ENABLE 1 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* 4962306a36Sopenharmony_ci * Formula seems accurate for battery current, but for USB current around 70mA 5062306a36Sopenharmony_ci * per step was seen on Kobo Clara HD but all sources show the same formula 5162306a36Sopenharmony_ci * also fur USB current. To avoid accidentially unwanted high currents we stick 5262306a36Sopenharmony_ci * to that formula 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci#define TO_CUR_REG(x) ((x) / 100000 - 1) 5562306a36Sopenharmony_ci#define FROM_CUR_REG(x) ((((x) & 0x1f) + 1) * 100000) 5662306a36Sopenharmony_ci#define CHG_MIN_CUR 100000 5762306a36Sopenharmony_ci#define CHG_MAX_CUR 1800000 5862306a36Sopenharmony_ci#define ADP_MAX_CUR 2500000 5962306a36Sopenharmony_ci#define USB_MAX_CUR 1400000 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistruct rn5t618_power_info { 6362306a36Sopenharmony_ci struct rn5t618 *rn5t618; 6462306a36Sopenharmony_ci struct platform_device *pdev; 6562306a36Sopenharmony_ci struct power_supply *battery; 6662306a36Sopenharmony_ci struct power_supply *usb; 6762306a36Sopenharmony_ci struct power_supply *adp; 6862306a36Sopenharmony_ci struct iio_channel *channel_vusb; 6962306a36Sopenharmony_ci struct iio_channel *channel_vadp; 7062306a36Sopenharmony_ci int irq; 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic enum power_supply_usb_type rn5t618_usb_types[] = { 7462306a36Sopenharmony_ci POWER_SUPPLY_USB_TYPE_SDP, 7562306a36Sopenharmony_ci POWER_SUPPLY_USB_TYPE_DCP, 7662306a36Sopenharmony_ci POWER_SUPPLY_USB_TYPE_CDP, 7762306a36Sopenharmony_ci POWER_SUPPLY_USB_TYPE_UNKNOWN 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic enum power_supply_property rn5t618_usb_props[] = { 8162306a36Sopenharmony_ci /* input current limit is not very accurate */ 8262306a36Sopenharmony_ci POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 8362306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_NOW, 8462306a36Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 8562306a36Sopenharmony_ci POWER_SUPPLY_PROP_USB_TYPE, 8662306a36Sopenharmony_ci POWER_SUPPLY_PROP_ONLINE, 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic enum power_supply_property rn5t618_adp_props[] = { 9062306a36Sopenharmony_ci /* input current limit is not very accurate */ 9162306a36Sopenharmony_ci POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 9262306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_NOW, 9362306a36Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 9462306a36Sopenharmony_ci POWER_SUPPLY_PROP_ONLINE, 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic enum power_supply_property rn5t618_battery_props[] = { 9962306a36Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 10062306a36Sopenharmony_ci POWER_SUPPLY_PROP_PRESENT, 10162306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_NOW, 10262306a36Sopenharmony_ci POWER_SUPPLY_PROP_CURRENT_NOW, 10362306a36Sopenharmony_ci POWER_SUPPLY_PROP_CAPACITY, 10462306a36Sopenharmony_ci POWER_SUPPLY_PROP_TEMP, 10562306a36Sopenharmony_ci POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 10662306a36Sopenharmony_ci POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 10762306a36Sopenharmony_ci POWER_SUPPLY_PROP_TECHNOLOGY, 10862306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, 10962306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_FULL, 11062306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_NOW, 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int rn5t618_battery_read_doublereg(struct rn5t618_power_info *info, 11462306a36Sopenharmony_ci u8 reg, u16 *result) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci int ret, i; 11762306a36Sopenharmony_ci u8 data[2]; 11862306a36Sopenharmony_ci u16 old, new; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci old = 0; 12162306a36Sopenharmony_ci /* Prevent races when registers are changing. */ 12262306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 12362306a36Sopenharmony_ci ret = regmap_bulk_read(info->rn5t618->regmap, 12462306a36Sopenharmony_ci reg, data, sizeof(data)); 12562306a36Sopenharmony_ci if (ret) 12662306a36Sopenharmony_ci return ret; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci new = data[0] << 8; 12962306a36Sopenharmony_ci new |= data[1]; 13062306a36Sopenharmony_ci if (new == old) 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci old = new; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci *result = new; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int rn5t618_decode_status(unsigned int status) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci switch (status & CHG_STATE_MASK) { 14462306a36Sopenharmony_ci case CHG_STATE_CHG_OFF: 14562306a36Sopenharmony_ci case CHG_STATE_SUSPEND: 14662306a36Sopenharmony_ci case CHG_STATE_VCHG_OVER_VOL: 14762306a36Sopenharmony_ci case CHG_STATE_DIE_SHUTDOWN: 14862306a36Sopenharmony_ci return POWER_SUPPLY_STATUS_DISCHARGING; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci case CHG_STATE_CHG_TRICKLE: 15162306a36Sopenharmony_ci case CHG_STATE_CHG_RAPID: 15262306a36Sopenharmony_ci return POWER_SUPPLY_STATUS_CHARGING; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci case CHG_STATE_CHG_COMPLETE: 15562306a36Sopenharmony_ci return POWER_SUPPLY_STATUS_FULL; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci default: 15862306a36Sopenharmony_ci return POWER_SUPPLY_STATUS_NOT_CHARGING; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int rn5t618_battery_status(struct rn5t618_power_info *info, 16362306a36Sopenharmony_ci union power_supply_propval *val) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci unsigned int v; 16662306a36Sopenharmony_ci int ret; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v); 16962306a36Sopenharmony_ci if (ret) 17062306a36Sopenharmony_ci return ret; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (v & 0xc0) { /* USB or ADP plugged */ 17562306a36Sopenharmony_ci val->intval = rn5t618_decode_status(v); 17662306a36Sopenharmony_ci } else 17762306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return ret; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int rn5t618_battery_present(struct rn5t618_power_info *info, 18362306a36Sopenharmony_ci union power_supply_propval *val) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci unsigned int v; 18662306a36Sopenharmony_ci int ret; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v); 18962306a36Sopenharmony_ci if (ret) 19062306a36Sopenharmony_ci return ret; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci v &= CHG_STATE_MASK; 19362306a36Sopenharmony_ci if ((v == CHG_STATE_NO_BAT) || (v == CHG_STATE_NO_BAT2)) 19462306a36Sopenharmony_ci val->intval = 0; 19562306a36Sopenharmony_ci else 19662306a36Sopenharmony_ci val->intval = 1; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return ret; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic int rn5t618_battery_voltage_now(struct rn5t618_power_info *info, 20262306a36Sopenharmony_ci union power_supply_propval *val) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci u16 res; 20562306a36Sopenharmony_ci int ret; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci ret = rn5t618_battery_read_doublereg(info, RN5T618_VOLTAGE_1, &res); 20862306a36Sopenharmony_ci if (ret) 20962306a36Sopenharmony_ci return ret; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci val->intval = res * 2 * 2500 / 4095 * 1000; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int rn5t618_battery_current_now(struct rn5t618_power_info *info, 21762306a36Sopenharmony_ci union power_supply_propval *val) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci u16 res; 22062306a36Sopenharmony_ci int ret; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci ret = rn5t618_battery_read_doublereg(info, RN5T618_CC_AVEREG1, &res); 22362306a36Sopenharmony_ci if (ret) 22462306a36Sopenharmony_ci return ret; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* current is negative when discharging */ 22762306a36Sopenharmony_ci val->intval = sign_extend32(res, 13) * 1000; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int rn5t618_battery_capacity(struct rn5t618_power_info *info, 23362306a36Sopenharmony_ci union power_supply_propval *val) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci unsigned int v; 23662306a36Sopenharmony_ci int ret; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci ret = regmap_read(info->rn5t618->regmap, RN5T618_SOC, &v); 23962306a36Sopenharmony_ci if (ret) 24062306a36Sopenharmony_ci return ret; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci val->intval = v; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic int rn5t618_battery_temp(struct rn5t618_power_info *info, 24862306a36Sopenharmony_ci union power_supply_propval *val) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci u16 res; 25162306a36Sopenharmony_ci int ret; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci ret = rn5t618_battery_read_doublereg(info, RN5T618_TEMP_1, &res); 25462306a36Sopenharmony_ci if (ret) 25562306a36Sopenharmony_ci return ret; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci val->intval = sign_extend32(res, 11) * 10 / 16; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return 0; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int rn5t618_battery_tte(struct rn5t618_power_info *info, 26362306a36Sopenharmony_ci union power_supply_propval *val) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci u16 res; 26662306a36Sopenharmony_ci int ret; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_EMPTY_H, &res); 26962306a36Sopenharmony_ci if (ret) 27062306a36Sopenharmony_ci return ret; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (res == 65535) 27362306a36Sopenharmony_ci return -ENODATA; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci val->intval = res * 60; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic int rn5t618_battery_ttf(struct rn5t618_power_info *info, 28162306a36Sopenharmony_ci union power_supply_propval *val) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci u16 res; 28462306a36Sopenharmony_ci int ret; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_FULL_H, &res); 28762306a36Sopenharmony_ci if (ret) 28862306a36Sopenharmony_ci return ret; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (res == 65535) 29162306a36Sopenharmony_ci return -ENODATA; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci val->intval = res * 60; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int rn5t618_battery_set_current_limit(struct rn5t618_power_info *info, 29962306a36Sopenharmony_ci const union power_supply_propval *val) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci if (val->intval < CHG_MIN_CUR) 30262306a36Sopenharmony_ci return -EINVAL; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (val->intval >= CHG_MAX_CUR) 30562306a36Sopenharmony_ci return -EINVAL; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return regmap_update_bits(info->rn5t618->regmap, 30862306a36Sopenharmony_ci RN5T618_CHGISET, 30962306a36Sopenharmony_ci 0x1F, TO_CUR_REG(val->intval)); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic int rn5t618_battery_get_current_limit(struct rn5t618_power_info *info, 31362306a36Sopenharmony_ci union power_supply_propval *val) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci unsigned int regval; 31662306a36Sopenharmony_ci int ret; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGISET, 31962306a36Sopenharmony_ci ®val); 32062306a36Sopenharmony_ci if (ret < 0) 32162306a36Sopenharmony_ci return ret; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci val->intval = FROM_CUR_REG(regval); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic int rn5t618_battery_charge_full(struct rn5t618_power_info *info, 32962306a36Sopenharmony_ci union power_supply_propval *val) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci u16 res; 33262306a36Sopenharmony_ci int ret; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci ret = rn5t618_battery_read_doublereg(info, RN5T618_FA_CAP_H, &res); 33562306a36Sopenharmony_ci if (ret) 33662306a36Sopenharmony_ci return ret; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci val->intval = res * 1000; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int rn5t618_battery_charge_now(struct rn5t618_power_info *info, 34462306a36Sopenharmony_ci union power_supply_propval *val) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci u16 res; 34762306a36Sopenharmony_ci int ret; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci ret = rn5t618_battery_read_doublereg(info, RN5T618_RE_CAP_H, &res); 35062306a36Sopenharmony_ci if (ret) 35162306a36Sopenharmony_ci return ret; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci val->intval = res * 1000; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int rn5t618_battery_get_property(struct power_supply *psy, 35962306a36Sopenharmony_ci enum power_supply_property psp, 36062306a36Sopenharmony_ci union power_supply_propval *val) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci int ret = 0; 36362306a36Sopenharmony_ci struct rn5t618_power_info *info = power_supply_get_drvdata(psy); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci switch (psp) { 36662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 36762306a36Sopenharmony_ci ret = rn5t618_battery_status(info, val); 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci case POWER_SUPPLY_PROP_PRESENT: 37062306a36Sopenharmony_ci ret = rn5t618_battery_present(info, val); 37162306a36Sopenharmony_ci break; 37262306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_NOW: 37362306a36Sopenharmony_ci ret = rn5t618_battery_voltage_now(info, val); 37462306a36Sopenharmony_ci break; 37562306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CURRENT_NOW: 37662306a36Sopenharmony_ci ret = rn5t618_battery_current_now(info, val); 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CAPACITY: 37962306a36Sopenharmony_ci ret = rn5t618_battery_capacity(info, val); 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP: 38262306a36Sopenharmony_ci ret = rn5t618_battery_temp(info, val); 38362306a36Sopenharmony_ci break; 38462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: 38562306a36Sopenharmony_ci ret = rn5t618_battery_tte(info, val); 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: 38862306a36Sopenharmony_ci ret = rn5t618_battery_ttf(info, val); 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TECHNOLOGY: 39162306a36Sopenharmony_ci val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 39462306a36Sopenharmony_ci ret = rn5t618_battery_get_current_limit(info, val); 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_FULL: 39762306a36Sopenharmony_ci ret = rn5t618_battery_charge_full(info, val); 39862306a36Sopenharmony_ci break; 39962306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_NOW: 40062306a36Sopenharmony_ci ret = rn5t618_battery_charge_now(info, val); 40162306a36Sopenharmony_ci break; 40262306a36Sopenharmony_ci default: 40362306a36Sopenharmony_ci return -EINVAL; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return ret; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic int rn5t618_battery_set_property(struct power_supply *psy, 41062306a36Sopenharmony_ci enum power_supply_property psp, 41162306a36Sopenharmony_ci const union power_supply_propval *val) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct rn5t618_power_info *info = power_supply_get_drvdata(psy); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci switch (psp) { 41662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 41762306a36Sopenharmony_ci return rn5t618_battery_set_current_limit(info, val); 41862306a36Sopenharmony_ci default: 41962306a36Sopenharmony_ci return -EINVAL; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic int rn5t618_battery_property_is_writeable(struct power_supply *psy, 42462306a36Sopenharmony_ci enum power_supply_property psp) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci switch (psp) { 42762306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 42862306a36Sopenharmony_ci return true; 42962306a36Sopenharmony_ci default: 43062306a36Sopenharmony_ci return false; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic int rn5t618_adp_get_property(struct power_supply *psy, 43562306a36Sopenharmony_ci enum power_supply_property psp, 43662306a36Sopenharmony_ci union power_supply_propval *val) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct rn5t618_power_info *info = power_supply_get_drvdata(psy); 43962306a36Sopenharmony_ci unsigned int chgstate; 44062306a36Sopenharmony_ci unsigned int regval; 44162306a36Sopenharmony_ci bool online; 44262306a36Sopenharmony_ci int ret; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate); 44562306a36Sopenharmony_ci if (ret) 44662306a36Sopenharmony_ci return ret; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci online = !!(chgstate & CHG_STATE_ADP_INPUT); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci switch (psp) { 45162306a36Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 45262306a36Sopenharmony_ci val->intval = online; 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 45562306a36Sopenharmony_ci if (!online) { 45662306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci val->intval = rn5t618_decode_status(chgstate); 46062306a36Sopenharmony_ci if (val->intval != POWER_SUPPLY_STATUS_CHARGING) 46162306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 46562306a36Sopenharmony_ci ret = regmap_read(info->rn5t618->regmap, 46662306a36Sopenharmony_ci RN5T618_REGISET1, ®val); 46762306a36Sopenharmony_ci if (ret < 0) 46862306a36Sopenharmony_ci return ret; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci val->intval = FROM_CUR_REG(regval); 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_NOW: 47362306a36Sopenharmony_ci if (!info->channel_vadp) 47462306a36Sopenharmony_ci return -ENODATA; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci ret = iio_read_channel_processed_scale(info->channel_vadp, &val->intval, 1000); 47762306a36Sopenharmony_ci if (ret < 0) 47862306a36Sopenharmony_ci return ret; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci default: 48262306a36Sopenharmony_ci return -EINVAL; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int rn5t618_adp_set_property(struct power_supply *psy, 48962306a36Sopenharmony_ci enum power_supply_property psp, 49062306a36Sopenharmony_ci const union power_supply_propval *val) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct rn5t618_power_info *info = power_supply_get_drvdata(psy); 49362306a36Sopenharmony_ci int ret; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci switch (psp) { 49662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 49762306a36Sopenharmony_ci if (val->intval > ADP_MAX_CUR) 49862306a36Sopenharmony_ci return -EINVAL; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (val->intval < CHG_MIN_CUR) 50162306a36Sopenharmony_ci return -EINVAL; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET1, 50462306a36Sopenharmony_ci TO_CUR_REG(val->intval)); 50562306a36Sopenharmony_ci if (ret < 0) 50662306a36Sopenharmony_ci return ret; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci break; 50962306a36Sopenharmony_ci default: 51062306a36Sopenharmony_ci return -EINVAL; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return 0; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic int rn5t618_adp_property_is_writeable(struct power_supply *psy, 51762306a36Sopenharmony_ci enum power_supply_property psp) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci switch (psp) { 52062306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 52162306a36Sopenharmony_ci return true; 52262306a36Sopenharmony_ci default: 52362306a36Sopenharmony_ci return false; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic int rc5t619_usb_get_type(struct rn5t618_power_info *info, 52862306a36Sopenharmony_ci union power_supply_propval *val) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci unsigned int regval; 53162306a36Sopenharmony_ci int ret; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci ret = regmap_read(info->rn5t618->regmap, RN5T618_GCHGDET, ®val); 53462306a36Sopenharmony_ci if (ret < 0) 53562306a36Sopenharmony_ci return ret; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci switch (regval & GCHGDET_TYPE_MASK) { 53862306a36Sopenharmony_ci case GCHGDET_TYPE_SDP: 53962306a36Sopenharmony_ci val->intval = POWER_SUPPLY_USB_TYPE_SDP; 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci case GCHGDET_TYPE_CDP: 54262306a36Sopenharmony_ci val->intval = POWER_SUPPLY_USB_TYPE_CDP; 54362306a36Sopenharmony_ci break; 54462306a36Sopenharmony_ci case GCHGDET_TYPE_DCP: 54562306a36Sopenharmony_ci val->intval = POWER_SUPPLY_USB_TYPE_DCP; 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci default: 54862306a36Sopenharmony_ci val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic int rn5t618_usb_get_property(struct power_supply *psy, 55562306a36Sopenharmony_ci enum power_supply_property psp, 55662306a36Sopenharmony_ci union power_supply_propval *val) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct rn5t618_power_info *info = power_supply_get_drvdata(psy); 55962306a36Sopenharmony_ci unsigned int chgstate; 56062306a36Sopenharmony_ci unsigned int regval; 56162306a36Sopenharmony_ci bool online; 56262306a36Sopenharmony_ci int ret; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate); 56562306a36Sopenharmony_ci if (ret) 56662306a36Sopenharmony_ci return ret; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci online = !!(chgstate & CHG_STATE_USB_INPUT); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci switch (psp) { 57162306a36Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 57262306a36Sopenharmony_ci val->intval = online; 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 57562306a36Sopenharmony_ci if (!online) { 57662306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 57762306a36Sopenharmony_ci break; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci val->intval = rn5t618_decode_status(chgstate); 58062306a36Sopenharmony_ci if (val->intval != POWER_SUPPLY_STATUS_CHARGING) 58162306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_USB_TYPE: 58562306a36Sopenharmony_ci if (!online || (info->rn5t618->variant != RC5T619)) 58662306a36Sopenharmony_ci return -ENODATA; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return rc5t619_usb_get_type(info, val); 58962306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 59062306a36Sopenharmony_ci ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGCTL1, 59162306a36Sopenharmony_ci ®val); 59262306a36Sopenharmony_ci if (ret < 0) 59362306a36Sopenharmony_ci return ret; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci val->intval = 0; 59662306a36Sopenharmony_ci if (regval & 2) { 59762306a36Sopenharmony_ci ret = regmap_read(info->rn5t618->regmap, 59862306a36Sopenharmony_ci RN5T618_REGISET2, 59962306a36Sopenharmony_ci ®val); 60062306a36Sopenharmony_ci if (ret < 0) 60162306a36Sopenharmony_ci return ret; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci val->intval = FROM_CUR_REG(regval); 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_NOW: 60762306a36Sopenharmony_ci if (!info->channel_vusb) 60862306a36Sopenharmony_ci return -ENODATA; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci ret = iio_read_channel_processed_scale(info->channel_vusb, &val->intval, 1000); 61162306a36Sopenharmony_ci if (ret < 0) 61262306a36Sopenharmony_ci return ret; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci default: 61662306a36Sopenharmony_ci return -EINVAL; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return 0; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic int rn5t618_usb_set_property(struct power_supply *psy, 62362306a36Sopenharmony_ci enum power_supply_property psp, 62462306a36Sopenharmony_ci const union power_supply_propval *val) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct rn5t618_power_info *info = power_supply_get_drvdata(psy); 62762306a36Sopenharmony_ci int ret; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci switch (psp) { 63062306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 63162306a36Sopenharmony_ci if (val->intval > USB_MAX_CUR) 63262306a36Sopenharmony_ci return -EINVAL; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (val->intval < CHG_MIN_CUR) 63562306a36Sopenharmony_ci return -EINVAL; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET2, 63862306a36Sopenharmony_ci 0xE0 | TO_CUR_REG(val->intval)); 63962306a36Sopenharmony_ci if (ret < 0) 64062306a36Sopenharmony_ci return ret; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci default: 64462306a36Sopenharmony_ci return -EINVAL; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci return 0; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic int rn5t618_usb_property_is_writeable(struct power_supply *psy, 65162306a36Sopenharmony_ci enum power_supply_property psp) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci switch (psp) { 65462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 65562306a36Sopenharmony_ci return true; 65662306a36Sopenharmony_ci default: 65762306a36Sopenharmony_ci return false; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic const struct power_supply_desc rn5t618_battery_desc = { 66262306a36Sopenharmony_ci .name = "rn5t618-battery", 66362306a36Sopenharmony_ci .type = POWER_SUPPLY_TYPE_BATTERY, 66462306a36Sopenharmony_ci .properties = rn5t618_battery_props, 66562306a36Sopenharmony_ci .num_properties = ARRAY_SIZE(rn5t618_battery_props), 66662306a36Sopenharmony_ci .get_property = rn5t618_battery_get_property, 66762306a36Sopenharmony_ci .set_property = rn5t618_battery_set_property, 66862306a36Sopenharmony_ci .property_is_writeable = rn5t618_battery_property_is_writeable, 66962306a36Sopenharmony_ci}; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic const struct power_supply_desc rn5t618_adp_desc = { 67262306a36Sopenharmony_ci .name = "rn5t618-adp", 67362306a36Sopenharmony_ci .type = POWER_SUPPLY_TYPE_MAINS, 67462306a36Sopenharmony_ci .properties = rn5t618_adp_props, 67562306a36Sopenharmony_ci .num_properties = ARRAY_SIZE(rn5t618_adp_props), 67662306a36Sopenharmony_ci .get_property = rn5t618_adp_get_property, 67762306a36Sopenharmony_ci .set_property = rn5t618_adp_set_property, 67862306a36Sopenharmony_ci .property_is_writeable = rn5t618_adp_property_is_writeable, 67962306a36Sopenharmony_ci}; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic const struct power_supply_desc rn5t618_usb_desc = { 68262306a36Sopenharmony_ci .name = "rn5t618-usb", 68362306a36Sopenharmony_ci .type = POWER_SUPPLY_TYPE_USB, 68462306a36Sopenharmony_ci .usb_types = rn5t618_usb_types, 68562306a36Sopenharmony_ci .num_usb_types = ARRAY_SIZE(rn5t618_usb_types), 68662306a36Sopenharmony_ci .properties = rn5t618_usb_props, 68762306a36Sopenharmony_ci .num_properties = ARRAY_SIZE(rn5t618_usb_props), 68862306a36Sopenharmony_ci .get_property = rn5t618_usb_get_property, 68962306a36Sopenharmony_ci .set_property = rn5t618_usb_set_property, 69062306a36Sopenharmony_ci .property_is_writeable = rn5t618_usb_property_is_writeable, 69162306a36Sopenharmony_ci}; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic irqreturn_t rn5t618_charger_irq(int irq, void *data) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct device *dev = data; 69662306a36Sopenharmony_ci struct rn5t618_power_info *info = dev_get_drvdata(dev); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci unsigned int ctrl, stat1, stat2, err; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci regmap_read(info->rn5t618->regmap, RN5T618_CHGERR_IRR, &err); 70162306a36Sopenharmony_ci regmap_read(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, &ctrl); 70262306a36Sopenharmony_ci regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, &stat1); 70362306a36Sopenharmony_ci regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, &stat2); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci regmap_write(info->rn5t618->regmap, RN5T618_CHGERR_IRR, 0); 70662306a36Sopenharmony_ci regmap_write(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, 0); 70762306a36Sopenharmony_ci regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, 0); 70862306a36Sopenharmony_ci regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, 0); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci dev_dbg(dev, "chgerr: %x chgctrl: %x chgstat: %x chgstat2: %x\n", 71162306a36Sopenharmony_ci err, ctrl, stat1, stat2); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci power_supply_changed(info->usb); 71462306a36Sopenharmony_ci power_supply_changed(info->adp); 71562306a36Sopenharmony_ci power_supply_changed(info->battery); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci return IRQ_HANDLED; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic int rn5t618_power_probe(struct platform_device *pdev) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci int ret = 0; 72362306a36Sopenharmony_ci unsigned int v; 72462306a36Sopenharmony_ci struct power_supply_config psy_cfg = {}; 72562306a36Sopenharmony_ci struct rn5t618_power_info *info; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 72862306a36Sopenharmony_ci if (!info) 72962306a36Sopenharmony_ci return -ENOMEM; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci info->pdev = pdev; 73262306a36Sopenharmony_ci info->rn5t618 = dev_get_drvdata(pdev->dev.parent); 73362306a36Sopenharmony_ci info->irq = -1; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci platform_set_drvdata(pdev, info); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci info->channel_vusb = devm_iio_channel_get(&pdev->dev, "vusb"); 73862306a36Sopenharmony_ci if (IS_ERR(info->channel_vusb)) { 73962306a36Sopenharmony_ci if (PTR_ERR(info->channel_vusb) == -ENODEV) 74062306a36Sopenharmony_ci return -EPROBE_DEFER; 74162306a36Sopenharmony_ci return PTR_ERR(info->channel_vusb); 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci info->channel_vadp = devm_iio_channel_get(&pdev->dev, "vadp"); 74562306a36Sopenharmony_ci if (IS_ERR(info->channel_vadp)) { 74662306a36Sopenharmony_ci if (PTR_ERR(info->channel_vadp) == -ENODEV) 74762306a36Sopenharmony_ci return -EPROBE_DEFER; 74862306a36Sopenharmony_ci return PTR_ERR(info->channel_vadp); 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci ret = regmap_read(info->rn5t618->regmap, RN5T618_CONTROL, &v); 75262306a36Sopenharmony_ci if (ret) 75362306a36Sopenharmony_ci return ret; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (!(v & FG_ENABLE)) { 75662306a36Sopenharmony_ci /* E.g. the vendor kernels of various Kobo and Tolino Ebook 75762306a36Sopenharmony_ci * readers disable the fuel gauge on shutdown. If a kernel 75862306a36Sopenharmony_ci * without fuel gauge support is booted after that, the fuel 75962306a36Sopenharmony_ci * gauge will get decalibrated. 76062306a36Sopenharmony_ci */ 76162306a36Sopenharmony_ci dev_info(&pdev->dev, "Fuel gauge not enabled, enabling now\n"); 76262306a36Sopenharmony_ci dev_info(&pdev->dev, "Expect imprecise results\n"); 76362306a36Sopenharmony_ci regmap_update_bits(info->rn5t618->regmap, RN5T618_CONTROL, 76462306a36Sopenharmony_ci FG_ENABLE, FG_ENABLE); 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci psy_cfg.drv_data = info; 76862306a36Sopenharmony_ci info->battery = devm_power_supply_register(&pdev->dev, 76962306a36Sopenharmony_ci &rn5t618_battery_desc, 77062306a36Sopenharmony_ci &psy_cfg); 77162306a36Sopenharmony_ci if (IS_ERR(info->battery)) { 77262306a36Sopenharmony_ci ret = PTR_ERR(info->battery); 77362306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register battery: %d\n", ret); 77462306a36Sopenharmony_ci return ret; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci info->adp = devm_power_supply_register(&pdev->dev, 77862306a36Sopenharmony_ci &rn5t618_adp_desc, 77962306a36Sopenharmony_ci &psy_cfg); 78062306a36Sopenharmony_ci if (IS_ERR(info->adp)) { 78162306a36Sopenharmony_ci ret = PTR_ERR(info->adp); 78262306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register adp: %d\n", ret); 78362306a36Sopenharmony_ci return ret; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci info->usb = devm_power_supply_register(&pdev->dev, 78762306a36Sopenharmony_ci &rn5t618_usb_desc, 78862306a36Sopenharmony_ci &psy_cfg); 78962306a36Sopenharmony_ci if (IS_ERR(info->usb)) { 79062306a36Sopenharmony_ci ret = PTR_ERR(info->usb); 79162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register usb: %d\n", ret); 79262306a36Sopenharmony_ci return ret; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (info->rn5t618->irq_data) 79662306a36Sopenharmony_ci info->irq = regmap_irq_get_virq(info->rn5t618->irq_data, 79762306a36Sopenharmony_ci RN5T618_IRQ_CHG); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (info->irq < 0) 80062306a36Sopenharmony_ci info->irq = -1; 80162306a36Sopenharmony_ci else { 80262306a36Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, 80362306a36Sopenharmony_ci rn5t618_charger_irq, 80462306a36Sopenharmony_ci IRQF_ONESHOT, 80562306a36Sopenharmony_ci "rn5t618_power", 80662306a36Sopenharmony_ci &pdev->dev); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (ret < 0) { 80962306a36Sopenharmony_ci dev_err(&pdev->dev, "request IRQ:%d fail\n", 81062306a36Sopenharmony_ci info->irq); 81162306a36Sopenharmony_ci info->irq = -1; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci return 0; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic struct platform_driver rn5t618_power_driver = { 81962306a36Sopenharmony_ci .driver = { 82062306a36Sopenharmony_ci .name = "rn5t618-power", 82162306a36Sopenharmony_ci }, 82262306a36Sopenharmony_ci .probe = rn5t618_power_probe, 82362306a36Sopenharmony_ci}; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cimodule_platform_driver(rn5t618_power_driver); 82662306a36Sopenharmony_ciMODULE_ALIAS("platform:rn5t618-power"); 82762306a36Sopenharmony_ciMODULE_DESCRIPTION("Power supply driver for RICOH RN5T618"); 82862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 829