drivers/battery/wireless: add cps4038

This commit is contained in:
j7b3y 2025-01-15 17:08:32 +09:00
parent f32a1238aa
commit d14bfe8797
11 changed files with 10690 additions and 2 deletions

View File

@ -8,6 +8,16 @@ config WIRELESS_CHARGING
Wireless charging models should enable this charging option.
it include various scenario for wireless charging models only.
config WIRELESS_CHARGER_CPS4038
tristate "MFC IC CPS4038 charger support"
select WIRELESS_CHARGING
depends on BATTERY_SAMSUNG && I2C
help
Say Y here, to enable
support for the CPS4038 MFC IC
CPS4038 MFC include wireless charger driver.
It is for CPS(Conveninet Power Systems).
config WIRELESS_CHARGER_NU1668
tristate "MFC IC NU1668 charger support"
select WIRELESS_CHARGING

View File

@ -1,5 +1,7 @@
obj-$(CONFIG_WIRELESS_CHARGER_NU1668) += nu1668-charger.o
obj-$(CONFIG_WIRELESS_CHARGER_CPS4038) += cps4038-charger.o
cps4038-charger-$(CONFIG_WIRELESS_CHARGER_CPS4038) += cps4038_fod.o cps4038_cmfet.o cps4038_charger.o
obj-$(CONFIG_WIRELESS_CHARGER_NU1668) += nu1668-charger.o
nu1668-charger-$(CONFIG_WIRELESS_CHARGER_NU1668) += nu1668_fod.o nu1668_cmfet.o nu1668_charger.o
ccflags-y := -Wformat
ccflags-y := -Wformat

View File

@ -0,0 +1,7 @@
ko_list = [
{
"ko_names" : [
"drivers/battery/wireless/cps4038-charger.ko"
]
}
]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,235 @@
#include <dt-bindings/battery/sec-battery.h>
&smd {
sb_tx: sb-tx {
aov {
high_freq = <144>;
};
};
};
&tlmm {
cps_irq_default: cps_irq_default {
GPIO_CONFIG_PUD_DRV(AP,tlmm,84, FUNC_INPUT_WAKEUP, PULL_NONE, DRV_LV1);
};
};
&pm8550_gpios {
cps_det_default: cps_det_default {
GPIO_CONFIG_PUD(PM,pm8550_gpios,9, FUNC_INPUT_WAKEUP, PULL_NONE);
};
};
&tlmm {
cps_en_default: cps_en_default {
GPIO_CONFIG_PUD(AP,tlmm,82, FUNC_OUTPUT_LOW, PULL_NONE);
};
};
#if 1
&pm8550ve_gpios {
cps_pdrc_default: cps_pdrc_default {
GPIO_CONFIG_PUD(PM,pm8550ve_gpios,6, FUNC_INPUT_WAKEUP, PULL_NONE);
};
};
#endif
#if 1
&tlmm {
cps_ping_nen_default: cps_ping_nen_default {
GPIO_CONFIG_PUD(AP,tlmm,180, FUNC_OUTPUT_HIGH, PULL_NONE);
};
};
#endif
#if 1
&tlmm {
cps_pdet_b_default: cps_pdet_b_default {
GPIO_CONFIG_PUD(AP,tlmm,55, FUNC_INPUT_WAKEUP, PULL_NONE);
};
};
#endif
#if 1
&pm8550vs_g_gpios {
cps_mag_det_default: cps_mag_det_default {
GPIO_CONFIG_PUD(PM,pm8550vs_g_gpios,5, FUNC_OUTPUT_HIGH, PULL_NONE);
};
};
#endif
&qupv3_hub_i2c7 {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
clock-frequency = <100000>;
cps4038_charger: cps4038-charger@38 {
compatible = "cps,cps4038-charger";
reg = <0x38>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&cps_irq_default &cps_det_default &cps_en_default &cps_pdrc_default
#if 1
&cps_ping_nen_default
#endif
#if 1
&cps_pdet_b_default
#endif
#if 1
&cps_mag_det_default
#endif
>;
battery,wpc_int = <SEC_GPIO_REF(AP,tlmm,84) 1>; /* MFC_AP_INT */
battery,wpc_det = <SEC_GPIO_REF(PM,pm8550_gpios,9) 0>; /* WPC_DET */
#if 0
battery,mst_pwr_en = <SEC_GPIO_REF(${cps_pwr_en_gpio}) 0>; /* MST_PWR_EN */
#endif
#if 1
battery,wpc_ping_nen = <SEC_GPIO_REF(AP,tlmm,180) 1>; /* PING_NEN */
#endif
#if 1
battery,wpc_pdet_b = <SEC_GPIO_REF(AP,tlmm,55) 1>; /* PDET_B */
#endif
battery,wpc_en = <SEC_GPIO_REF(AP,tlmm,82) 0>; /* WPC_EN */
#if 1
battery,wpc_pdrc = <SEC_GPIO_REF(PM,pm8550ve_gpios,6) 1>; /* VRECT_INT */
#endif
#if 1
battery,wpc_mag_det = <SEC_GPIO_REF(PM,pm8550vs_g_gpios,5) 0>; /* MAG_DET */
#endif
battery,charger_name = "max77775-charger";
battery,fuelgauge_name = "max77775-fuelgauge";
battery,wireless_charger_name = "cps4038-charger";
battery,wc_cover_rpp = <0x44>;
battery,phone_fod_threshold = <0x3b>;
battery,wireless20_vout_list = <WIRELESS_VOUT_9V /* 0xA0 */
WIRELESS_VOUT_12V /* 0xA1 */
WIRELESS_VOUT_12V /* 0xA2 */
WIRELESS_VOUT_12V /* 0xA3 */
WIRELESS_VOUT_12V /* 0xA4 */
WIRELESS_VOUT_12V>; /* 0xA5 */
battery,wireless20_vrect_list = <MFC_AFC_CONF_12V_TX
MFC_AFC_CONF_12_5V_TX
MFC_AFC_CONF_12_5V_TX
MFC_AFC_CONF_12_5V_TX
MFC_AFC_CONF_12_5V_TX
MFC_AFC_CONF_12_5V_TX>;
battery,wireless20_max_power_list = <SEC_WIRELESS_RX_POWER_12W
SEC_WIRELESS_RX_POWER_15W
SEC_WIRELESS_RX_POWER_15W
SEC_WIRELESS_RX_POWER_15W
SEC_WIRELESS_RX_POWER_15W
SEC_WIRELESS_RX_POWER_15W>;
battery,buds_fod_ta_thresh = <0x0898>; /* 2200mW */
battery,wpc_vout_ctrl_full = <WIRELESS_VOUT_5V_STEP>;
battery,mis_align_guide;
battery,mis_align_target_vout = <5000>;
battery,mpp_epp_vout = <WIRELESS_VOUT_12V>;
fod_list {
count = <1>;
pad_0x00 { /* DEFAULT PAD */
bpp { /* DEFAULT OP MODE */
flag = <(SET_FOD_CC(ADD) | SET_FOD_CV(USE_CC) | SET_FOD_FULL(ADD))>;
cc = <0x4E 0x0F 0x4E 0x10 0x4E 0x0C 0x4E 0x0C 0x4E 0x0C 0x4E 0x0C 0x4E 0x0D 0x4E 0x0D 0x4E 0x0D 0x4E 0x0D>;
full = <0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F
0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F>;
};
ppde {
flag = <(SET_FOD_CC(USE_DEF_OP) | SET_FOD_CV(USE_DEF_OP) | SET_FOD_FULL(USE_DEF_OP))>;
};
epp {
flag = <(SET_FOD_CC(USE_DEF_OP) | SET_FOD_CV(USE_DEF_OP) | SET_FOD_FULL(USE_DEF_OP))>;
};
mpp {
flag = <(SET_FOD_CC(USE_DEF_OP) | SET_FOD_CV(USE_DEF_OP) | SET_FOD_FULL(USE_DEF_OP))>;
};
};
};
};
};
/* /home/dpi/qb5_8814/workspace/P4_1788/android/kernel_platform/kmodule/battery/stable/eureka/wireless/cps4038/cps4038_charger.e1q.dtsi */
#include <dt-bindings/battery/sec-battery.h>
&cps_pdrc_default {
power-source = <1>; /* need to set default MV gpio to LV */
};
&cps_det_default {
power-source = <1>; /* need to set default MV gpio to LV */
};
#if 1
&cps_mag_det_default {
power-source = <1>; /* need to set default MV gpio to LV */
};
#endif
&cps4038_charger {
battery,unknown_cmb_ctrl;
battery,default_clamp_volt;
battery,tx_max_op_freq = <1450>;
battery,tx_min_op_freq = <1120>;
battery,wireless20_iec_ploss_fod_enable = <0x1>;
battery,tx_fod_gain = <0x74>;
battery,buds_fod_thresh1 = <0x0DAC>;
battery,buds_fod_ta_thresh = <0x0DAC>;
battery,cep_timeout_xac = <900>;
fod_list {
epp_ref_qf = <0x24>;
epp_ref_rf = <0x69>;
count = <3>;
pad_0x00 { /* DEFAULT */
bpp { /* DEFAULT OP MODE */
flag = <(SET_FOD_CC(ADD) | SET_FOD_CV(ADD) | SET_FOD_FULL(ADD))>;
cc = <0x52 0x0E 0x52 0x0E 0x52 0x0A 0x52 0x0A 0x52 0x0A 0x52 0x0A 0x52 0x0B 0x52 0x0B 0x52 0x0B 0x52 0x0B>;
cv = <0x52 0x16 0x52 0x16 0x52 0x12 0x52 0x12 0x52 0x12 0x52 0x12 0x52 0x13 0x52 0x13 0x52 0x13 0x52 0x13>;
full = <0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F>;
};
epp {
flag = <(SET_FOD_CC(ADD) | SET_FOD_CV(ADD) | SET_FOD_FULL(ADD))>;
cc = <0x65 0x1B 0x65 0x1B 0x65 0x16 0x65 0x16 0x65 0x19 0x65 0x19 0x62 0x1D 0x62 0x1D 0x62 0x1D 0x0E 0x03>;
cv = <0x65 0x23 0x65 0x23 0x65 0x1E 0x65 0x1E 0x65 0x21 0x65 0x21 0x62 0x25 0x62 0x25 0x62 0x25 0x0E 0x03>;
full = <0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0x0E 0x03>;
};
ppde {
flag = <(SET_FOD_CC(ADD) | SET_FOD_CV(ADD) | SET_FOD_FULL(USE_DEF_OP))>;
cc = <0xA0 0x4F 0xA0 0x4F 0xA0 0x3B 0xA0 0x3D 0xA0 0x3E 0xA0 0x3E 0xA0 0x3E 0xA0 0x3B 0xA0 0x39 0xA0 0x39>;
cv = <0xA0 0x57 0xA0 0x57 0xA0 0x43 0xA0 0x45 0xA0 0x46 0xA0 0x46 0xA0 0x46 0xA0 0x43 0xA0 0x41 0xA0 0x41>;
};
};
pad_0xA3 { /* p2400 */
epp {
flag = <(SET_FOD_CC(ADD) | SET_FOD_CV(ADD) | SET_FOD_FULL(ADD))>;
cc = <0x65 0x41 0x65 0x41 0x65 0x3C 0x65 0x3C 0x65 0x3E 0x65 0x3E 0x62 0x43 0x62 0x43 0x62 0x43 0x0E 0x0A>;
cv = <0x65 0x49 0x65 0x49 0x65 0x44 0x65 0x44 0x65 0x46 0x65 0x46 0x62 0x4B 0x62 0x4B 0x62 0x4B 0x62 0x4B>;
full = <0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F>;
};
};
pad_0x18 { /* p2400 */
epp {
flag = <(SET_FOD_CC(ADD) | SET_FOD_CV(ADD) | SET_FOD_FULL(ADD))>;
cc = <0x65 0x41 0x65 0x41 0x65 0x3C 0x65 0x3C 0x65 0x3E 0x65 0x3E 0x62 0x43 0x62 0x43 0x62 0x43 0x0E 0x0A>;
cv = <0x65 0x49 0x65 0x49 0x65 0x44 0x65 0x44 0x65 0x46 0x65 0x46 0x62 0x4B 0x62 0x4B 0x62 0x4B 0x62 0x4B>;
full = <0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F>;
};
};
};
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,335 @@
/*
* mfc_cmfet.c
* Samsung Mobile MFC CMFET Module
*
* Copyright (C) 2023 Samsung Electronics
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/module.h>
#include "cps4038_charger.h"
#define cmfet_log(str, ...) pr_info("[MFC-CMFET]:%s: "str, __func__, ##__VA_ARGS__)
struct mfc_cmfet {
struct device *parent;
mfc_set_cmfet cb_func;
struct mutex lock;
union mfc_cmfet_state state;
/* threshold */
bool unknown_cmb_ctrl;
unsigned int high_swell_cc_cv_thr;
};
static int mfc_cmfet_parse_dt(struct device_node *np, struct mfc_cmfet *cmfet)
{
int ret = 0;
cmfet->unknown_cmb_ctrl = of_property_read_bool(np, "battery,unknown_cmb_ctrl");
ret = of_property_read_u32(np, "high_swell_cc_cv_thr", &cmfet->high_swell_cc_cv_thr);
if (ret < 0)
cmfet->high_swell_cc_cv_thr = 70;
cmfet_log("unknown_cmb_ctrl = %d, high_swell_cc_cv_thr = %d\n",
cmfet->unknown_cmb_ctrl, cmfet->high_swell_cc_cv_thr);
return 0;
}
struct mfc_cmfet *mfc_cmfet_init(struct device *dev, mfc_set_cmfet cb_func)
{
struct mfc_cmfet *cmfet;
int ret = 0;
if (IS_ERR_OR_NULL(dev) ||
(cb_func == NULL))
return ERR_PTR(-EINVAL);
cmfet = kzalloc(sizeof(struct mfc_cmfet), GFP_KERNEL);
if (!cmfet)
return ERR_PTR(-ENOMEM);
ret = mfc_cmfet_parse_dt(dev->of_node, cmfet);
if (ret < 0) {
kfree(cmfet);
return ERR_PTR(ret);
}
mutex_init(&cmfet->lock);
cmfet->parent = dev;
cmfet->cb_func = cb_func;
cmfet->state.value = 0;
cmfet_log("DONE!!\n");
return cmfet;
}
EXPORT_SYMBOL(mfc_cmfet_init);
int mfc_cmfet_init_state(struct mfc_cmfet *cmfet)
{
if (IS_ERR(cmfet))
return -EINVAL;
mutex_lock(&cmfet->lock);
if (cmfet->state.value != 0) {
cmfet->state.value = 0;
cmfet->cb_func(cmfet->parent, &cmfet->state, false, false);
}
mutex_unlock(&cmfet->lock);
return 0;
}
EXPORT_SYMBOL(mfc_cmfet_init_state);
int mfc_cmfet_refresh(struct mfc_cmfet *cmfet)
{
if (IS_ERR(cmfet))
return -EINVAL;
mutex_lock(&cmfet->lock);
if (cmfet->state.value != 0)
cmfet->cb_func(cmfet->parent, &cmfet->state, cmfet->state.cma, cmfet->state.cmb);
mutex_unlock(&cmfet->lock);
return 0;
}
EXPORT_SYMBOL(mfc_cmfet_refresh);
static void set_init_state(union mfc_cmfet_state *state, bool cma, bool cmb)
{
state->cma = cma;
state->cmb = cmb;
}
static unsigned long long check_tx_default(struct mfc_cmfet *cmfet, union mfc_cmfet_state *state)
{
if (state->high_swell)
state->cmb = (state->bat_cap > cmfet->high_swell_cc_cv_thr);
if (state->full)
state->cmb = true;
if (state->chg_done)
state->cmb = false;
return state->value;
}
static unsigned long long check_tx_unknown(struct mfc_cmfet *cmfet, union mfc_cmfet_state *state)
{
set_init_state(state, true, (cmfet->unknown_cmb_ctrl));
return state->value;
}
static unsigned long long check_tx_p1100(struct mfc_cmfet *cmfet, union mfc_cmfet_state *state)
{
set_init_state(state, true, true);
if (state->vout <= 5500)
state->cmb = false;
if (state->chg_done)
state->cmb = false;
return state->value;
}
static unsigned long long check_tx_n5200(struct mfc_cmfet *cmfet, union mfc_cmfet_state *state)
{
set_init_state(state, true, false);
return check_tx_default(cmfet, state);
}
static unsigned long long check_tx_p5200(struct mfc_cmfet *cmfet, union mfc_cmfet_state *state)
{
set_init_state(state, true, true);
if (state->auth)
state->cmb = false;
return check_tx_default(cmfet, state);
}
static unsigned long long check_cmfet_state(struct mfc_cmfet *cmfet, union mfc_cmfet_state *state)
{
switch (state->tx_id) {
case TX_ID_UNKNOWN:
return check_tx_unknown(cmfet, state);
case TX_ID_P1100_PAD:
return check_tx_p1100(cmfet, state);
case TX_ID_N5200_V_PAD:
case TX_ID_N5200_H_PAD:
return check_tx_n5200(cmfet, state);
case TX_ID_P5200_PAD:
return check_tx_p5200(cmfet, state);
default:
break;
}
set_init_state(state, true, true);
return check_tx_default(cmfet, state);
}
static bool is_changed_state(union mfc_cmfet_state *state1, union mfc_cmfet_state *state2)
{
return (state1->cma != state2->cma) || (state1->cmb != state2->cmb);
}
static int update_cmfet_state(struct mfc_cmfet *cmfet, union mfc_cmfet_state *state)
{
state->value = check_cmfet_state(cmfet, state);
if (is_changed_state(state, &cmfet->state))
cmfet->cb_func(cmfet->parent, state, state->cma, state->cmb);
cmfet->state.value = state->value;
return 0;
}
int mfc_cmfet_set_tx_id(struct mfc_cmfet *cmfet, int tx_id)
{
if (IS_ERR(cmfet) ||
(tx_id < 0) || (tx_id >= 256))
return -EINVAL;
mutex_lock(&cmfet->lock);
if (cmfet->state.tx_id != tx_id) {
union mfc_cmfet_state temp = { cmfet->state.value, };
temp.tx_id = tx_id;
update_cmfet_state(cmfet, &temp);
}
mutex_unlock(&cmfet->lock);
return 0;
}
EXPORT_SYMBOL(mfc_cmfet_set_tx_id);
int mfc_cmfet_set_bat_cap(struct mfc_cmfet *cmfet, int bat_cap)
{
if (IS_ERR(cmfet) ||
(bat_cap < 0) || (bat_cap > 100))
return -EINVAL;
mutex_lock(&cmfet->lock);
if (cmfet->state.bat_cap != bat_cap) {
union mfc_cmfet_state temp = { cmfet->state.value, };
temp.bat_cap = bat_cap;
update_cmfet_state(cmfet, &temp);
}
mutex_unlock(&cmfet->lock);
return 0;
}
EXPORT_SYMBOL(mfc_cmfet_set_bat_cap);
int mfc_cmfet_set_vout(struct mfc_cmfet *cmfet, int vout)
{
if (IS_ERR(cmfet) ||
(vout <= 0))
return -EINVAL;
mutex_lock(&cmfet->lock);
if (cmfet->state.vout != vout) {
union mfc_cmfet_state temp = { cmfet->state.value, };
temp.vout = vout;
update_cmfet_state(cmfet, &temp);
}
mutex_unlock(&cmfet->lock);
return 0;
}
EXPORT_SYMBOL(mfc_cmfet_set_vout);
int mfc_cmfet_set_high_swell(struct mfc_cmfet *cmfet, bool state)
{
if (IS_ERR(cmfet))
return -EINVAL;
mutex_lock(&cmfet->lock);
if (cmfet->state.high_swell != state) {
union mfc_cmfet_state temp = { cmfet->state.value, };
temp.high_swell = state;
update_cmfet_state(cmfet, &temp);
}
mutex_unlock(&cmfet->lock);
return 0;
}
EXPORT_SYMBOL(mfc_cmfet_set_high_swell);
int mfc_cmfet_set_full(struct mfc_cmfet *cmfet, bool full)
{
if (IS_ERR(cmfet))
return -EINVAL;
mutex_lock(&cmfet->lock);
if (cmfet->state.full != full) {
union mfc_cmfet_state temp = { cmfet->state.value, };
temp.full = full;
update_cmfet_state(cmfet, &temp);
}
mutex_unlock(&cmfet->lock);
return 0;
}
EXPORT_SYMBOL(mfc_cmfet_set_full);
int mfc_cmfet_set_chg_done(struct mfc_cmfet *cmfet, bool chg_done)
{
if (IS_ERR(cmfet))
return -EINVAL;
mutex_lock(&cmfet->lock);
if (cmfet->state.chg_done != chg_done) {
union mfc_cmfet_state temp = { cmfet->state.value, };
temp.chg_done = chg_done;
update_cmfet_state(cmfet, &temp);
}
mutex_unlock(&cmfet->lock);
return 0;
}
EXPORT_SYMBOL(mfc_cmfet_set_chg_done);
int mfc_cmfet_set_auth(struct mfc_cmfet *cmfet, bool auth)
{
if (IS_ERR(cmfet))
return -EINVAL;
mutex_lock(&cmfet->lock);
if (cmfet->state.auth != auth) {
union mfc_cmfet_state temp = { cmfet->state.value, };
temp.auth = auth;
update_cmfet_state(cmfet, &temp);
}
mutex_unlock(&cmfet->lock);
return 0;
}
EXPORT_SYMBOL(mfc_cmfet_set_auth);
int mfc_cmfet_get_state(struct mfc_cmfet *cmfet, union mfc_cmfet_state *state)
{
if (IS_ERR(cmfet) ||
(state == NULL))
return -EINVAL;
mutex_lock(&cmfet->lock);
state->value = cmfet->state.value;
mutex_unlock(&cmfet->lock);
return 0;
}
EXPORT_SYMBOL(mfc_cmfet_get_state);

View File

@ -0,0 +1,90 @@
/*
* mfc_cmfet.h
* Samsung Mobile MFC CMFET Header
*
* Copyright (C) 2023 Samsung Electronics, Inc.
*
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __MFC_CMFET_H
#define __MFC_CMFET_H __FILE__
#include <linux/err.h>
struct device;
struct mfc_cmfet;
union mfc_cmfet_state {
unsigned long long value;
struct {
unsigned cma : 1,
cmb : 1,
resv : 6,
tx_id : 8,
vout : 16,
bat_cap : 7,
full : 1,
chg_done : 1,
high_swell : 1,
auth : 1;
};
};
typedef int (*mfc_set_cmfet)(struct device *dev, union mfc_cmfet_state *state, bool cma, bool cmb);
#define MFC_CMFET_DISABLED (-ESRCH)
#if IS_ENABLED(CONFIG_WIRELESS_CHARGING)
struct mfc_cmfet *mfc_cmfet_init(struct device *dev, mfc_set_cmfet cb_func);
int mfc_cmfet_init_state(struct mfc_cmfet *cmfet);
int mfc_cmfet_refresh(struct mfc_cmfet *cmfet);
int mfc_cmfet_set_tx_id(struct mfc_cmfet *cmfet, int tx_id);
int mfc_cmfet_set_bat_cap(struct mfc_cmfet *cmfet, int bat_cap);
int mfc_cmfet_set_vout(struct mfc_cmfet *cmfet, int vout);
int mfc_cmfet_set_high_swell(struct mfc_cmfet *cmfet, bool state);
int mfc_cmfet_set_full(struct mfc_cmfet *cmfet, bool full);
int mfc_cmfet_set_chg_done(struct mfc_cmfet *cmfet, bool chg_done);
int mfc_cmfet_set_auth(struct mfc_cmfet *cmfet, bool auth);
int mfc_cmfet_get_state(struct mfc_cmfet *cmfet, union mfc_cmfet_state *state);
#else
static inline struct mfc_cmfet *mfc_cmfet_init(struct device *dev, mfc_set_cmfet cb_func)
{ return ERR_PTR(MFC_CMFET_DISABLED); }
static inline int mfc_cmfet_init_state(struct mfc_cmfet *cmfet)
{ return MFC_CMFET_DISABLED; }
static inline int mfc_cmfet_refresh(struct mfc_cmfet *cmfet)
{ return MFC_CMFET_DISABLED; }
static inline int mfc_cmfet_set_tx_id(struct mfc_cmfet *cmfet, int tx_id)
{ return MFC_CMFET_DISABLED; }
static inline int mfc_cmfet_set_bat_cap(struct mfc_cmfet *cmfet, int bat_cap)
{ return MFC_CMFET_DISABLED; }
static inline int mfc_cmfet_set_vout(struct mfc_cmfet *cmfet, int vout)
{ return MFC_CMFET_DISABLED; }
static inline int mfc_cmfet_set_high_swell(struct mfc_cmfet *cmfet, bool state)
{ return MFC_CMFET_DISABLED; }
static inline int mfc_cmfet_set_full(struct mfc_cmfet *cmfet, bool full)
{ return MFC_CMFET_DISABLED; }
static inline int mfc_cmfet_set_chg_done(struct mfc_cmfet *cmfet, bool chg_done)
{ return MFC_CMFET_DISABLED; }
static inline int mfc_cmfet_set_auth(struct mfc_cmfet *cmfet, bool auth)
{ return MFC_CMFET_DISABLED; }
static inline int mfc_cmfet_get_state(struct mfc_cmfet *cmfet, union mfc_cmfet_state *state)
{ return MFC_CMFET_DISABLED; }
#endif
#endif /* __MFC_CMFET_H */

View File

@ -0,0 +1,293 @@
/*
* cps4038_firmware.h
* Samsung Mobile CPS4038 FIRMWARE Header
*
* Copyright (C) 2023 Samsung Electronics, Inc.
*
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __CPS4038_FIRMWARE_H
#define __CPS4038_FIRMWARE_H __FILE__
#define MFC_FW_BIN_VERSION 0x4012
#define MFC_FW_VER_BIN_CPS 0x00C4
#define MFC_FLASH_FW_HEX_PATH "mfc/mfc_fw_flash.bin"
#define MFC_FW_SDCARD_BIN_PATH "wpc_fw_sdcard.bin"
#define MFC_FLASH_FW_HEX_CPS_PATH "mfc/mfc_fw_flash_cps4038.bin"
/* for SPU FW update */
#define MFC_FW_SPU_BIN_PATH "mfc/mfc_fw_spu_cps4038.bin"
static const unsigned char CPS4038_BL[0x800] = {
// CPS4038_BL_01_07_V0.2_CRC57AE
0x78, 0x1D, 0x00, 0x20, 0xF9, 0x04, 0x00, 0x20,
0x55, 0x01, 0x00, 0x20, 0x7D, 0x01, 0x00, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x59, 0x01, 0x00, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5B, 0x01, 0x00, 0x20, 0x5D, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x5F, 0x01, 0x00, 0x20, 0x5F, 0x01, 0x00, 0x20,
0x00, 0x01, 0x01, 0x07, 0x00, 0x02, 0x00, 0x00,
0x28, 0x05, 0x00, 0x00, 0x00, 0xF0, 0x02, 0xF8,
0x00, 0xF0, 0x30, 0xF8, 0x0C, 0xA0, 0x30, 0xC8,
0x08, 0x38, 0x24, 0x18, 0x2D, 0x18, 0xA2, 0x46,
0x67, 0x1E, 0xAB, 0x46, 0x54, 0x46, 0x5D, 0x46,
0xAC, 0x42, 0x01, 0xD1, 0x00, 0xF0, 0x22, 0xF8,
0x7E, 0x46, 0x0F, 0x3E, 0x0F, 0xCC, 0xB6, 0x46,
0x01, 0x26, 0x33, 0x42, 0x00, 0xD0, 0xFB, 0x1A,
0xA2, 0x46, 0xAB, 0x46, 0x33, 0x43, 0x18, 0x47,
0x0C, 0x04, 0x00, 0x00, 0x1C, 0x04, 0x00, 0x00,
0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26,
0x10, 0x3A, 0x01, 0xD3, 0x78, 0xC1, 0xFB, 0xD8,
0x52, 0x07, 0x00, 0xD3, 0x30, 0xC1, 0x00, 0xD5,
0x0B, 0x60, 0x70, 0x47, 0x1F, 0xB5, 0x1F, 0xBD,
0x10, 0xB5, 0x10, 0xBD, 0x00, 0xF0, 0xAD, 0xF9,
0x11, 0x46, 0xFF, 0xF7, 0xF7, 0xFF, 0x00, 0xF0,
0x5D, 0xF9, 0x00, 0xF0, 0xC5, 0xF9, 0x03, 0xB4,
0xFF, 0xF7, 0xF2, 0xFF, 0x03, 0xBC, 0x00, 0xF0,
0xCB, 0xF9, 0x00, 0x00, 0xFE, 0xE7, 0xFE, 0xE7,
0xFE, 0xE7, 0xFE, 0xE7, 0xFE, 0xE7, 0xFE, 0xE7,
0x02, 0x48, 0x03, 0x49, 0x03, 0x4A, 0x04, 0x4B,
0x70, 0x47, 0x00, 0x00, 0x78, 0x18, 0x00, 0x20,
0x78, 0x1D, 0x00, 0x20, 0x78, 0x19, 0x00, 0x20,
0x78, 0x19, 0x00, 0x20, 0xFE, 0xE7, 0xA9, 0x48,
0x01, 0x68, 0x00, 0x29, 0x08, 0xD1, 0xA8, 0x4A,
0x0B, 0x21, 0xD1, 0x61, 0xA6, 0x4A, 0xA7, 0x49,
0xC0, 0x32, 0x91, 0x63, 0x01, 0x21, 0x01, 0x60,
0x70, 0x47, 0xA2, 0x48, 0x01, 0x68, 0x01, 0x29,
0x09, 0xD1, 0xA1, 0x49, 0x03, 0x22, 0xCA, 0x61,
0x0B, 0x22, 0xCA, 0x61, 0x9E, 0x4A, 0x00, 0x21,
0xC0, 0x32, 0x91, 0x63, 0x01, 0x60, 0x70, 0x47,
0x30, 0xB5, 0x5F, 0x22, 0x00, 0x23, 0x12, 0x02,
0x90, 0x42, 0x04, 0xDB, 0x9A, 0x4A, 0x90, 0x42,
0x01, 0xD0, 0x00, 0x20, 0x30, 0xBD, 0x96, 0x4A,
0x90, 0x60, 0xD1, 0x60, 0x03, 0x21, 0xD1, 0x61,
0x07, 0x20, 0xD0, 0x61, 0xD0, 0x61, 0xD0, 0x61,
0xD0, 0x61, 0xD1, 0x61, 0x93, 0x48, 0x01, 0x24,
0x15, 0x6A, 0x00, 0x2D, 0x05, 0xD0, 0x40, 0x1E,
0xFA, 0xD2, 0xD4, 0x61, 0xD1, 0x61, 0x01, 0x23,
0xF6, 0xE7, 0x08, 0x20, 0x40, 0x1E, 0xFD, 0xD2,
0x18, 0x46, 0x30, 0xBD, 0x70, 0xB5, 0x04, 0x46,
0x00, 0x20, 0x8B, 0x4D, 0x02, 0x46, 0x0E, 0xE0,
0xA3, 0x5C, 0x1B, 0x02, 0x58, 0x40, 0x00, 0x23,
0x06, 0x04, 0x02, 0xD5, 0x40, 0x00, 0x68, 0x40,
0x00, 0xE0, 0x40, 0x00, 0x5B, 0x1C, 0x80, 0xB2,
0x08, 0x2B, 0xF5, 0xDB, 0x52, 0x1C, 0x8A, 0x42,
0xEE, 0xDB, 0x70, 0xBD, 0x00, 0x25, 0xFF, 0xF7,
0xA2, 0xFF, 0x69, 0x1E, 0x7C, 0x48, 0xFF, 0xF7,
0xBB, 0xFF, 0xFF, 0xF7, 0xAA, 0xFF, 0x7D, 0x4F,
0x7D, 0x49, 0x08, 0x68, 0x00, 0x28, 0xFB, 0xD0,
0x00, 0x22, 0x0A, 0x60, 0x14, 0x46, 0x01, 0x22,
0x39, 0x68, 0x52, 0x02, 0x91, 0x42, 0x01, 0xDD,
0x40, 0x20, 0x7B, 0xE0, 0x66, 0x22, 0x77, 0x49,
0x90, 0x28, 0x0A, 0x60, 0x24, 0xD0, 0x06, 0xDC,
0x10, 0x28, 0x41, 0xD0, 0x20, 0x28, 0x5B, 0xD0,
0x80, 0x28, 0x73, 0xD1, 0x34, 0xE0, 0xB0, 0x28,
0x02, 0xD0, 0xC0, 0x28, 0x6E, 0xD1, 0x66, 0xE0,
0xFF, 0xF7, 0x87, 0xFF, 0x6E, 0x48, 0x84, 0x68,
0x80, 0x14, 0x84, 0x42, 0x02, 0xDD, 0x6D, 0x48,
0x04, 0x60, 0x45, 0xE0, 0x01, 0x20, 0x21, 0x1F,
0x40, 0x07, 0xFF, 0xF7, 0xAF, 0xFF, 0x69, 0x4A,
0x69, 0x49, 0x10, 0x60, 0x61, 0x18, 0xC9, 0x6F,
0x51, 0x60, 0x88, 0x42, 0x38, 0xD1, 0x50, 0xE0,
0xFF, 0xF7, 0x6F, 0xFF, 0xC0, 0x20, 0x84, 0x68,
0x00, 0x2C, 0x31, 0xDB, 0xC0, 0x01, 0x84, 0x42,
0x2E, 0xDC, 0xC8, 0x2C, 0x2C, 0xDB, 0x21, 0x1F,
0x00, 0x20, 0xFF, 0xF7, 0x97, 0xFF, 0x01, 0x46,
0x5C, 0x48, 0x80, 0x3C, 0x01, 0x60, 0xE2, 0x6F,
0x42, 0x60, 0x91, 0x42, 0x20, 0xD1, 0x38, 0xE0,
0xFF, 0xF7, 0x49, 0xFF, 0x59, 0x49, 0x50, 0x48,
0xFF, 0xF7, 0x62, 0xFF, 0x04, 0x46, 0x11, 0xE0,
0xFF, 0xF7, 0x41, 0xFF, 0x00, 0x26, 0x08, 0xE0,
0x52, 0x48, 0xB1, 0x00, 0x41, 0x58, 0x28, 0x46,
0xFF, 0xF7, 0x56, 0xFF, 0x04, 0x43, 0x2D, 0x1D,
0x76, 0x1C, 0x38, 0x68, 0x86, 0x42, 0xF3, 0xDB,
0x4C, 0x48, 0x1A, 0xE0, 0xFF, 0xF7, 0x3D, 0xFF,
0x60, 0x1C, 0x1F, 0xD0, 0x00, 0x2C, 0x18, 0xD0,
0xAA, 0x21, 0x46, 0x48, 0x01, 0x60, 0x8B, 0xE7,
0xFF, 0xF7, 0x25, 0xFF, 0x00, 0x26, 0x08, 0xE0,
0x47, 0x48, 0xB1, 0x00, 0x41, 0x58, 0x28, 0x46,
0xFF, 0xF7, 0x3A, 0xFF, 0x04, 0x43, 0x2D, 0x1D,
0x76, 0x1C, 0x38, 0x68, 0x86, 0x42, 0xF3, 0xDB,
0x41, 0x48, 0x05, 0x60, 0xE2, 0xE7, 0x3D, 0x48,
0x05, 0x68, 0x55, 0x20, 0x39, 0x49, 0x08, 0x60,
0x72, 0xE7, 0xFF, 0xE7, 0x40, 0x21, 0xE0, 0xE7,
0x3D, 0x48, 0x3C, 0x49, 0x01, 0x60, 0x3D, 0x4A,
0x00, 0x21, 0x91, 0x60, 0x33, 0x22, 0x3C, 0x4B,
0x92, 0x03, 0x5A, 0x60, 0x01, 0x60, 0x70, 0x47,
0x01, 0x20, 0x3A, 0x49, 0x80, 0x04, 0x48, 0x63,
0x38, 0x48, 0x39, 0x49, 0x40, 0x30, 0x81, 0x62,
0x01, 0x21, 0xC9, 0x05, 0xC1, 0x62, 0x40, 0x21,
0x41, 0x63, 0xFF, 0x21, 0x35, 0x4A, 0xBD, 0x31,
0x11, 0x60, 0x35, 0x49, 0x41, 0x62, 0x30, 0x49,
0x00, 0x14, 0x48, 0x60, 0x70, 0x47, 0x70, 0xB5,
0x2D, 0x48, 0x00, 0x24, 0x80, 0x30, 0x04, 0x62,
0x31, 0x4B, 0x30, 0x4D, 0xDD, 0x61, 0x2B, 0x49,
0x07, 0x20, 0x40, 0x31, 0x48, 0x61, 0xFF, 0xF7,
0xDB, 0xFF, 0xDC, 0x61, 0x18, 0x48, 0x38, 0x38,
0xC0, 0x6B, 0x2C, 0x49, 0x88, 0x42, 0x0F, 0xD1,
0xDD, 0x61, 0xC1, 0x21, 0x23, 0x4A, 0x00, 0x20,
0xC9, 0x01, 0x80, 0x3A, 0x45, 0x18, 0x2D, 0x68,
0x86, 0x18, 0x35, 0x60, 0x00, 0x1D, 0x80, 0x28,
0xF8, 0xDB, 0xDC, 0x61, 0x01, 0x20, 0x70, 0xBD,
0x00, 0x20, 0x70, 0xBD, 0xFF, 0x21, 0x09, 0x48,
0x01, 0x31, 0x41, 0x60, 0x0D, 0x4A, 0x49, 0x00,
0x11, 0x60, 0x0D, 0x4A, 0x00, 0x21, 0x11, 0x60,
0x0C, 0x4B, 0x55, 0x22, 0x1A, 0x60, 0x01, 0x60,
0xFF, 0xF7, 0xC9, 0xFF, 0xFF, 0xF7, 0xA4, 0xFF,
0xFF, 0xF7, 0x08, 0xFF, 0x0C, 0x18, 0x00, 0x20,
0x00, 0x20, 0x01, 0x40, 0x78, 0x56, 0x00, 0x00,
0xF8, 0x60, 0x00, 0x00, 0x50, 0xC3, 0x00, 0x00,
0x21, 0x10, 0x00, 0x00, 0x08, 0x18, 0x00, 0x20,
0x00, 0x18, 0x00, 0x20, 0x04, 0x18, 0x00, 0x20,
0xC0, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x20,
0x80, 0xFF, 0xFF, 0x1F, 0x85, 0xE1, 0x24, 0x57,
0x00, 0x10, 0x00, 0x20, 0x51, 0xE5, 0xCC, 0x1A,
0x00, 0x8C, 0x00, 0x40, 0x00, 0x80, 0x00, 0x40,
0x00, 0x00, 0x04, 0x40, 0x80, 0xF0, 0x00, 0x40,
0x2C, 0x00, 0x00, 0x04, 0x00, 0x40, 0x00, 0x40,
0x00, 0x02, 0xA1, 0x02, 0x50, 0x12, 0x00, 0x00,
0x40, 0xE7, 0x00, 0x40, 0x4E, 0x87, 0x55, 0x74,
0x70, 0x47, 0x70, 0x47, 0x70, 0x47, 0x70, 0x47,
0x70, 0x47, 0x75, 0x46, 0x00, 0xF0, 0x24, 0xF8,
0xAE, 0x46, 0x05, 0x00, 0x69, 0x46, 0x53, 0x46,
0xC0, 0x08, 0xC0, 0x00, 0x85, 0x46, 0x18, 0xB0,
0x20, 0xB5, 0xFF, 0xF7, 0x59, 0xFE, 0x60, 0xBC,
0x00, 0x27, 0x49, 0x08, 0xB6, 0x46, 0x00, 0x26,
0xC0, 0xC5, 0xC0, 0xC5, 0xC0, 0xC5, 0xC0, 0xC5,
0xC0, 0xC5, 0xC0, 0xC5, 0xC0, 0xC5, 0xC0, 0xC5,
0x40, 0x3D, 0x49, 0x00, 0x8D, 0x46, 0x70, 0x47,
0x10, 0xB5, 0x04, 0x46, 0xC0, 0x46, 0xC0, 0x46,
0x20, 0x46, 0xFF, 0xF7, 0x34, 0xFE, 0x10, 0xBD,
0x00, 0x48, 0x70, 0x47, 0x14, 0x18, 0x00, 0x20,
0x01, 0x49, 0x18, 0x20, 0xAB, 0xBE, 0xFE, 0xE7,
0x26, 0x00, 0x02, 0x00, 0x70, 0x47, 0x00, 0x00,
0x03, 0x49, 0x00, 0x20, 0x48, 0x60, 0x08, 0x60,
0x02, 0x48, 0x80, 0x47, 0x02, 0x48, 0x00, 0x47,
0x14, 0xE1, 0x00, 0x40, 0x8B, 0x04, 0x00, 0x20,
0xCD, 0x00, 0x00, 0x20, 0x24, 0x05, 0x00, 0x20,
0x00, 0x08, 0x00, 0x20, 0x78, 0x15, 0x00, 0x00,
0x10, 0x01, 0x00, 0x20, 0x16, 0x2B, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#endif /* __CPS4038_FIRMWARE_H */

View File

@ -0,0 +1,721 @@
/*
* mfc_fod.c
* Samsung Mobile MFC FOD Module
*
* Copyright (C) 2023 Samsung Electronics
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/battery/sb_wireless.h>
#include <dt-bindings/battery/sec-battery.h>
#include "cps4038_fod.h"
#define fod_log(str, ...) pr_info("[MFC-FOD]:%s: "str, __func__, ##__VA_ARGS__)
#define DEFAULT_TX_IDX 0
#define DEFAULT_OP_MODE WPC_OP_MODE_BPP
#define DEFAULT_VENDOR_ID 0x42
struct mfc_fod_op {
unsigned int flag;
fod_data_t *data[MFC_FOD_BAT_STATE_MAX];
};
struct mfc_fod_tx {
unsigned int id;
struct mfc_fod_op op[WPC_OP_MODE_MAX];
};
struct mfc_fod {
struct device *parent;
mfc_set_fod cb_func;
struct mutex lock;
union mfc_fod_state state;
/* fod data */
struct mfc_fod_tx *list;
unsigned int count;
unsigned int ext[MFC_FOD_EXT_MAX];
/* threshold */
unsigned int bpp_vout;
unsigned int cc_cv_thr;
unsigned int high_swell_cc_cv_thr;
unsigned int vendor_id;
};
static int get_op_mode_by_str(const char *str)
{
if (str == NULL)
return WPC_OP_MODE_NONE;
if (!strncmp(str, "ppde", 4))
return WPC_OP_MODE_PPDE;
if (!strncmp(str, "epp", 3))
return WPC_OP_MODE_EPP;
if (!strncmp(str, "mpp", 3))
return WPC_OP_MODE_MPP;
return WPC_OP_MODE_BPP;
}
static const char *get_ext_str(unsigned int ext_type)
{
switch (ext_type) {
case MFC_FOD_EXT_EPP_REF_QF:
return "epp_ref_qf";
case MFC_FOD_EXT_EPP_REF_RF:
return "epp_ref_rf";
}
return "none";
}
static const char *get_bat_state_str(unsigned int bat_state)
{
switch (bat_state) {
case MFC_FOD_BAT_STATE_CC:
return "cc";
case MFC_FOD_BAT_STATE_CV:
return "cv";
case MFC_FOD_BAT_STATE_FULL:
return "full";
}
return "none";
}
static fod_data_t *mfc_fod_parse_data(struct device_node *np, int bat_state, unsigned int fod_size)
{
fod_data_t *data;
const u32 *p;
int len = 0, t_size = 0, ret;
p = of_get_property(np, get_bat_state_str(bat_state), &len);
if (!p)
return NULL;
t_size = sizeof(fod_data_t);
data = kcalloc(fod_size, t_size, GFP_KERNEL);
if (!data)
return NULL;
if (fod_size != (len / t_size)) {
fod_log("not match the size(%d, %d, %d)\n", fod_size, len, t_size);
goto err_size;
}
switch (t_size) {
case sizeof(u64):
ret = of_property_read_u64_array(np, get_bat_state_str(bat_state),
(u64 *)data, fod_size);
break;
case sizeof(u32):
ret = of_property_read_u32_array(np, get_bat_state_str(bat_state),
(u32 *)data, fod_size);
break;
case sizeof(u16):
ret = of_property_read_u16_array(np, get_bat_state_str(bat_state),
(u16 *)data, fod_size);
break;
case sizeof(u8):
ret = of_property_read_u8_array(np, get_bat_state_str(bat_state),
(u8 *)data, fod_size);
break;
default:
fod_log("invalid t size(%d)\n", t_size);
goto err_size;
}
if (ret < 0) {
fod_log("%s, failed to parse data (ret = %d)\n", get_bat_state_str(bat_state), ret);
goto err_size;
}
return data;
err_size:
kfree(data);
return NULL;
}
static int mfc_fod_parse_op_node(struct device_node *np,
struct mfc_fod *fod, struct mfc_fod_tx *fod_tx, int op_mode, unsigned int fod_size)
{
struct mfc_fod_op *fod_op = &fod_tx->op[op_mode];
unsigned int flag = 0;
int ret = 0, i;
ret = of_property_read_u32(np, "flag", &flag);
if (ret < 0) {
pr_err("%s: failed to get flag of %s\n", __func__, np->name);
return ret;
}
for (i = MFC_FOD_BAT_STATE_CC; i < MFC_FOD_BAT_STATE_MAX; i++) {
switch ((flag >> (i * 4)) & 0xF) {
case FOD_FLAG_ADD:
fod_op->data[i] = mfc_fod_parse_data(np, i, fod_size);
if (fod_op->data[i] == NULL) {
ret = -1;
goto err_data;
}
break;
case FOD_FLAG_USE_CC:
if (fod_op->data[MFC_FOD_BAT_STATE_CC] == NULL) {
ret = -2;
goto err_data;
}
fod_op->data[i] = fod_op->data[MFC_FOD_BAT_STATE_CC];
break;
case FOD_FLAG_USE_CV:
if (fod_op->data[MFC_FOD_BAT_STATE_CV] == NULL) {
ret = -3;
goto err_data;
}
fod_op->data[i] = fod_op->data[MFC_FOD_BAT_STATE_CV];
break;
case FOD_FLAG_USE_FULL:
if (fod_op->data[MFC_FOD_BAT_STATE_FULL] == NULL) {
ret = -4;
goto err_data;
}
fod_op->data[i] = fod_op->data[MFC_FOD_BAT_STATE_FULL];
break;
case FOD_FLAG_USE_DEF_PAD:
{
struct mfc_fod_tx *def_tx = &fod->list[DEFAULT_TX_IDX];
if (def_tx->op[op_mode].data[i] == NULL) {
ret = -5;
goto err_data;
}
fod_op->data[i] = def_tx->op[op_mode].data[i];
}
break;
case FOD_FLAG_USE_DEF_OP:
{
struct mfc_fod_op *def_op = &fod_tx->op[DEFAULT_OP_MODE];
if (def_op->data[i] == NULL) {
ret = -6;
goto err_data;
}
fod_op->data[i] = def_op->data[i];
}
break;
case FOD_FLAG_NONE:
default:
fod_log("%s - %s is not set\n", np->name, get_bat_state_str(i));
break;
}
}
fod_op->flag = flag;
return 0;
err_data:
for (; i >= 0; i--) {
if (((flag >> (i * 4)) & 0xF) == FOD_FLAG_ADD)
kfree(fod_op->data[i]);
}
return ret;
}
static int mfc_fod_init_ext_pad(struct mfc_fod_tx *fod_tx, struct mfc_fod_tx *def_tx)
{
int i, j;
if (fod_tx->id == DEFAULT_TX_IDX)
return 0;
for (j = WPC_OP_MODE_NONE; j < WPC_OP_MODE_MAX; j++) {
if (def_tx->op[j].flag == 0)
continue;
for (i = MFC_FOD_BAT_STATE_CC; i < MFC_FOD_BAT_STATE_MAX; i++)
fod_tx->op[j].data[i] = def_tx->op[j].data[i];
fod_tx->op[j].flag =
(SET_FOD_CC(USE_DEF_PAD) | SET_FOD_CV(USE_DEF_PAD) | SET_FOD_FULL(USE_DEF_PAD));
}
return 0;
}
static int mfc_fod_parse_tx_node(struct device_node *np, struct mfc_fod *fod, unsigned int fod_size)
{
struct device_node *tx_node = NULL;
int ret = 0, tx_idx = 0;
for_each_child_of_node(np, tx_node) {
struct mfc_fod_tx *fod_tx = NULL;
struct device_node *op_node = NULL;
if (tx_idx >= fod->count) {
fod_log("out of range(%d <--> %d)\n", tx_idx, fod->count);
break;
}
fod_tx = &fod->list[tx_idx++];
if (sscanf(tx_node->name, "pad_0x%X", &fod_tx->id) < 0) {
fod_log("failed to get tx id(%s)\n", tx_node->name);
continue;
}
mfc_fod_init_ext_pad(fod_tx, &fod->list[DEFAULT_TX_IDX]);
for_each_child_of_node(tx_node, op_node) {
int op_mode;
op_mode = get_op_mode_by_str(op_node->name);
if (op_mode == WPC_OP_MODE_NONE) {
fod_log("%s, invalid op name\n", op_node->name);
continue;
}
ret = mfc_fod_parse_op_node(op_node, fod, fod_tx, op_mode, fod_size);
if (ret < 0)
fod_log("%s, failed to parse data(ret = %d)\n", op_node->name, ret);
}
}
return 0;
}
static void mfc_fod_print_data(struct mfc_fod *fod, unsigned int fod_size)
{
int x, y, z, k;
struct mfc_fod_tx *fod_tx;
for (x = 0; x < fod->count; x++) {
fod_tx = &fod->list[x];
for (y = WPC_OP_MODE_NONE + 1; y < WPC_OP_MODE_MAX; y++) {
for (z = MFC_FOD_BAT_STATE_CC; z < MFC_FOD_BAT_STATE_MAX; z++) {
char temp_buf[1024] = {0, };
int size = 1024;
if (fod_tx->op[y].data[z] == NULL) {
fod_log("PAD_0x%02X:%s:%s is null!!\n",
fod_tx->id, sb_wrl_op_mode_str(y), get_bat_state_str(z));
continue;
}
for (k = 0; k < fod_size; k++) {
snprintf(temp_buf + strlen(temp_buf), size, "0x%02X ", fod_tx->op[y].data[z][k]);
size = sizeof(temp_buf) - strlen(temp_buf);
}
fod_log("PAD_0x%02X:%s:%s - %s\n",
fod_tx->id, sb_wrl_op_mode_str(y), get_bat_state_str(z), temp_buf);
}
}
}
}
static void mfc_fod_print_ext(struct mfc_fod *fod)
{
char ext_buf[1024] = {0, };
int x, ext_size = 1024;
for (x = 0; x < MFC_FOD_EXT_MAX; x++) {
snprintf(ext_buf + strlen(ext_buf), ext_size, "%02d:0x%X ", x, fod->ext[x]);
ext_size = sizeof(ext_buf) - strlen(ext_buf);
}
fod_log("EXT - %s\n", ext_buf);
}
static int mfc_fod_parse_dt(struct device_node *np, struct mfc_fod *fod, unsigned int fod_size)
{
int ret = 0, i;
np = of_find_node_by_name(np, "fod_list");
if (!np) {
fod_log("fod list is null!!!!\n");
return -ENODEV;
}
ret = of_property_read_u32(np, "count", &fod->count);
if (ret < 0) {
fod_log("count is null(ret = %d)\n", ret);
return ret;
}
fod->list = kcalloc(fod->count, sizeof(struct mfc_fod_tx), GFP_KERNEL);
if (!fod->list) {
fod_log("failed to alloc fod list\n");
return -ENOMEM;
}
ret = mfc_fod_parse_tx_node(np, fod, fod_size);
if (ret < 0) {
kfree(fod->list);
return ret;
}
/* parse ext */
for (i = 0; i < MFC_FOD_EXT_MAX; i++) {
ret = of_property_read_u32(np, get_ext_str(i), (unsigned int *)&fod->ext[i]);
if (ret < 0)
fod_log("%s is null(ret = %d)!!\n", get_ext_str(i), ret);
}
mfc_fod_print_data(fod, fod_size);
mfc_fod_print_ext(fod);
return 0;
}
static int mfc_fod_thr_parse_dt(struct device_node *np, struct mfc_fod *fod)
{
int ret = 0;
ret = of_property_read_u32(np, "bpp_vout", &fod->bpp_vout);
if (ret < 0)
fod->bpp_vout = 7000;
ret = of_property_read_u32(np, "cc_cv_thr", &fod->cc_cv_thr);
if (ret < 0)
fod->cc_cv_thr = 85;
ret = of_property_read_u32(np, "high_swell_cc_cv_thr", &fod->high_swell_cc_cv_thr);
if (ret < 0)
fod->high_swell_cc_cv_thr = 70;
ret = of_property_read_u32(np, "vendor_id", (unsigned int *)&fod->vendor_id);
if (ret < 0) {
fod_log("vendor_id is null(ret = %d)!!\n", ret);
fod->vendor_id = DEFAULT_VENDOR_ID;
}
fod_log("bpp_vout = %d, cc_cv_thr = %d, high_swell_cc_cv_thr = %d, vendor_id = 0x%x\n",
fod->bpp_vout, fod->cc_cv_thr, fod->high_swell_cc_cv_thr, fod->vendor_id);
return 0;
}
static struct mfc_fod_tx *get_fod_tx(struct mfc_fod *fod, unsigned int tx_id)
{
int i;
for (i = 0; i < fod->count; i++) {
if (fod->list[i].id == tx_id)
return &fod->list[i];
}
return &fod->list[DEFAULT_TX_IDX];
}
static bool check_vendor_id_to_set_op_mode_by_vout(union mfc_fod_state *state, int vendor_id)
{
return (state->vendor_id == vendor_id);
}
static int check_op_mode_vout(struct mfc_fod *fod, union mfc_fod_state *state)
{
if (!check_vendor_id_to_set_op_mode_by_vout(state, fod->vendor_id))
return state->op_mode;
switch (state->op_mode) {
case WPC_OP_MODE_EPP:
case WPC_OP_MODE_PPDE:
if (state->vout <= fod->bpp_vout)
return WPC_OP_MODE_BPP;
break;
case WPC_OP_MODE_MPP:
break;
default:
/* default op mode */
return WPC_OP_MODE_BPP;
}
return state->op_mode;
}
static fod_data_t *mfc_fod_get_data(struct mfc_fod *fod)
{
union mfc_fod_state *fod_state = &fod->state;
struct mfc_fod_tx *fod_tx;
if (fod->count <= 0)
return NULL;
fod_tx = get_fod_tx(fod, fod_state->tx_id);
fod_state->fake_op_mode = check_op_mode_vout(fod, fod_state);
return fod_tx->op[fod_state->fake_op_mode].data[fod_state->bat_state];
}
struct mfc_fod *mfc_fod_init(struct device *dev, unsigned int fod_size, mfc_set_fod cb_func)
{
struct mfc_fod *fod;
int ret = 0;
if (IS_ERR_OR_NULL(dev) ||
(fod_size <= 0) ||
(fod_size > MFC_FOD_MAX_SIZE) ||
(cb_func == NULL))
return ERR_PTR(-EINVAL);
fod = kzalloc(sizeof(struct mfc_fod), GFP_KERNEL);
if (!fod)
return ERR_PTR(-ENOMEM);
ret = mfc_fod_parse_dt(dev->of_node, fod, fod_size);
if (ret < 0) {
kfree(fod);
return ERR_PTR(ret);
}
mfc_fod_thr_parse_dt(dev->of_node, fod);
mutex_init(&fod->lock);
fod->parent = dev;
fod->cb_func = cb_func;
fod->state.value = 0;
fod_log("DONE!!\n");
return fod;
}
EXPORT_SYMBOL(mfc_fod_init);
int mfc_fod_init_state(struct mfc_fod *fod)
{
if (IS_ERR(fod))
return -EINVAL;
mutex_lock(&fod->lock);
if (fod->state.value != 0) {
fod->state.value = 0;
fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
}
mutex_unlock(&fod->lock);
return 0;
}
EXPORT_SYMBOL(mfc_fod_init_state);
int mfc_fod_refresh(struct mfc_fod *fod)
{
if (IS_ERR(fod))
return -EINVAL;
mutex_lock(&fod->lock);
if (fod->state.value != 0)
fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
mutex_unlock(&fod->lock);
return 0;
}
EXPORT_SYMBOL(mfc_fod_refresh);
int mfc_fod_set_op_mode(struct mfc_fod *fod, int op_mode)
{
if (IS_ERR(fod) ||
(op_mode < WPC_OP_MODE_NONE) ||
(op_mode >= WPC_OP_MODE_MAX))
return -EINVAL;
mutex_lock(&fod->lock);
switch (fod->state.op_mode) {
case WPC_OP_MODE_EPP:
case WPC_OP_MODE_MPP:
case WPC_OP_MODE_PPDE:
fod_log("prevent op mode(%d)!!\n", op_mode);
break;
case WPC_OP_MODE_BPP:
case WPC_OP_MODE_NONE:
default:
if (fod->state.op_mode != op_mode) {
fod->state.op_mode = op_mode;
fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
}
break;
}
mutex_unlock(&fod->lock);
return 0;
}
EXPORT_SYMBOL(mfc_fod_set_op_mode);
int mfc_fod_set_vendor_id(struct mfc_fod *fod, int vendor_id)
{
if (IS_ERR(fod) ||
(vendor_id < 0) ||
(vendor_id > 0xFF))
return -EINVAL;
mutex_lock(&fod->lock);
if (vendor_id != fod->state.vendor_id) {
fod->state.vendor_id = vendor_id;
fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
}
mutex_unlock(&fod->lock);
return 0;
}
EXPORT_SYMBOL(mfc_fod_set_vendor_id);
int mfc_fod_set_tx_id(struct mfc_fod *fod, int tx_id)
{
if (IS_ERR(fod) ||
(tx_id < 0) || (tx_id >= 256))
return -EINVAL;
mutex_lock(&fod->lock);
if (fod->state.tx_id != tx_id) {
fod->state.tx_id = tx_id;
fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
}
mutex_unlock(&fod->lock);
return 0;
}
EXPORT_SYMBOL(mfc_fod_set_tx_id);
static int check_bat_state(struct mfc_fod *fod)
{
if (fod->state.high_swell)
return (fod->state.bat_cap > fod->high_swell_cc_cv_thr) ?
MFC_FOD_BAT_STATE_CV : MFC_FOD_BAT_STATE_CC;
return (fod->state.bat_cap > fod->cc_cv_thr) ?
MFC_FOD_BAT_STATE_CV : MFC_FOD_BAT_STATE_CC;
}
static int set_bat_state(struct mfc_fod *fod, int bat_state)
{
switch (fod->state.bat_state) {
case MFC_FOD_BAT_STATE_FULL:
fod_log("prevent bat state(%d)!!\n", bat_state);
break;
case MFC_FOD_BAT_STATE_CC:
case MFC_FOD_BAT_STATE_CV:
default:
if (fod->state.bat_state != bat_state) {
fod->state.bat_state = bat_state;
fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
}
break;
}
return 0;
}
int mfc_fod_set_bat_state(struct mfc_fod *fod, int bat_state)
{
if (IS_ERR(fod) ||
(bat_state < MFC_FOD_BAT_STATE_CC) ||
(bat_state >= MFC_FOD_BAT_STATE_MAX))
return -EINVAL;
mutex_lock(&fod->lock);
set_bat_state(fod, bat_state);
mutex_unlock(&fod->lock);
return 0;
}
EXPORT_SYMBOL(mfc_fod_set_bat_state);
int mfc_fod_set_bat_cap(struct mfc_fod *fod, int bat_cap)
{
if (IS_ERR(fod) ||
(bat_cap < 0) || (bat_cap > 100))
return -EINVAL;
mutex_lock(&fod->lock);
if (fod->state.bat_cap != bat_cap) {
fod->state.bat_cap = bat_cap;
set_bat_state(fod, check_bat_state(fod));
}
mutex_unlock(&fod->lock);
return 0;
}
EXPORT_SYMBOL(mfc_fod_set_bat_cap);
int mfc_fod_set_vout(struct mfc_fod *fod, int vout)
{
if (IS_ERR(fod) ||
(vout <= 0))
return -EINVAL;
mutex_lock(&fod->lock);
if (fod->state.vout != vout) {
int new_op_mode, old_op_mode;
old_op_mode = check_op_mode_vout(fod, &fod->state);
fod->state.vout = vout;
new_op_mode = check_op_mode_vout(fod, &fod->state);
if (new_op_mode != old_op_mode)
fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
}
mutex_unlock(&fod->lock);
return 0;
}
EXPORT_SYMBOL(mfc_fod_set_vout);
int mfc_fod_set_high_swell(struct mfc_fod *fod, bool state)
{
if (IS_ERR(fod))
return -EINVAL;
mutex_lock(&fod->lock);
if (fod->state.high_swell != state) {
fod->state.high_swell = state;
set_bat_state(fod, check_bat_state(fod));
}
mutex_unlock(&fod->lock);
return 0;
}
EXPORT_SYMBOL(mfc_fod_set_high_swell);
int mfc_fod_get_state(struct mfc_fod *fod, union mfc_fod_state *state)
{
if (IS_ERR(fod) ||
(state == NULL))
return -EINVAL;
mutex_lock(&fod->lock);
state->value = fod->state.value;
mutex_unlock(&fod->lock);
return 0;
}
EXPORT_SYMBOL(mfc_fod_get_state);
int mfc_fod_get_ext(struct mfc_fod *fod, int ext_type, int *data)
{
if (IS_ERR(fod) ||
(ext_type < MFC_FOD_EXT_EPP_REF_QF) ||
(ext_type >= MFC_FOD_EXT_MAX) ||
(data == NULL))
return -EINVAL;
mutex_lock(&fod->lock);
*data = fod->ext[ext_type];
mutex_unlock(&fod->lock);
return 0;
}
EXPORT_SYMBOL(mfc_fod_get_ext);

View File

@ -0,0 +1,108 @@
/*
* mfc_fod.h
* Samsung Mobile MFC FOD Header
*
* Copyright (C) 2023 Samsung Electronics, Inc.
*
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __MFC_FOD_H
#define __MFC_FOD_H __FILE__
#include <linux/err.h>
struct device;
struct mfc_fod;
#define MFC_FOD_MAX_SIZE 256
enum {
MFC_FOD_BAT_STATE_CC = 0,
MFC_FOD_BAT_STATE_CV,
MFC_FOD_BAT_STATE_FULL,
MFC_FOD_BAT_STATE_MAX
};
union mfc_fod_state {
unsigned long long value;
struct {
unsigned tx_id : 8,
vendor_id : 8,
op_mode : 8,
fake_op_mode : 8,
bat_state : 8,
bat_cap : 7,
high_swell : 1,
vout : 16;
};
};
typedef unsigned int fod_data_t;
typedef int (*mfc_set_fod)(struct device *dev, union mfc_fod_state *state, fod_data_t *data);
enum {
MFC_FOD_EXT_EPP_REF_QF = 0,
MFC_FOD_EXT_EPP_REF_RF,
MFC_FOD_EXT_MAX
};
#define MFC_FOD_DISABLED (-ESRCH)
#if IS_ENABLED(CONFIG_WIRELESS_CHARGING)
struct mfc_fod *mfc_fod_init(struct device *dev, unsigned int fod_size, mfc_set_fod cb_func);
int mfc_fod_init_state(struct mfc_fod *fod);
int mfc_fod_refresh(struct mfc_fod *fod);
int mfc_fod_set_op_mode(struct mfc_fod *fod, int op_mode);
int mfc_fod_set_vendor_id(struct mfc_fod *fod, int vendor_id);
int mfc_fod_set_tx_id(struct mfc_fod *fod, int tx_id);
int mfc_fod_set_bat_state(struct mfc_fod *fod, int bat_state);
int mfc_fod_set_bat_cap(struct mfc_fod *fod, int bat_cap);
int mfc_fod_set_vout(struct mfc_fod *fod, int vout);
int mfc_fod_set_high_swell(struct mfc_fod *fod, bool state);
int mfc_fod_get_state(struct mfc_fod *fod, union mfc_fod_state *state);
int mfc_fod_get_ext(struct mfc_fod *fod, int ext_type, int *data);
#else
static inline struct mfc_fod *mfc_fod_init(struct device *dev, unsigned int fod_size, mfc_set_fod cb_func)
{ return ERR_PTR(MFC_FOD_DISABLED); }
static inline int mfc_fod_init_state(struct mfc_fod *fod)
{ return MFC_FOD_DISABLED; }
static inline int mfc_fod_refresh(struct mfc_fod *fod)
{ return MFC_FOD_DISABLED; }
static inline int mfc_fod_set_op_mode(struct mfc_fod *fod, int op_mode)
{ return MFC_FOD_DISABLED; }
static inline int mfc_fod_set_vendor_id(struct mfc_fod *fod, int vendor_id)
{ return MFC_FOD_DISABLED; }
static inline int mfc_fod_set_tx_id(struct mfc_fod *fod, int tx_id)
{ return MFC_FOD_DISABLED; }
static inline int mfc_fod_set_bat_state(struct mfc_fod *fod, int bat_state)
{ return MFC_FOD_DISABLED; }
static inline int mfc_fod_set_bat_cap(struct mfc_fod *fod, int bat_cap)
{ return MFC_FOD_DISABLED; }
static inline int mfc_fod_set_vout(struct mfc_fod *fod, int vout)
{ return MFC_FOD_DISABLED; }
static inline int mfc_fod_set_high_swell(struct mfc_fod *fod, bool state)
{ return MFC_FOD_DISABLED; }
static inline int mfc_fod_get_state(struct mfc_fod *fod, union mfc_fod_state *state)
{ return MFC_FOD_DISABLED; }
static inline int mfc_fod_get_ext(struct mfc_fod *fod, int ext_type, int *data)
{ return MFC_FOD_DISABLED; }
#endif
#endif /* __MFC_FOD_H */