Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save macromorgan/95099bf2d43b395ad68301e30c83aac6 to your computer and use it in GitHub Desktop.

Select an option

Save macromorgan/95099bf2d43b395ad68301e30c83aac6 to your computer and use it in GitHub Desktop.
Updated macc24's battery driver
From 786be1506dbf839f9d93b2613c26221a067f202c Mon Sep 17 00:00:00 2001
From: Chris Morgan <macromorgan@hotmail.com>
Date: Tue, 4 May 2021 21:45:31 -0500
Subject: [PATCH] Updated macc24's battery driver
---
.../boot/dts/rockchip/rk3326-odroid-go2.dts | 37 +++
drivers/mfd/rk808.c | 12 +-
drivers/power/supply/Kconfig | 7 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/rk817_battery.c | 266 ++++++++++++++++++
include/linux/mfd/rk808.h | 34 +++
6 files changed, 356 insertions(+), 1 deletion(-)
create mode 100644 drivers/power/supply/rk817_battery.c
diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts
index e8c2b5a817a7..335fbfed954b 100644
--- a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts
@@ -52,6 +52,21 @@ backlight: backlight {
pwms = <&pwm1 0 25000 0>;
};
+ battery_cell: battery-cell {
+ compatible = "simple-battery";
+ energy-full-design-microamp-hours = <3000000>;
+ voltage-min-design-microvolt = <3500000>;
+ voltage-max-design-microvolt = <4100000>;
+
+ ocv-capacity-celcius = <20>;
+ ocv-capacity-table-0 = <3500 0>, <3625 5>, <3685 10>, <3697 15>,
+ <3718 20>, <3735 25>, <3748 30>, <3760 35>,
+ <3774 40>, <3788 45>, <3802 50>, <3816 55>,
+ <3834 60>, <3853 65>, <3877 70>, <3908 75>,
+ <3946 80>, <3975 85>, <4018 90>, <4071 95>,
+ <4106 100>;
+ };
+
gpio-keys {
compatible = "gpio-keys";
pinctrl-names = "default";
@@ -464,6 +494,13 @@ regulator-state-mem {
rk817_codec: codec {
rockchip,mic-in-differential;
};
+
+ rk817_battery: battery {
+ compatible = "rk817,battery";
+ monitored-battery = <&battery_cell>;
+ bat_res = <180>;
+ sample_res = <10>;
+ };
};
};
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index 9231209184e0..13f160a03554 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -66,6 +66,10 @@ static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
case RK817_SECONDS_REG ... RK817_WEEKS_REG:
case RK817_RTC_STATUS_REG:
case RK817_CODEC_DTOP_LPT_SRST:
+ case RK817_GAS_GAUGE_ADC_CONFIG0 ... RK817_GAS_GAUGE_CUR_ADC_K0:
+ case RK817_PMIC_CHRG_STS:
+ case RK817_PMIC_CHRG_OUT:
+ case RK817_PMIC_CHRG_IN:
case RK817_INT_STS_REG0:
case RK817_INT_STS_REG1:
case RK817_INT_STS_REG2:
@@ -73,7 +77,7 @@ static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
return true;
}
- return true;
+ return false;
}
static const struct regmap_config rk818_regmap_config = {
@@ -169,6 +173,12 @@ static const struct mfd_cell rk817s[] = {
.name = "rk817-codec",
},
#endif
+#ifdef CONFIG_BATTERY_RK817
+ {
+ .name = "rk817-battery",
+ .of_compatible = "rk817,battery",
+ },
+#endif
};
static const struct mfd_cell rk818s[] = {
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index e696364126f1..a1289746ebc4 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -718,6 +718,13 @@ config BATTERY_RT5033
The fuelgauge calculates and determines the battery state of charge
according to battery open circuit voltage.
+config BATTERY_RK817
+ bool "RK817 Battery Driver"
+ depends on MFD_RK808
+ help
+ This adds support for the battery for the Rockchip RK817 PMIC.
+ The battery is an optional device for the RK817 PMIC.
+
config CHARGER_RT9455
tristate "Richtek RT9455 battery charger driver"
depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index a7309a3d1a47..f23b1554fdbf 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
obj-$(CONFIG_BATTERY_MAX1721X) += max1721x_battery.o
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
+obj-$(CONFIG_BATTERY_RK817) += rk817_battery.o
obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o
obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o
obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
diff --git a/drivers/power/supply/rk817_battery.c b/drivers/power/supply/rk817_battery.c
new file mode 100644
index 000000000000..7212b785b3ff
--- /dev/null
+++ b/drivers/power/supply/rk817_battery.c
@@ -0,0 +1,266 @@
+#include <linux/delay.h>
+#include <linux/extcon.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/rk808.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/power_supply.h>
+
+enum charge_status {
+ CHRG_OFF,
+ DEAD_CHRG,
+ TRICKLE_CHRG,
+ CC_OR_CV_CHRG,
+ CHARGE_FINISH,
+ USB_OVER_VOL,
+ BAT_TMP_ERR,
+ BAT_TIM_ERR,
+};
+
+struct rk817_bat {
+ struct platform_device *pdev;
+ struct device *dev;
+ struct i2c_client *client;
+ struct rk808 *rk808;
+
+ struct power_supply *bat_ps;
+ struct power_supply_battery_info info;
+
+ /* FIXME: do i move it into other struct? */
+ uint32_t voltage_k;
+ uint32_t voltage_b;
+ int res_div;
+ int sample_res;
+};
+
+static int rk817_get_reg_hl(struct rk817_bat *battery, int regH, int regL)
+{
+ int tmp, ret;
+ uint32_t out;
+ struct rk808 *rk808 = battery->rk808;
+
+ ret = regmap_read(rk808->regmap, regL, &tmp);
+ if (ret)
+ return ret;
+ out |= tmp;
+
+ ret = regmap_read(rk808->regmap, regH, &tmp);
+ if (ret)
+ return ret;
+ out |= tmp << 8;
+
+ return out;
+}
+
+static void rk817_write_reg_hl(struct rk817_bat *battery, int regH, int regL, int val)
+{
+ uint8_t tmp;
+ struct rk808 *rk808 = battery->rk808;
+
+ tmp = val & 0xff;
+ regmap_write(rk808->regmap, regL, tmp);
+ tmp = (val >> 8) & 0xff;
+ regmap_write(rk808->regmap, regH, tmp);
+}
+
+static void rk817_bat_calib_vol(struct rk817_bat *battery)
+{
+ uint32_t vcalib0 = 0;
+ uint32_t vcalib1 = 0;
+
+ /* calibrate voltage */
+ vcalib0 = rk817_get_reg_hl(battery, RK817_GAS_GAUGE_VCALIB0_H, RK817_GAS_GAUGE_VCALIB0_L);
+ vcalib1 = rk817_get_reg_hl(battery, RK817_GAS_GAUGE_VCALIB1_H, RK817_GAS_GAUGE_VCALIB1_L);
+
+ /* values were taken from BSP kernel */
+ battery->voltage_k = (4025 - 2300) * 1000 / ((vcalib1 - vcalib0) ? (vcalib1 - vcalib0) : 1);
+ battery->voltage_b = 4025 - (battery->voltage_k * vcalib1) / 1000;
+
+}
+
+static void rk817_bat_calib_cur(struct rk817_bat *battery)
+{
+ int ioffset = 0;
+ /* calibrate current */
+ ioffset = rk817_get_reg_hl(battery, RK817_GAS_GAUGE_IOFFSET_H, RK817_GAS_GAUGE_IOFFSET_H);
+ rk817_write_reg_hl(battery, RK817_GAS_GAUGE_CAL_OFFSET_H, RK817_GAS_GAUGE_CAL_OFFSET_L, ioffset);
+}
+
+static int rk817_bat_get_prop(struct power_supply *ps,
+ enum power_supply_property prop,
+ union power_supply_propval *val)
+{
+ struct rk817_bat *battery = power_supply_get_drvdata(ps);
+ uint32_t tmp = 0;
+ int ret = 0;
+ int reg = 0;
+ struct rk808 *rk808 = battery->rk808;
+
+ /* recalibrate voltage and current readings if we need to */
+ /* BSP does both on CUR_CALIB_UPD, ignoring VOL_CALIB_UPD */
+ regmap_read(rk808->regmap, RK817_GAS_GAUGE_ADC_CONFIG1, &reg);
+ tmp = (reg >> 7) & RK817_CUR_CALIB_UPD;
+ if (tmp == 0)
+ {
+ rk817_bat_calib_vol(battery);
+ rk817_bat_calib_cur(battery);
+ regmap_update_bits(rk808->regmap, RK817_GAS_GAUGE_ADC_CONFIG1, RK817_CUR_CALIB_UPD, 1);
+ }
+
+ switch (prop) {
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = regmap_read(rk808->regmap, RK817_PMIC_CHRG_STS, &reg);
+ if (ret)
+ return ret;
+ tmp = (reg >> 4) & RK817_CHG_STS;
+ switch(tmp) {
+ case CHRG_OFF:
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ case DEAD_CHRG:
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case TRICKLE_CHRG:
+ case CC_OR_CV_CHRG:
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case CHARGE_FINISH:
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ break;
+ default:
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ printk("Error getting battery value");
+ return -EINVAL;
+
+ }
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ ret = regmap_read(rk808->regmap, RK817_PMIC_CHRG_STS, &reg);
+ if (ret)
+ return ret;
+ tmp = (reg >> 4) & RK817_CHG_STS;
+ switch(tmp) {
+ case CHRG_OFF:
+ case DEAD_CHRG:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ case TRICKLE_CHRG:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ case CC_OR_CV_CHRG:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ default:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ break;
+ }
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ val->intval = battery->info.voltage_min_design_uv;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ tmp = rk817_get_reg_hl(battery, RK817_GAS_GAUGE_BAT_VOL_H, RK817_GAS_GAUGE_BAT_VOL_L);
+ val->intval = 1000 * ((battery->voltage_k * tmp) / (1000 + battery->voltage_b));
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ val->intval = battery->info.voltage_max_design_uv;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+
+static enum power_supply_property rk817_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+};
+
+static const struct power_supply_desc rk817_desc = {
+ .name = "rk817-battery",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = rk817_bat_props,
+ .num_properties = ARRAY_SIZE(rk817_bat_props),
+ .get_property = rk817_bat_get_prop,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rk817_bat_of_match[] = {
+ { .compatible = "rk817,battery", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, rk817_bat_of_match);
+#endif
+
+static int rk817_bat_probe(struct platform_device *pdev)
+{
+ struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
+ struct rk817_bat *battery;
+ struct device *dev = &pdev->dev;
+ struct power_supply_config pscfg = {};
+ int ret;
+
+ if (!of_device_is_available(pdev->dev.of_node))
+ return -ENODEV;
+
+ battery = devm_kzalloc(&pdev->dev, sizeof(battery), GFP_KERNEL);
+ if (!battery)
+ return -ENOMEM;
+
+ battery->rk808 = rk808;
+
+ battery->dev = &pdev->dev;
+ platform_set_drvdata(pdev, battery);
+
+ rk817_bat_calib_vol(battery);
+
+ pscfg.drv_data = battery;
+ pscfg.of_node = pdev->dev.of_node;
+
+ /* some boards may use different values for sample resistor */
+ ret = of_property_read_u32(pdev->dev.of_node, "sample_res", &battery->sample_res);
+ if (ret < 0)
+ dev_err(dev, "Error reading sample_res");
+ battery->res_div = (battery->sample_res == 20) ? 1 : 2;
+
+ battery->bat_ps = devm_power_supply_register(&pdev->dev, &rk817_desc, &pscfg);
+
+ ret = power_supply_get_battery_info(battery->bat_ps, &battery->info);
+ if (ret) {
+ dev_err(dev, "Unable to get battery info: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static struct platform_driver rk817_bat_driver = {
+ .probe = rk817_bat_probe,
+ .driver = {
+ .name = "rk817-battery",
+ .of_match_table = rk817_bat_of_match,
+ },
+};
+module_platform_driver(rk817_bat_driver);
+
+MODULE_DESCRIPTION("Battery power supply driver for RK817 PMIC");
+MODULE_AUTHOR("Maciej Matuszczyk <maccraft123mc@gmail.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h
index a96e6d43ca06..1efa37017c04 100644
--- a/include/linux/mfd/rk808.h
+++ b/include/linux/mfd/rk808.h
@@ -495,6 +495,34 @@ enum rk809_reg_id {
#define RK817_CODEC_DI2S_TXCR2 0x4e
#define RK817_CODEC_DI2S_TXCR3_TXCMD 0x4f
+/* RK817 Battery Registers */
+#define RK817_GAS_GAUGE_ADC_CONFIG0 0x50
+#define RK817_GAS_GAUGE_ADC_CONFIG1 0x55
+
+#define RK817_CUR_CALIB_UPD (0x1 << 7)
+#define RK817_VOL_CALIB_UPD (0x1 << 6)
+
+#define RK817_GAS_GAUGE_OCV_THRE_VOL 0x62
+#define RK817_GAS_GAUGE_OCV_VOL_H 0x63
+#define RK817_GAS_GAUGE_OCV_VOL_L 0x64
+#define RK817_GAS_GAUGE_Q_PRES_H3 0x74
+#define RK817_GAS_GAUGE_Q_PRES_H2 0x75
+#define RK817_GAS_GAUGE_Q_PRES_L1 0x76
+#define RK817_GAS_GAUGE_Q_PRES_L0 0x77
+#define RK817_GAS_GAUGE_BAT_VOL_H 0x78
+#define RK817_GAS_GAUGE_BAT_VOL_L 0x79
+#define RK817_GAS_GAUGE_SYS_VOL_H 0x80
+#define RK817_GAS_GAUGE_SYS_VOL_L 0x81
+#define RK817_GAS_GAUGE_CAL_OFFSET_H 0x91
+#define RK817_GAS_GAUGE_CAL_OFFSET_L 0x92
+#define RK817_GAS_GAUGE_VCALIB0_H 0x93
+#define RK817_GAS_GAUGE_VCALIB0_L 0x94
+#define RK817_GAS_GAUGE_VCALIB1_H 0x95
+#define RK817_GAS_GAUGE_VCALIB1_L 0x96
+#define RK817_GAS_GAUGE_IOFFSET_H 0x97
+#define RK817_GAS_GAUGE_IOFFSET_L 0x98
+#define RK817_GAS_GAUGE_CUR_ADC_K0 0xb0
+
/* RK817_CODEC_DI2S_CKM */
#define RK817_I2S_MODE_MASK (0x1 << 0)
#define RK817_I2S_MODE_MST (0x1 << 0)
@@ -543,6 +571,12 @@ enum rk809_reg_id {
#define RK817_LDO_ON_VSEL_REG(idx) (0xcc + (idx) * 2)
#define RK817_BOOST_OTG_CFG (0xde)
+#define RK817_PMIC_CHRG_OUT 0xe4
+#define RK817_PMIC_CHRG_IN 0xe5
+#define RK817_PMIC_CHRG_STS 0xeb
+
+#define RK817_CHG_STS (0x07 << 4)
+
#define RK817_ID_MSB 0xed
#define RK817_ID_LSB 0xee
--
2.25.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment