Files
android/sound/soc/codecs/aw87xxx/aw87xxx_monitor.c
threeeye bc1d038eac REVVL 6 Pro kernel bring-up: full working tree snapshot (2026-09-12)
Squashed backup commit (no shallow-clone history issues) of
xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2 branch, upstream
commit 9eece662e) plus all fixes applied to get everpal_defconfig building
clean against a modern (GCC 15.2.0) toolchain -- see the previous commit
message on the lineage-23.2 branch (also in this repo history is not
available here since this is a squashed snapshot; full incremental history
lives in the local DL380 checkout and the upstream GitHub remote).

Upstream: https://github.com/xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2)
2026-09-12 13:36:46 +00:00

489 lines
14 KiB
C

/*
* aw87xxx_monitor.c aw87xxx pa module
*
* Copyright (c) 2020 AWINIC Technology CO., LTD
*
* Author: Alex <zhangpengbiao@awinic.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/power_supply.h>
#include <linux/of.h>
#include <linux/power_supply.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/firmware.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/gameport.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include "aw87xxx.h"
#include "aw87xxx_monitor.h"
#include "awinic_dsp.h"
/****************************************************************************
* aw87xxx get battery capacity
*****************************************************************************/
int aw87xxx_get_battery_capacity(struct aw87xxx *aw87xxx,
uint32_t *vbat_capacity)
{
char name[] = "battery";
int ret;
union power_supply_propval prop = { 0 };
struct power_supply *psy = NULL;
aw_dev_info(aw87xxx->dev, "%s:enter\n", __func__);
psy = power_supply_get_by_name(name);
if (psy) {
ret = power_supply_get_property(psy,
POWER_SUPPLY_PROP_CAPACITY,
&prop);
if (ret < 0) {
aw_dev_err(aw87xxx->dev,
"%s: get vbat capacity failed\n", __func__);
return -EINVAL;
}
*vbat_capacity = prop.intval;
aw_dev_info(aw87xxx->dev, "The percentage is %d\n",
*vbat_capacity);
} else {
aw_dev_err(aw87xxx->dev, "no struct power supply name :%s",
name);
return -EINVAL;
}
return 0;
}
/*****************************************************
* aw87xxx monitor control
*****************************************************/
void aw87xxx_monitor_stop(struct aw87xxx_monitor *monitor)
{
struct aw87xxx *aw87xxx = container_of(monitor,
struct aw87xxx, monitor);
aw_dev_info(aw87xxx->dev, "%s enter, dev_i2c%d@0x%02X\n", __func__,
aw87xxx->i2c_seq, aw87xxx->i2c_addr);
if (delayed_work_pending(&aw87xxx->monitor.work))
cancel_delayed_work(&aw87xxx->monitor.work);
}
void aw87xxx_monitor_start(struct aw87xxx_monitor *monitor)
{
struct aw87xxx *aw87xxx = container_of(monitor,
struct aw87xxx, monitor);
if (aw87xxx->current_mode == AW87XXX_RCV_MODE) {
aw87xxx_monitor_stop(&aw87xxx->monitor);
} else if (aw87xxx->monitor.monitor_flag &&
aw87xxx->open_dsp_en &&
(aw87xxx->monitor.cfg_update_flag == AW87XXX_CFG_OK)) {
aw87xxx->monitor.pre_vmax = AW_VMAX_INIT_VAL;
aw87xxx->monitor.first_entry = AW_FIRST_ENTRY;
schedule_delayed_work(&aw87xxx->monitor.work,
msecs_to_jiffies(WAIT_DSP_OPEN_TIME));
}
}
static int aw87xxx_vbat_monitor_update_vmax(struct aw87xxx *aw87xxx,
int vbat_vol)
{
int ret = -1;
int i = 0;
uint32_t vmax_flag = 0;
uint32_t vmax_set = 0;
struct aw87xxx_monitor *monitor = NULL;
monitor = &aw87xxx->monitor;
for (i = 0; i < monitor->vmax_cfg->vmax_cfg_num; i++) {
if (vbat_vol > monitor->vmax_cfg->vmax_cfg_total[i].min_thr) {
vmax_set = monitor->vmax_cfg->vmax_cfg_total[i].vmax;
vmax_flag = 1;
aw_dev_dbg(aw87xxx->dev,
"%s: read setting vmax=0x%x, step[%d]: min_thr=%d\n",
__func__, vmax_set, i,
monitor->vmax_cfg->vmax_cfg_total[i].
min_thr);
break;
}
}
pr_info("%s:vmax_flag=%d\n", __func__, vmax_flag);
if (vmax_flag) {
if (monitor->pre_vmax != vmax_set) {
ret = aw_set_vmax_to_dsp(vmax_set, aw87xxx->pa_channel);
if (ret) {
aw_dev_err(aw87xxx->dev,
"%s: set dsp msg fail, ret=%d\n",
__func__, ret);
return ret;
} else {
aw_dev_info(aw87xxx->dev,
"%s: set dsp vmax=0x%x sucess\n",
__func__, vmax_set);
monitor->pre_vmax = vmax_set;
}
} else {
aw_dev_info(aw87xxx->dev, "%s:vmax=0x%x no change\n",
__func__, vmax_set);
}
}
return 0;
}
static void aw87xxx_monitor_work_func(struct work_struct *work)
{
int ret;
uint32_t vbat_capacity;
uint32_t ave_capacity;
struct aw87xxx *aw87xxx = container_of(work,
struct aw87xxx, monitor.work.work);
aw_dev_info(aw87xxx->dev, "%s: enter\n", __func__);
ret = aw87xxx_get_battery_capacity(aw87xxx, &vbat_capacity);
if (ret < 0)
return;
if (aw87xxx->monitor.timer_cnt < aw87xxx->monitor.timer_cnt_max) {
aw87xxx->monitor.timer_cnt++;
aw87xxx->monitor.vbat_sum += vbat_capacity;
}
if ((aw87xxx->monitor.timer_cnt == aw87xxx->monitor.timer_cnt_max) ||
(aw87xxx->monitor.first_entry == AW_FIRST_ENTRY)) {
if (aw87xxx->monitor.first_entry == AW_FIRST_ENTRY)
aw87xxx->monitor.first_entry = AW_NOT_FIRST_ENTRY;
ave_capacity = aw87xxx->monitor.vbat_sum /
aw87xxx->monitor.timer_cnt;
if (aw87xxx->monitor.custom_capacity)
ave_capacity = aw87xxx->monitor.custom_capacity;
aw_dev_info(aw87xxx->dev, "%s: get average capacity = %d\n",
__func__, ave_capacity);
aw87xxx_vbat_monitor_update_vmax(aw87xxx, ave_capacity);
aw87xxx->monitor.timer_cnt = 0;
aw87xxx->monitor.vbat_sum = 0;
}
schedule_delayed_work(&aw87xxx->monitor.work,
msecs_to_jiffies(aw87xxx->monitor.timer_val));
}
static int aw87xxx_nodsp_get_vmax(struct aw87xxx *aw87xxx,
uint32_t *vmax_get)
{
int ret = -1, i = 0;
uint32_t vbat_capacity = 0;
struct vmax_config *vmax_cfg = aw87xxx->monitor.vmax_cfg;
ret = aw87xxx_get_battery_capacity(aw87xxx, &vbat_capacity);
if (ret < 0)
return ret;
aw_dev_info(aw87xxx->dev, "%s: get_battery_capacity is [%d]\n",
__func__, vbat_capacity);
for (i = 0; i < vmax_cfg->vmax_cfg_num; i++) {
if (vbat_capacity > vmax_cfg->vmax_cfg_total[i].min_thr) {
*vmax_get = vmax_cfg->vmax_cfg_total[i].vmax;
aw_dev_info(aw87xxx->dev, "%s: read setting vmax=0x%x, step[%d]: min_thr=%d\n",
__func__, *vmax_get, i,
vmax_cfg->vmax_cfg_total[i].min_thr);
return ret;
}
}
return -EPERM;
}
/**********************************************************
* aw873xx monitor attribute
***********************************************************/
static ssize_t aw87xxx_get_vbat(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t len = 0;
struct aw87xxx *aw87xxx = dev_get_drvdata(dev);
len += snprintf(buf + len, PAGE_SIZE - len,
"vbat capacity=%d\n", aw87xxx->monitor.custom_capacity);
return len;
}
static ssize_t aw87xxx_set_vbat(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t len)
{
int ret = -1;
uint32_t capacity;
struct aw87xxx *aw87xxx = dev_get_drvdata(dev);
if (len == 0)
return 0;
ret = kstrtouint(buf, 0, &capacity);
if (ret < 0)
return ret;
aw_dev_info(aw87xxx->dev, "%s: set capacity = %d\n",
__func__, capacity);
if (capacity >= AW87XXX_VBAT_CAPACITY_MIN &&
capacity <= AW87XXX_VBAT_CAPACITY_MAX)
aw87xxx->monitor.custom_capacity = capacity;
return len;
}
static ssize_t aw87xxx_get_vmax(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t len = 0;
uint32_t vmax_get = 0;
int ret = -1;
struct aw87xxx *aw87xxx = dev_get_drvdata(dev);
aw_dev_info(aw87xxx->dev, "%s: enter", __func__);
if (aw87xxx->open_dsp_en) {
ret = aw_get_vmax_from_dsp(&vmax_get, aw87xxx->pa_channel);
if (ret < 0) {
aw_dev_err(aw87xxx->dev, "%s: get dsp vmax fail, ret = %d\n",
__func__, ret);
} else {
len += snprintf(buf + len, PAGE_SIZE - len,
"get_vmax=0x%x\n", vmax_get);
aw_dev_info(aw87xxx->dev, "%s: get vmax=[%08x] from dsp\n",
__func__, vmax_get);
}
} else {
if (aw87xxx->monitor.cfg_update_flag != AW87XXX_CFG_OK) {
len += snprintf(buf + len, PAGE_SIZE - len,
"%x\n", 0);
aw_dev_err(aw87xxx->dev, "%s: vmax not ready,return 0 to hal\n",
__func__);
return len;
}
ret = aw87xxx_nodsp_get_vmax(aw87xxx, &vmax_get);
if (ret < 0) {
aw_dev_err(aw87xxx->dev, "%s: get nodsp vmax fail, ret = %d\n",
__func__, ret);
} else {
len += snprintf(buf + len, PAGE_SIZE - len,
"%x\n", vmax_get);
aw_dev_info(aw87xxx->dev, "%s: set vmax=[%08x] to hal\n",
__func__, vmax_get);
}
}
return len;
}
static ssize_t aw87xxx_set_vmax(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t len)
{
uint32_t vmax_set = 0;
int ret = -1;
struct aw87xxx *aw87xxx = dev_get_drvdata(dev);
if (len == 0)
return 0;
ret = kstrtouint(buf, 0, &vmax_set);
if (ret < 0)
return ret;
aw_dev_info(aw87xxx->dev, "%s: vmax_set=%d\n", __func__, vmax_set);
if (aw87xxx->open_dsp_en) {
ret = aw_set_vmax_to_dsp(vmax_set, aw87xxx->pa_channel);
if (ret)
aw_dev_err(aw87xxx->dev, "%s: send dsp_msg error, ret = %d\n",
__func__, ret);
mdelay(2);
}
return len;
}
static ssize_t aw87xxx_get_monitor(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct aw87xxx *aw87xxx = dev_get_drvdata(dev);
ssize_t len = 0;
uint32_t local_enable;
local_enable = aw87xxx->monitor.monitor_flag;
len += snprintf(buf + len, PAGE_SIZE - len,
"aw87xxx monitor enable: %d\n", local_enable);
return len;
}
static ssize_t aw87xxx_set_monitor(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct aw87xxx *aw87xxx = dev_get_drvdata(dev);
uint32_t enable = 0;
int ret = -1;
if (count == 0)
return 0;
ret = kstrtouint(buf, 0, &enable);
if (ret < 0)
return ret;
aw_dev_info(aw87xxx->dev, "%s:monitor enable set =%d\n",
__func__, enable);
aw87xxx->monitor.monitor_flag = enable;
if (!aw87xxx->monitor.monitor_flag) {
aw87xxx_monitor_stop(&aw87xxx->monitor);
} else {
if (aw87xxx->current_mode != AW87XXX_RCV_MODE &&
aw87xxx->monitor.cfg_update_flag == AW87XXX_CFG_OK)
schedule_delayed_work(&aw87xxx->monitor.work,
msecs_to_jiffies(aw87xxx->monitor.timer_val));
}
return count;
}
static ssize_t aw87xxx_get_vmax_time(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct aw87xxx *aw87xxx = dev_get_drvdata(dev);
ssize_t len = 0;
len += snprintf(buf + len, PAGE_SIZE - len,
"aw87xxx_vmax_timer_val = %d\n",
aw87xxx->monitor.timer_val);
return len;
}
static ssize_t aw87xxx_set_vmax_time(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct aw87xxx *aw87xxx = dev_get_drvdata(dev);
unsigned int timer_val = 0;
int ret;
ret = kstrtouint(buf, 0, &timer_val);
if (ret < 0)
return ret;
pr_info("%s:timer_val =%d\n", __func__, timer_val);
aw87xxx->monitor.timer_val = timer_val;
return count;
}
static DEVICE_ATTR(vbat, S_IWUSR | S_IRUGO, aw87xxx_get_vbat, aw87xxx_set_vbat);
static DEVICE_ATTR(vmax, S_IWUSR | S_IRUGO, aw87xxx_get_vmax, aw87xxx_set_vmax);
static DEVICE_ATTR(monitor, S_IWUSR | S_IRUGO,
aw87xxx_get_monitor, aw87xxx_set_monitor);
static DEVICE_ATTR(vmax_time, S_IWUSR | S_IRUGO,
aw87xxx_get_vmax_time, aw87xxx_set_vmax_time);
static struct attribute *aw87xxx_monitor_attr[] = {
&dev_attr_vbat.attr,
&dev_attr_vmax.attr,
&dev_attr_monitor.attr,
&dev_attr_vmax_time.attr,
NULL
};
static struct attribute_group aw87xxx_monitor_attr_group = {
.attrs = aw87xxx_monitor_attr
};
/**********************************************************
* aw87xxx monitor init
***********************************************************/
void aw87xxx_monitor_init(struct aw87xxx_monitor *monitor)
{
int ret;
struct aw87xxx *aw87xxx = container_of(monitor,
struct aw87xxx, monitor);
aw_dev_info(aw87xxx->dev, "%s: enter\n", __func__);
INIT_DELAYED_WORK(&monitor->work, aw87xxx_monitor_work_func);
ret = sysfs_create_group(&aw87xxx->dev->kobj,
&aw87xxx_monitor_attr_group);
if (ret < 0) {
aw_dev_err(aw87xxx->dev,
"%s error creating monitor sysfs attr files\n",
__func__);
}
}
void aw87xxx_parse_monitor_dt(struct aw87xxx_monitor *monitor)
{
int ret;
struct aw87xxx *aw87xxx = container_of(monitor,
struct aw87xxx, monitor);
struct device_node *np = aw87xxx->dev->of_node;
ret = of_property_read_u32(np, "monitor-flag", &monitor->monitor_flag);
if (ret) {
monitor->monitor_flag = AW87XXX_MONITOR_DEFAULT_FLAG;
aw_dev_err(aw87xxx->dev,
"%s: monitor-flag get failed ,user default value!\n",
__func__);
} else {
aw_dev_info(aw87xxx->dev, "%s: monitor-flag = %d\n",
__func__, monitor->monitor_flag);
}
ret = of_property_read_u32(np, "monitor-timer-val",
&monitor->timer_val);
if (ret) {
monitor->timer_val = AW87XXX_MONITOR_DEFAULT_TIMER_VAL;
aw_dev_err(aw87xxx->dev,
"%s: monitor-timer-val get failed,user default value!\n",
__func__);
} else {
aw_dev_info(aw87xxx->dev, "%s: monitor-timer-val = %d\n",
__func__, monitor->timer_val);
}
ret = of_property_read_u32(np, "monitor-timer-count-max",
&monitor->timer_cnt_max);
if (ret) {
monitor->timer_cnt_max = AW87XXX_MONITOR_DEFAULT_TIMER_COUNT;
aw_dev_err(aw87xxx->dev,
"%s: monitor-timer-count-max get failed,user default config!\n",
__func__);
} else {
aw_dev_info(aw87xxx->dev, "%s: monitor-timer-count-max = %d\n",
__func__, monitor->timer_cnt_max);
}
}