kernel:moto charger/battery driver enable

Enable moto charger battery feature
at gaum

Change-Id: I8ff7240bdb42afd7bfd120ed4d35cbc84803000c
Signed-off-by: xuwei9 <xuwei9@mt.com>
Reviewed-on: https://gerrit.mot.com/1509675
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Xiangpo Zhao <zhaoxp3@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
xuwei9 2020-03-10 11:53:54 +08:00 committed by caoqian4
parent 09919c1697
commit 7930a06896
19 changed files with 5404 additions and 79 deletions

View file

@ -555,7 +555,85 @@ struct lut_table {
u32 tablesize;
};
#ifdef CONFIG_BAT_NTC_10K
static const struct vadc_map_pt adcmap_batt_therm_30k_NTC10K[] = {
{1618, -400},
{1593, -380},
{1566, -360},
{1538, -340},
{1508, -320},
{1477, -300},
{1444, -280},
{1410, -260},
{1374, -240},
{1338, -220},
{1300, -200},
{1261, -180},
{1221, -160},
{1181, -140},
{1140, -120},
{1099, -100},
{1057, -80},
{1016, -60},
{974, -40},
{934, -20},
{893, 0},
{853, 20},
{814, 40},
{776, 60},
{738, 80},
{702, 100},
{667, 120},
{633, 140},
{600, 160},
{569, 180},
{539, 200},
{510, 220},
{482, 240},
{456, 260},
{431, 280},
{407, 300},
{384, 320},
{363, 340},
{342, 360},
{323, 380},
{305, 400},
{288, 420},
{272, 440},
{256, 460},
{242, 480},
{228, 500},
{215, 520},
{203, 540},
{192, 560},
{181, 580},
{171, 600},
{162, 620},
{153, 640},
{145, 660},
{137, 680},
{130, 700},
{123, 720},
{116, 740},
{110, 760},
{104, 780},
{99, 800},
{94, 820},
{89, 840},
{84, 860},
{80, 880},
{76, 900},
{72, 920},
{69, 940},
{65, 960},
{62, 980}
};
#endif
static const struct lut_table lut_table_30[] = {
#ifdef CONFIG_BAT_NTC_10K
{adcmap_batt_therm_30k_NTC10K, ARRAY_SIZE(adcmap_batt_therm_30k_NTC10K)},
#endif
{adcmap_batt_therm_30k, ARRAY_SIZE(adcmap_batt_therm_30k)},
{adcmap_batt_therm_30k_6125, ARRAY_SIZE(adcmap_batt_therm_30k_6125)},
};

View file

@ -308,6 +308,85 @@ static int64_t of_batterydata_convert_battery_id_kohm(int batt_id_uv,
return resistor_value_kohm;
}
static const char *get_battery_serialnumber(void)
{
struct device_node *np = of_find_node_by_path("/chosen");
const char *battsn_buf;
int retval;
if (np)
retval = of_property_read_string(np, "mmi,battid",
&battsn_buf);
else
return NULL;
if ((retval == -EINVAL) || !battsn_buf) {
pr_err("Battsn unused\n");
of_node_put(np);
return NULL;
} else
pr_err("Battsn = %s\n", battsn_buf);
of_node_put(np);
return battsn_buf;
}
static struct device_node *get_profile_by_serialnumber(
const struct device_node *np)
{
struct device_node *node, *df_node, *sn_node;
const char *sn_buf, *df_sn, *dev_sn;
int rc;
if (!np)
return NULL;
dev_sn = NULL;
df_sn = NULL;
sn_buf = NULL;
df_node = NULL;
sn_node = NULL;
dev_sn = get_battery_serialnumber();
rc = of_property_read_string(np, "df-serialnum",
&df_sn);
if (rc)
pr_warn("No Default Serial Number defined\n");
else if (df_sn)
pr_info("Default Serial Number %s\n", df_sn);
for_each_child_of_node(np, node) {
rc = of_property_read_string(node, "serialnum",
&sn_buf);
if (!rc && sn_buf) {
if (dev_sn)
if (strnstr(dev_sn, sn_buf, 32))
sn_node = node;
if (df_sn)
if (strnstr(df_sn, sn_buf, 32))
df_node = node;
}
}
if (sn_node) {
node = sn_node;
df_node = NULL;
pr_info("Battery Match Found using %s\n", sn_node->name);
} else if (df_node) {
node = df_node;
sn_node = NULL;
pr_info("Battery Match Found using default %s\n",
df_node->name);
} else {
pr_warn("No Battery Match Found!\n");
return NULL;
}
return node;
}
struct device_node *of_batterydata_get_best_profile(
const struct device_node *batterydata_container_node,
int batt_id_kohm, const char *batt_type)
@ -332,6 +411,10 @@ struct device_node *of_batterydata_get_best_profile(
}
}
best_node = get_profile_by_serialnumber(batterydata_container_node);
if (best_node)
return best_node;
/*
* Find the battery data with a battery id resistor closest to this one
*/

View file

@ -464,6 +464,13 @@ config CHARGER_GPIO
This driver can be build as a module. If so, the module will be
called gpio-charger.
config BAT_NTC_10K
bool "for ntc 10k"
default n
help
Say Y to enable
for battery ntc 10k
config CHARGER_MANAGER
bool "Battery charger manager for multiple chargers"
depends on REGULATOR

View file

@ -153,6 +153,8 @@ static void power_supply_deferred_register_work(struct work_struct *work)
}
psy_register_cooler(psy->dev.parent, psy);
atomic_notifier_call_chain(&power_supply_notifier,
PSY_EVENT_PROP_ADDED, psy);
power_supply_changed(psy);
if (psy->dev.parent)
@ -463,7 +465,10 @@ struct power_supply *power_supply_get_by_name(const char *name)
if (dev) {
psy = dev_get_drvdata(dev);
atomic_inc(&psy->use_cnt);
if (atomic_read(&psy->use_cnt) >= 1)
atomic_inc(&psy->use_cnt);
else
psy = NULL;
}
return psy;
@ -522,7 +527,10 @@ struct power_supply *power_supply_get_by_phandle(struct device_node *np,
if (dev) {
psy = dev_get_drvdata(dev);
atomic_inc(&psy->use_cnt);
if (atomic_read(&psy->use_cnt) >= 1)
atomic_inc(&psy->use_cnt);
else
psy = NULL;
}
return psy;
@ -629,7 +637,8 @@ int power_supply_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
if (atomic_read(&psy->use_cnt) <= 0) {
if (!psy || atomic_read(&psy->use_cnt) <= 0 ||
!psy->desc || !psy->desc->get_property) {
if (!psy->initialized)
return -EAGAIN;
return -ENODEV;
@ -643,7 +652,8 @@ int power_supply_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
if (atomic_read(&psy->use_cnt) <= 0 || !psy->desc->set_property)
if (!psy || atomic_read(&psy->use_cnt) <= 0 ||
!psy->desc || !psy->desc->set_property)
return -ENODEV;
return psy->desc->set_property(psy, psp, val);
@ -653,8 +663,8 @@ EXPORT_SYMBOL_GPL(power_supply_set_property);
int power_supply_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
if (atomic_read(&psy->use_cnt) <= 0 ||
!psy->desc->property_is_writeable)
if (!psy || atomic_read(&psy->use_cnt) <= 0 ||
!psy->desc || !psy->desc->property_is_writeable)
return -ENODEV;
return psy->desc->property_is_writeable(psy, psp);
@ -663,8 +673,8 @@ EXPORT_SYMBOL_GPL(power_supply_property_is_writeable);
void power_supply_external_power_changed(struct power_supply *psy)
{
if (atomic_read(&psy->use_cnt) <= 0 ||
!psy->desc->external_power_changed)
if (!psy || atomic_read(&psy->use_cnt) <= 0 ||
!psy->desc || !psy->desc->external_power_changed)
return;
psy->desc->external_power_changed(psy);
@ -679,9 +689,15 @@ EXPORT_SYMBOL_GPL(power_supply_powers);
static void power_supply_dev_release(struct device *dev)
{
struct power_supply *psy = to_power_supply(dev);
dev_dbg(dev, "%s\n", __func__);
struct power_supply *psy = container_of(dev, struct power_supply, dev);
void *drvr_data = NULL;
if (psy->free_pdd_on_release)
drvr_data = psy->drv_data;
pr_warn("device: '%s': %s\n", dev_name(dev), __func__);
kfree(psy);
if (drvr_data)
kfree(drvr_data);
}
int power_supply_reg_notifier(struct notifier_block *nb)
@ -895,6 +911,8 @@ __power_supply_register(struct device *parent,
cfg->fwnode ? to_of_node(cfg->fwnode) : cfg->of_node;
psy->supplied_to = cfg->supplied_to;
psy->num_supplicants = cfg->num_supplicants;
if (cfg->drv_data)
psy->free_pdd_on_release = cfg->free_drv_data;
}
rc = dev_set_name(dev, "%s", desc->name);
@ -1093,6 +1111,8 @@ void power_supply_unregister(struct power_supply *psy)
{
WARN_ON(atomic_dec_return(&psy->use_cnt));
psy->removing = true;
atomic_notifier_call_chain(&power_supply_notifier,
PSY_EVENT_PROP_REMOVED, psy);
cancel_work_sync(&psy->changed_work);
cancel_delayed_work_sync(&psy->deferred_register_work);
sysfs_remove_link(&psy->dev.kobj, "powers");

View file

@ -97,6 +97,122 @@ static const char * const power_supply_usbc_pr_text[] = {
static const char * const power_supply_typec_src_rp_text[] = {
"Rp-Default", "Rp-1.5A", "Rp-3A"
};
static char *charge_rate[] = {
"None", "Normal", "Weak", "Turbo", "Hyper"
};
static ssize_t power_supply_check_property(struct device *dev,
struct device_attribute *attr,
union power_supply_propval value) {
ssize_t ret = 0;
struct power_supply *psy = dev_get_drvdata(dev);
const ptrdiff_t off = attr - power_supply_attrs;
if (!psy ||!psy->desc) {
dev_err(dev, "no dev\n");
return -ENODEV;
}
if (off == POWER_SUPPLY_PROP_STATUS
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_status_text))) {
dev_err(dev, "power_supply_status_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_CHARGE_TYPE
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_charge_type_text))) {
dev_err(dev, "power_supply_charge_type_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_CHARGE_RATE
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(charge_rate))) {
dev_err(dev, "charge_rate, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_HEALTH
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_health_text))) {
dev_err(dev, "power_supply_health_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_TECHNOLOGY
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_technology_text))) {
dev_err(dev, "power_supply_technology_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_capacity_level_text))) {
dev_err(dev, "power_supply_capacity_level_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if ((off == POWER_SUPPLY_PROP_TYPE ||
off == POWER_SUPPLY_PROP_REAL_TYPE)
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_type_text))) {
dev_err(dev, "power_supply_type_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_SCOPE
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_scope_text))) {
dev_err(dev, "power_supply_scope_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_TYPEC_MODE
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_usbc_text))) {
dev_err(dev, "power_supply_usbc_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_TYPEC_POWER_ROLE
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_usbc_pr_text))) {
dev_err(dev, "power_supply_usbc_pr_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_TYPEC_SRC_RP
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_typec_src_rp_text))) {
dev_err(dev, "power_supply_typec_src_rp_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_DIE_HEALTH
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_health_text))) {
dev_err(dev, "power_supply_die_health_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_CONNECTOR_HEALTH
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_health_text))) {
dev_err(dev, "power_supply_connector_health_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off == POWER_SUPPLY_PROP_SKIN_HEALTH
&& (value.intval < 0 ||
value.intval > ARRAY_SIZE(power_supply_health_text))) {
dev_err(dev, "power_supply_skin_health_text, invaid intval %d\n",
value.intval);
goto check_failed;
} else if (off >= POWER_SUPPLY_PROP_MODEL_NAME
&& !value.strval) {
dev_err(dev, "power_supply_mode_name is null\n");
goto check_failed;
}
return ret;
check_failed:
if (psy->desc->name)
dev_err(dev, "psy : %s\n", psy->desc->name);
ret = -ENODATA;
return ret;
}
static ssize_t power_supply_show_usb_type(struct device *dev,
enum power_supply_usb_type *usb_types,
@ -158,6 +274,9 @@ static ssize_t power_supply_show_property(struct device *dev,
}
}
if (power_supply_check_property(dev, attr, value) < 0)
return ret;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
ret = sprintf(buf, "%s\n",
@ -167,6 +286,10 @@ static ssize_t power_supply_show_property(struct device *dev,
ret = sprintf(buf, "%s\n",
power_supply_charge_type_text[value.intval]);
break;
case POWER_SUPPLY_PROP_CHARGE_RATE:
ret = snprintf(buf, strlen(charge_rate[value.intval]) + 2,
"%s\n", charge_rate[value.intval]);
break;
case POWER_SUPPLY_PROP_HEALTH:
ret = sprintf(buf, "%s\n",
power_supply_health_text[value.intval]);
@ -309,6 +432,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(charge_empty),
POWER_SUPPLY_ATTR(charge_now),
POWER_SUPPLY_ATTR(charge_avg),
POWER_SUPPLY_ATTR(charge_rate),
POWER_SUPPLY_ATTR(charge_counter),
POWER_SUPPLY_ATTR(constant_charge_current),
POWER_SUPPLY_ATTR(constant_charge_current_max),
@ -374,6 +498,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(temp_cold),
POWER_SUPPLY_ATTR(temp_hot),
POWER_SUPPLY_ATTR(system_temp_level),
POWER_SUPPLY_ATTR(num_system_temp_levels),
POWER_SUPPLY_ATTR(resistance),
POWER_SUPPLY_ATTR(resistance_capacitive),
POWER_SUPPLY_ATTR(resistance_id),
@ -464,6 +589,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(comp_clamp_level),
POWER_SUPPLY_ATTR(adapter_cc_mode),
POWER_SUPPLY_ATTR(skin_health),
POWER_SUPPLY_ATTR(vbus_conflict),
POWER_SUPPLY_ATTR(aicl_done),
POWER_SUPPLY_ATTR(voltage_step),
POWER_SUPPLY_ATTR(apsd_rerun),
@ -484,6 +610,21 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(cc_toggle_enable),
POWER_SUPPLY_ATTR(fg_type),
POWER_SUPPLY_ATTR(charger_status),
POWER_SUPPLY_ATTR(internal_send),
POWER_SUPPLY_ATTR(internal_receive),
POWER_SUPPLY_ATTR(external),
POWER_SUPPLY_ATTR(current_flow),
POWER_SUPPLY_ATTR(max_input_current),
POWER_SUPPLY_ATTR(max_output_current),
POWER_SUPPLY_ATTR(external_present),
POWER_SUPPLY_ATTR(power_required),
POWER_SUPPLY_ATTR(power_available),
POWER_SUPPLY_ATTR(power_source),
POWER_SUPPLY_ATTR(max_output_voltage),
POWER_SUPPLY_ATTR(output_voltage),
POWER_SUPPLY_ATTR(max_input_voltage),
POWER_SUPPLY_ATTR(input_voltage),
POWER_SUPPLY_ATTR(age),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */

View file

@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SMB1360_CHARGER_FG) += smb1360-charger-fg.o
obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o
obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o qpnp-smbcharger-mmi.o pmic-voter.o storm-watch.o schgm-flash.o
obj-$(CONFIG_SMB1390_CHARGE_PUMP_PSY) += smb1390-charger-psy.o pmic-voter.o
obj-$(CONFIG_SMB1355_SLAVE_CHARGER) += smb1355-charger.o pmic-voter.o
obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o

View file

@ -1316,7 +1316,7 @@ static int usb_icl_vote_callback(struct votable *votable, void *data,
}
/* rerun AICL if new ICL is above settled ICL */
if (icl_ua > pval.intval)
if (icl_ua != INT_MAX && icl_ua > pval.intval)
rerun_aicl = true;
if (rerun_aicl && (chip->wa_flags & AICL_RERUN_WA_BIT)) {

View file

@ -426,6 +426,7 @@ int vote(struct votable *votable, const char *client_str, bool enabled, int val)
client_id = get_client_id(votable, client_str);
if (client_id < 0) {
rc = client_id;
pr_err("%s client id not found for %s\n", __func__, client_str);
goto out;
}
@ -494,7 +495,11 @@ int vote(struct votable *votable, const char *client_str, bool enabled, int val)
get_client_str(votable, effective_id));
}
#ifdef QCOM_BASE
votable->voted_on = true;
#else
votable->voted_on = (rc >= 0);
#endif
out:
unlock_votable(votable);
return rc;

View file

@ -364,10 +364,10 @@ int qg_get_battery_temp(struct qpnp_qg *chip, int *temp)
{
int rc = 0;
// if (chip->battery_missing) {
if (chip->battery_missing) {
*temp = 250;
return 0;
// }
}
rc = iio_read_channel_processed(chip->batt_therm_chan, temp);
if (rc < 0) {

View file

@ -36,8 +36,9 @@
#include "qg-soc.h"
#include "qg-battery-profile.h"
#include "qg-defs.h"
#include <dt-bindings/iio/qcom,spmi-vadc.h>
static int qg_debug_mask;
static int qg_debug_mask = 0xff;
static int qg_esr_mod_count = 30;
static ssize_t esr_mod_count_show(struct device *dev, struct device_attribute
@ -2215,6 +2216,9 @@ static int qg_psy_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW:
pval->intval = chip->qg_charge_counter;
break;
case POWER_SUPPLY_PROP_CHARGE_NOW:
pval->intval = chip->cl->init_cap_uah;
break;
case POWER_SUPPLY_PROP_CHARGE_FULL:
if (!chip->dt.cl_disable && chip->dt.cl_feedback_on)
@ -2289,7 +2293,12 @@ static int qg_psy_get_property(struct power_supply *psy,
break;
}
return rc;
if (rc < 0) {
pr_err("Failed to get property: %d\n", rc);
return rc;
}
return 0;
}
static int qg_property_is_writeable(struct power_supply *psy,
@ -2333,6 +2342,7 @@ static enum power_supply_property qg_psy_props[] = {
POWER_SUPPLY_PROP_BATT_PROFILE_VERSION,
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_CYCLE_COUNTS,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
@ -4706,8 +4716,11 @@ static int qpnp_qg_probe(struct platform_device *pdev)
chip->batt_id_chan = NULL;
return rc;
}
#ifdef CONFIG_BAT_NTC_10K
chip->batt_therm_chan = iio_channel_get(&pdev->dev, "batt-therm-ntc-10k");
#else
chip->batt_therm_chan = iio_channel_get(&pdev->dev, "batt-therm");
#endif
if (IS_ERR(chip->batt_therm_chan)) {
rc = PTR_ERR(chip->batt_therm_chan);
if (rc != -EPROBE_DEFER)
@ -4717,6 +4730,8 @@ static int qpnp_qg_probe(struct platform_device *pdev)
}
chip->dev = &pdev->dev;
qg_debug_mask |= QG_DEBUG_PON | QG_DEBUG_STATUS
| QG_DEBUG_IRQ | QG_DEBUG_PM | QG_DEBUG_ESR;
chip->debug_mask = &qg_debug_mask;
platform_set_drvdata(pdev, chip);
INIT_WORK(&chip->udata_work, process_udata_work);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include <linux/device.h>
#include <linux/power_supply.h>
#include <linux/pmic-voter.h>
#include "smb5-lib.h"
#include "smb5-reg.h"
#include "storm-watch.h"
#include <linux/moduleparam.h>
static int set_eb_param(const char *val, const struct kernel_param *kp)
{
int prev_attach_stop_soc;
int rv;
prev_attach_stop_soc = eb_attach_stop_soc;
rv = param_set_int(val, kp);
if (rv)
return rv;
if (mmi_chip) {
mmi_chip->mmi.update_eb_params++;
vote(mmi_chip->awake_votable, HEARTBEAT_VOTER, true, true);
mmi_chip->mmi.check_ebsrc_vl = (eb_attach_stop_soc !=
prev_attach_stop_soc);
cancel_delayed_work(&mmi_chip->mmi.heartbeat_work);
schedule_delayed_work(&mmi_chip->mmi.heartbeat_work,
msecs_to_jiffies(HEARTBEAT_EB_MS));
}
return 0;
}
static struct kernel_param_ops eb_ops = {
.set = set_eb_param,
.get = param_get_int,
};
int eb_rechrg_start_soc = 70;
module_param_cb(eb_rechrg_start_soc, &eb_ops, &eb_rechrg_start_soc, 0644);
int eb_rechrg_stop_soc = 80;
module_param_cb(eb_rechrg_stop_soc, &eb_ops, &eb_rechrg_stop_soc, 0644);
int eb_attach_start_soc = 100;
module_param_cb(eb_attach_start_soc, &eb_ops, &eb_attach_start_soc, 0644);
int eb_attach_stop_soc = 100;
module_param_cb(eb_attach_stop_soc, &eb_ops, &eb_attach_stop_soc, 0644);
int eb_low_start_soc = 16;
module_param_cb(eb_low_start_soc, &eb_ops, &eb_low_start_soc, 0644);
int eb_low_stop_soc = 100;
module_param_cb(eb_low_stop_soc, &eb_ops, &eb_low_stop_soc, 0644);
int eb_on_sw = 1;
module_param_cb(eb_on_sw, &eb_ops, &eb_on_sw, 0644);

File diff suppressed because it is too large Load diff

View file

@ -5,18 +5,24 @@
#ifndef __SMB5_CHARGER_H
#define __SMB5_CHARGER_H
#include <linux/gpio.h>
#include <linux/alarmtimer.h>
#include <linux/ktime.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/reboot.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/consumer.h>
#include <linux/extcon-provider.h>
#include <linux/usb/typec.h>
#include "storm-watch.h"
#include "battery.h"
#include <linux/alarmtimer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/power_supply.h>
#include <linux/usb/usbpd.h>
enum print_reason {
PR_INTERRUPT = BIT(0),
@ -25,6 +31,7 @@ enum print_reason {
PR_PARALLEL = BIT(3),
PR_OTG = BIT(4),
PR_WLS = BIT(5),
PR_MOTO = BIT(7),
};
#define DEFAULT_VOTER "DEFAULT_VOTER"
@ -47,6 +54,7 @@ enum print_reason {
#define CTM_VOTER "CTM_VOTER"
#define SW_QC3_VOTER "SW_QC3_VOTER"
#define AICL_RERUN_VOTER "AICL_RERUN_VOTER"
#define ICL_LIMIT_VOTER "ICL_LIMIT_VOTER"
#define SW_ICL_MAX_VOTER "SW_ICL_MAX_VOTER"
#define PL_QNOVO_VOTER "PL_QNOVO_VOTER"
#define QNOVO_VOTER "QNOVO_VOTER"
@ -85,6 +93,11 @@ enum print_reason {
#define BOOST_BACK_STORM_COUNT 3
#define WEAK_CHG_STORM_COUNT 8
#define HEARTBEAT_VOTER "HEARTBEAT_VOTER"
#define EB_VOTER "EB_VOTER"
#define WIRELESS_VOTER "WIRELESS_VOTER"
#define DEMO_VOTER "DEMO_VOTER"
#define MMI_VOTER "MMI_VOTER"
#define VBAT_TO_VRAW_ADC(v) div_u64((u64)v * 1000000UL, 194637UL)
@ -259,6 +272,10 @@ struct smb_irq_info {
static const unsigned int smblib_extcon_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
#ifdef CONFIG_MODS_NEW_SW_ARCH
EXTCON_USB_CC,
EXTCON_USB_SPEED,
#endif
EXTCON_NONE,
};
@ -371,6 +388,123 @@ struct smb_iio {
struct iio_channel *die_temp_chan;
struct iio_channel *skin_temp_chan;
struct iio_channel *smb_temp_chan;
struct iio_channel *dcin_v_chan;
};
struct mmi_temp_zone {
int temp_c;
int norm_mv;
int fcc_max_ma;
int fcc_norm_ma;
};
#define MAX_NUM_STEPS 10
enum mmi_temp_zones {
ZONE_FIRST = 0,
/* states 0-9 are reserved for zones */
ZONE_LAST = MAX_NUM_STEPS + ZONE_FIRST - 1,
ZONE_HOT,
ZONE_COLD,
ZONE_NONE = 0xFF,
};
enum mmi_chrg_step {
STEP_MAX,
STEP_NORM,
STEP_EB,
STEP_FULL,
STEP_FLOAT,
STEP_DEMO,
STEP_STOP,
STEP_NONE = 0xFF,
};
enum ebchg_state {
EB_DISCONN = POWER_SUPPLY_EXTERN_STATE_DIS,
EB_SINK = POWER_SUPPLY_EXTERN_STATE_SINK,
EB_SRC = POWER_SUPPLY_EXTERN_STATE_SRC,
EB_OFF = POWER_SUPPLY_EXTERN_STATE_OFF,
};
enum charging_limit_modes {
CHARGING_LIMIT_OFF,
CHARGING_LIMIT_RUN,
CHARGING_LIMIT_UNKNOWN,
};
enum turbo_ebsrc {
TURBO_EBSRC_UNKNOWN,
TURBO_EBSRC_NOT_SUPPORTED,
TURBO_EBSRC_VALID,
};
struct mmi_params {
bool factory_mode;
int demo_mode;
struct gpio ebchg_gpio;
struct notifier_block smb_reboot;
/* thermal mitigation */
int dc_system_temp_level;
int dc_thermal_levels;
int *dc_thermal_mitigation;
int usb_system_temp_level;
int usb_thermal_levels;
int *usb_thermal_mitigation;
bool factory_kill_armed;
/* Charge Profile */
int num_temp_zones;
struct mmi_temp_zone *temp_zones;
enum mmi_temp_zones pres_temp_zone;
enum mmi_chrg_step pres_chrg_step;
int chrg_taper_cnt;
int dc_ebmax_current_ma;
int dc_ebmax_current_ma_default;
int dc_eff_current_ma;
/* external battery params */
const char *eb_batt_psy_name;
const char *eb_pwr_psy_name;
const char *extrn_fg_psy_name;
enum ebchg_state ebchg_state;
bool force_eb_chrg;
int update_eb_params;
int charger_debounce_cnt;
int cl_ebchg;
int cl_ebsrc;
int vl_ebsrc;
int vo_ebsrc;
int vi_ebsrc;
bool eb_rechrg;
bool usbeb_present;
bool wls_present;
int temp_state;
int chrg_iterm;
atomic_t hb_ready;
struct alarm heartbeat_alarm;
struct delayed_work heartbeat_work;
struct power_supply *wls_psy;
struct power_supply *usbeb_psy;
struct pinctrl *smb_pinctrl;
struct wakeup_source smblib_mmi_hb_wake_source;
bool apsd_done;
int charger_rate;
bool hvdcp3_con;
struct notifier_block mmi_psy_notifier;
bool init_done;
int vbus_inc_cnt;
bool enable_charging_limit;
bool is_factory_image;
enum charging_limit_modes charging_limit_modes;
int upper_limit_capacity;
int lower_limit_capacity;
int base_fv_mv;
int vfloat_comp_mv;
enum turbo_ebsrc turbo_pwr_ebsrc;
bool check_ebsrc_vl;
int batt_health;
int max_chrg_temp;
int is_otg_enable;
bool force_chg_suspend;
};
struct smb_charger {
@ -398,7 +532,7 @@ struct smb_charger {
struct mutex adc_lock;
struct mutex dpdm_lock;
struct mutex typec_lock;
struct mutex otg_lock;
/* power supplies */
struct power_supply *batt_psy;
struct power_supply *usb_psy;
@ -437,6 +571,7 @@ struct smb_charger {
struct votable *fcc_main_votable;
struct votable *fv_votable;
struct votable *usb_icl_votable;
struct votable *dc_icl_votable;
struct votable *awake_votable;
struct votable *pl_disable_votable;
struct votable *chg_disable_votable;
@ -509,6 +644,10 @@ struct smb_charger {
int dcp_icl_ua;
int fake_capacity;
int fake_batt_status;
bool extrn_fg;
bool dc_unsupported;
bool wireless_unsupported;
bool usbeb_unsupported;
bool step_chg_enabled;
bool sw_jeita_enabled;
bool jeita_arb_enable;
@ -617,6 +756,19 @@ struct smb_charger {
int dcin_uv_count;
ktime_t dcin_uv_last_time;
int last_wls_vout;
/* mmi based params */
/* Place at end of struct smb_charger as it grows */
struct mmi_params mmi;
void *ipc_log;
void *ipc_log_reg;
struct usbpd *pd;
int pd_contract_uv;
struct delayed_work pd_contract_work;
bool external_vbus;
bool support_mods;
bool suspended;
u32 source_current_ma;
bool reverse_boost;
};
int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
@ -657,6 +809,7 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev);
irqreturn_t default_irq_handler(int irq, void *data);
irqreturn_t smb_en_irq_handler(int irq, void *data);
irqreturn_t smblib_handle_usbin_collapse(int irq, void *data);
irqreturn_t chg_state_change_irq_handler(int irq, void *data);
irqreturn_t batt_temp_changed_irq_handler(int irq, void *data);
irqreturn_t batt_psy_changed_irq_handler(int irq, void *data);
@ -676,12 +829,17 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data);
irqreturn_t temp_change_irq_handler(int irq, void *data);
irqreturn_t usbin_ov_irq_handler(int irq, void *data);
irqreturn_t sdam_sts_change_irq_handler(int irq, void *data);
irqreturn_t dcin_uv_irq_handler(int irq, void *data);
int smblib_get_prop_input_suspend(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_present(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_capacity(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_age(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_status(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
@ -841,4 +999,29 @@ int smblib_get_qc3_main_icl_offset(struct smb_charger *chg, int *offset_ua);
int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
int smblib_get_prop_dc_system_temp_level(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_dc_system_temp_level(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_get_prop_usb_system_temp_level(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_usb_system_temp_level(struct smb_charger *chg,
const union power_supply_propval *val);
void mmi_init(struct smb_charger *chg);
void mmi_deinit(struct smb_charger *chg);
void mmi_chrg_rate_check(struct smb_charger *chip);
#define HEARTBEAT_EB_MS 1000
extern struct smb_charger *mmi_chip;
extern int eb_rechrg_start_soc;
extern int eb_rechrg_stop_soc;
extern int eb_attach_start_soc;
extern int eb_attach_stop_soc;
extern int eb_low_start_soc;
extern int eb_low_stop_soc;
extern int eb_on_sw;
#define DEFAULT_SOURCE_CURRENT_MA 1500
#endif /* __SMB5_CHARGER_H */

View file

@ -70,6 +70,9 @@ enum {
#define SOC_BASED_RECHG_BIT GENMASK(2, 1)
#define CHARGER_INHIBIT_BIT BIT(0)
#define CHGR_PRE_CHARGE_CURRENT_CFG_REG (CHGR_BASE + 0x60)
#define CHGR_PRE_CHARGE_CURRENT_SETTING_MASK GENMASK(2, 0)
#define CHGR_FAST_CHARGE_CURRENT_CFG_REG (CHGR_BASE + 0x61)
#define CHGR_ADC_ITERM_UP_THD_MSB_REG (CHGR_BASE + 0x67)
@ -275,6 +278,19 @@ enum {
HVDCP_PULSE_COUNT_MAX_QC2_INVALID = 0xC0
};
#define USBIN_ADAPTER_ALLOW_CFG_REG (USBIN_BASE + 0x60)
enum {
USBIN_ADAPTER_ALLOW_5V = 0,
USBIN_ADAPTER_ALLOW_9V = 2,
USBIN_ADAPTER_ALLOW_5V_OR_9V = 3,
USBIN_ADAPTER_ALLOW_12V = 4,
USBIN_ADAPTER_ALLOW_5V_OR_12V = 5,
USBIN_ADAPTER_ALLOW_9V_TO_12V = 6,
USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V = 7,
USBIN_ADAPTER_ALLOW_5V_TO_9V = 8,
USBIN_ADAPTER_ALLOW_5V_TO_12V = 12,
};
#define USBIN_OPTIONS_1_CFG_REG (USBIN_BASE + 0x62)
#define HVDCP_AUTH_ALG_EN_CFG_BIT BIT(6)
#define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT BIT(5)
@ -292,6 +308,8 @@ enum {
#define ICL_OVERRIDE_AFTER_APSD_BIT BIT(4)
#define USBIN_AICL_STEP_TIMING_SEL_MASK GENMASK(3, 2)
#define USBIN_IN_COLLAPSE_GF_SEL_MASK GENMASK(1, 0)
#define USBIN_IN_COLLAPSE_GF_30MS 0x2
#define USBIN_IN_COLLAPSE_GF_30US 0x3
#define USBIN_ICL_OPTIONS_REG (USBIN_BASE + 0x66)
#define CFG_USB3P0_SEL_BIT BIT(2)
@ -302,6 +320,7 @@ enum {
#define USBIN_AICL_OPTIONS_CFG_REG (USBIN_BASE + 0x80)
#define SUSPEND_ON_COLLAPSE_USBIN_BIT BIT(7)
#define USBIN_AICL_HDC_EN_BIT BIT(6)
#define USBIN_AICL_PERIODIC_RERUN_EN_BIT BIT(4)
#define USBIN_AICL_ADC_EN_BIT BIT(3)
#define USBIN_AICL_EN_BIT BIT(2)
@ -329,7 +348,19 @@ enum {
#define DCIN_LOAD_CFG_REG (DCIN_BASE + 0x65)
#define INPUT_MISS_POLL_EN_BIT BIT(5)
#define DCIN_ADAPTER_ALLOW_CFG_REG (DCIN_BASE + 0x60)
#define DCIN_ADAPTER_ALLOW_MASK GENMASK(3, 0)
enum {
DCIN_ADAPTER_ALLOW_5V = 0,
DCIN_ADAPTER_ALLOW_9V = 2,
DCIN_ADAPTER_ALLOW_5V_OR_9V = 3,
DCIN_ADAPTER_ALLOW_12V = 4,
DCIN_ADAPTER_ALLOW_5V_OR_12V = 5,
DCIN_ADAPTER_ALLOW_9V_TO_12V = 6,
DCIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V = 7,
DCIN_ADAPTER_ALLOW_5V_TO_9V = 8,
DCIN_ADAPTER_ALLOW_5V_TO_12V = 12,
};
/********************************
* TYPEC Peripheral Registers *
********************************/

View file

@ -234,6 +234,7 @@ static void *usbpd_ipc_log;
#define VDM_BUSY_TIME 50
#define VCONN_ON_TIME 100
#define SINK_TX_TIME 16
#define APSD_RECHECK_TIME 5000
/* tPSHardReset + tSafe0V */
#define SNK_HARD_RESET_VBUS_OFF_TIME (35 + 650)
@ -305,6 +306,7 @@ static void *usbpd_ipc_log;
#define PD_SRC_PDO_FIXED_PEAK_CURR(pdo) (((pdo) >> 20) & 3)
#define PD_SRC_PDO_FIXED_VOLTAGE(pdo) (((pdo) >> 10) & 0x3FF)
#define PD_SRC_PDO_FIXED_MAX_CURR(pdo) ((pdo) & 0x3FF)
#define PD_SRC_PDO_FIXED_CURRENT_MASK 0x3FF
#define PD_SRC_PDO_VAR_BATT_MAX_VOLT(pdo) (((pdo) >> 20) & 0x3FF)
#define PD_SRC_PDO_VAR_BATT_MIN_VOLT(pdo) (((pdo) >> 10) & 0x3FF)
@ -353,7 +355,7 @@ static void *usbpd_ipc_log;
#define PD_MIN_SINK_CURRENT 900
static const u32 default_src_caps[] = { 0x36019096 }; /* VSafe5V @ 1.5A */
static u32 default_src_caps[] = { 0x36019096 }; /* VSafe5V @ 1.5A */
static const u32 default_snk_caps[] = { 0x2601912C }; /* VSafe5V @ 3A */
struct vdm_tx {
@ -493,6 +495,10 @@ static const unsigned int usbpd_extcon_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
EXTCON_DISP_DP,
#ifdef CONFIG_MODS_NEW_SW_ARCH
EXTCON_USB_CC,
EXTCON_USB_SPEED,
#endif
EXTCON_NONE,
};
@ -550,6 +556,12 @@ static inline void start_usb_host(struct usbpd *pd, bool ss)
union extcon_property_value val;
int ret = 0;
#ifdef CONFIG_MODS_NEW_SW_ARCH
extcon_set_cable_state_(pd->extcon, EXTCON_USB_CC,
cc == ORIENTATION_CC2);
extcon_set_cable_state_(pd->extcon, EXTCON_USB_SPEED, ss);
#endif
val.intval = (cc == ORIENTATION_CC2);
extcon_set_property(pd->extcon, EXTCON_USB_HOST,
EXTCON_PROP_USB_TYPEC_POLARITY, val);
@ -578,6 +590,12 @@ static inline void start_usb_peripheral(struct usbpd *pd)
enum plug_orientation cc = usbpd_get_plug_orientation(pd);
union extcon_property_value val;
#ifdef CONFIG_MODS_NEW_SW_ARCH
extcon_set_cable_state_(pd->extcon, EXTCON_USB_CC,
cc == ORIENTATION_CC2);
extcon_set_cable_state_(pd->extcon, EXTCON_USB_SPEED, 1);
#endif
val.intval = (cc == ORIENTATION_CC2);
extcon_set_property(pd->extcon, EXTCON_USB,
EXTCON_PROP_USB_TYPEC_POLARITY, val);
@ -887,10 +905,38 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos, int uv, int ua)
pd->requested_current = curr;
pd->requested_pdo = pdo_pos;
usbpd_warn(&pd->dev, "select_pdo: PDO:%d, %d uV, %d uA, type %d\n",
pdo_pos, uv, ua, type);
return 0;
}
static int pd_get_pdo(struct usbpd *pd, int pdo_pos, int *uv_max, int *uv_min, int *ua)
{
u8 type;
u32 pdo = pd->received_pdos[pdo_pos - 1];
if (0 == pdo)
return -ENOTSUPP;
type = PD_SRC_PDO_TYPE(pdo);
if (type == PD_SRC_PDO_TYPE_FIXED) {
*ua = PD_SRC_PDO_FIXED_MAX_CURR(pdo) * 10;
*uv_max = *uv_min = PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 * 1000;
} else if (type == PD_SRC_PDO_TYPE_AUGMENTED) {
*uv_max = PD_APDO_MAX_VOLT(pdo) * 100000;
*uv_min = PD_APDO_MIN_VOLT(pdo) * 100000;
*ua = PD_APDO_MAX_CURR(pdo) * 50000;
} else {
usbpd_err(&pd->dev, "Only Fixed or Programmable PDOs supported\n");
return -ENOTSUPP;
}
usbpd_warn(&pd->dev, "pdo_pos = %d, type= %d, uv_max = %d, uv_min= %d, *ua = %d\n",
pdo_pos, type, *uv_max, *uv_min, *ua);
return 0;
}
static int pd_eval_src_caps(struct usbpd *pd)
{
int i;
@ -1242,6 +1288,7 @@ static enum hrtimer_restart pd_timeout(struct hrtimer *timer)
{
struct usbpd *pd = container_of(timer, struct usbpd, timer);
usbpd_dbg(&pd->dev, "timeout");
queue_work(pd->wq, &pd->sm_work);
return HRTIMER_NORESTART;
@ -4269,9 +4316,228 @@ static ssize_t pdo_n_show(struct device *dev, struct device_attribute *attr,
return -EINVAL;
}
int usbpd_get_current_dr(struct usbpd *pd)
{
if (!pd)
return -EINVAL;
return (int)pd->current_dr;
}
EXPORT_SYMBOL(usbpd_get_current_dr);
int usbpd_select_pdo_match(struct usbpd *pd)
{
int uv_diff = 0, max_uv_diff = 0, pdo = 0;
int pdo_max_uv = 0, pdo_min_uv = 0, pdo_ua = 0;
int uv_in, i;
int ret;
union power_supply_propval val;
if (!pd)
return -EINVAL;
mutex_lock(&pd->swap_lock);
if (pd->current_pr == PR_SRC) {
usbpd_err(&pd->dev, "select_pdo:not support in source mode\n");
ret = -ENOTSUPP;
goto out;
}
/* Only allowed if we are already in explicit sink contract */
if (pd->current_state != PE_SNK_READY || !is_sink_tx_ok(pd)) {
usbpd_err(&pd->dev, "select_pdo: Cannot select new PDO yet\n");
ret = -EBUSY;
goto out;
}
/* Check the Max Input Voltage from USBPSY */
power_supply_get_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_VOLTAGE_MAX, &val);
uv_in = val.intval;
/* start with 5 V */
max_uv_diff = 5000000;
for (i = 1; i < 8; i++) {
if (!pd_get_pdo(pd, i, &pdo_max_uv, &pdo_min_uv, &pdo_ua)) {
if (pdo_max_uv <= uv_in) {
uv_diff = uv_in - pdo_max_uv;
if (uv_diff < max_uv_diff) {
max_uv_diff = uv_diff;
pdo = i;
}
}
}
}
if (pdo < 1 || pdo > 7) {
usbpd_err(&pd->dev, "select_pdo: invalid PDO:%d\n", pdo);
ret = -EINVAL;
goto out;
}
pd_get_pdo(pd, pdo, &pdo_max_uv, &pdo_min_uv, &pdo_ua);
ret = pd_select_pdo(pd, pdo, pdo_max_uv, pdo_ua);
if (ret)
goto out;
else
ret = pdo_max_uv;
reinit_completion(&pd->is_ready);
pd->send_request = true;
kick_sm(pd, 0);
/* wait for operation to complete */
if (!wait_for_completion_timeout(&pd->is_ready,
msecs_to_jiffies(1000))) {
usbpd_err(&pd->dev, "select_pdo: request timed out\n");
ret = -ETIMEDOUT;
goto out;
}
/* determine if request was accepted/rejected */
if (pd->selected_pdo != pd->requested_pdo ||
pd->current_voltage != pd->requested_voltage) {
usbpd_err(&pd->dev, "select_pdo: request rejected\n");
ret = -EINVAL;
}
out:
pd->send_request = false;
mutex_unlock(&pd->swap_lock);
return ret;
}
EXPORT_SYMBOL(usbpd_select_pdo_match);
int usbpd_get_pdo_info(struct usbpd *pd, struct usbpd_pdo_info *pdo_info)
{
int pdo = 0;
int i;
int ret = 0;
if (!pd || !pdo_info)
return -EINVAL;
mutex_lock(&pd->swap_lock);
if (pd->current_pr == PR_SRC) {
usbpd_err(&pd->dev, "select_pdo:not support in source mode\n");
ret = -ENOTSUPP;
goto out;
}
usbpd_err(&pd->dev, "select pdo info ,pd->current_state %d\n", pd->current_state);
if (!is_sink_tx_ok(pd))
usbpd_err(&pd->dev, "select pdo info , !is_sink_tx_ok\n");
/* Only allowed if we are already in explicit sink contract */
if (pd->current_state != PE_SNK_READY || !is_sink_tx_ok(pd)) {
usbpd_err(&pd->dev, "select_pdo_info: Cannot select new PDO yet\n");
ret = -EBUSY;
goto out;
}
for (i = 0; i < 7; i++) {
pdo = pd->received_pdos[i];
if (pdo == 0)
break;
pdo_info[i].pdo_pos = i + 1;
pdo_info[i].type = PD_SRC_PDO_TYPE(pdo);
if (pdo_info[i].type == PD_SRC_PDO_TYPE_FIXED) {
pdo_info[i].ua = PD_SRC_PDO_FIXED_MAX_CURR(pdo) * 10;
pdo_info[i].uv_max = PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 * 1000;
pdo_info[i].uv_min = PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 * 1000;
printk(KERN_INFO "pdo %d, Fixed supply\n"
"Voltage:%d (uV)\n"
"Max Current:%d (uA)\n",
pdo_info[i].pdo_pos,
pdo_info[i].uv_max,
pdo_info[i].ua);
} else if (pdo_info[i].type == PD_SRC_PDO_TYPE_AUGMENTED) {
pdo_info[i].uv_max = PD_APDO_MAX_VOLT(pdo) * 100000;
pdo_info[i].uv_min = PD_APDO_MIN_VOLT(pdo) * 100000;
pdo_info[i].ua = PD_APDO_MAX_CURR(pdo) * 50000;
printk(KERN_INFO "pdo %d, Programmable Power supply\n"
"Voltage:%d (uV)\n"
"Max Current:%d (uA)\n",
pdo_info[i].pdo_pos,
pdo_info[i].uv_max,
pdo_info[i].ua);
} else
usbpd_err(&pd->dev, "Only get Fixed or Programmable PDOs supported\n");
}
out:
mutex_unlock(&pd->swap_lock);
return ret;
}
EXPORT_SYMBOL(usbpd_get_pdo_info);
int usbpd_select_pdo(struct usbpd *pd, int pdo_pos, int uv, int ua)
{
int ret;
if (!pd)
return -EINVAL;
mutex_lock(&pd->swap_lock);
if (pd->current_pr == PR_SRC) {
usbpd_err(&pd->dev, "select_pdo:not support in source mode\n");
ret = -ENOTSUPP;
goto out;
}
/* Only allowed if we are already in explicit sink contract */
if (pd->current_state != PE_SNK_READY || !is_sink_tx_ok(pd)) {
usbpd_err(&pd->dev, "select_pdo: Cannot select new PDO yet\n");
ret = -EBUSY;
goto out;
}
if (pdo_pos < 1 || pdo_pos > 7) {
usbpd_err(&pd->dev, "select_pdo: invalid PDO:%d\n", pdo_pos);
ret = -EINVAL;
goto out;
}
ret = pd_select_pdo(pd, pdo_pos, uv, ua);
if (ret)
goto out;
reinit_completion(&pd->is_ready);
pd->send_request = true;
kick_sm(pd, 0);
/* wait for operation to complete */
if (!wait_for_completion_timeout(&pd->is_ready,
msecs_to_jiffies(1000))) {
usbpd_err(&pd->dev, "select_pdo: request timed out\n");
ret = -ETIMEDOUT;
goto out;
}
/* determine if request was accepted/rejected */
if (pd->selected_pdo != pd->requested_pdo ||
pd->current_voltage != pd->requested_voltage) {
usbpd_err(&pd->dev, "select_pdo: request rejected\n");
ret = -EINVAL;
}
out:
pd->send_request = false;
mutex_unlock(&pd->swap_lock);
return ret;
}
EXPORT_SYMBOL(usbpd_select_pdo);
static ssize_t select_pdo_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
#ifdef QCOM_BASE
struct usbpd *pd = dev_get_drvdata(dev);
int src_cap_id;
int pdo, uv = 0, ua = 0;
@ -4333,6 +4599,9 @@ out:
pd->send_request = false;
mutex_unlock(&pd->swap_lock);
return ret ? ret : size;
#else
return size;
#endif
}
static ssize_t select_pdo_show(struct device *dev,
@ -4458,6 +4727,7 @@ out:
static ssize_t get_src_cap_ext_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
#ifdef QCOM_BASE
int i, ret, len = 0;
struct usbpd *pd = dev_get_drvdata(dev);
@ -4475,6 +4745,11 @@ static ssize_t get_src_cap_ext_show(struct device *dev,
len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
return len;
#else
struct usbpd *pd = dev_get_drvdata(dev);
usbpd_warn(&pd->dev, "%s don't get src cap ext\n", __func__);
return -EINVAL;
#endif
}
static DEVICE_ATTR_RO(get_src_cap_ext);
@ -4707,6 +4982,7 @@ struct usbpd *usbpd_create(struct device *parent)
int ret;
struct usbpd *pd;
union power_supply_propval val = {0};
u32 source_current = 0;
pd = kzalloc(sizeof(*pd), GFP_KERNEL);
if (!pd)
@ -4837,6 +5113,20 @@ struct usbpd *usbpd_create(struct device *parent)
if (device_property_read_bool(parent, "qcom,pd-20-source-only"))
pd->pd20_source_only = true;
device_property_read_u32(parent,
"qcom,source-current",
&source_current);
if (source_current) {
usbpd_dbg(&pd->dev, "Override default src current with %d\n",
source_current);
source_current = (source_current / 10) &
PD_SRC_PDO_FIXED_CURRENT_MASK;
default_src_caps[0] = (*default_src_caps &
(~PD_SRC_PDO_FIXED_CURRENT_MASK)) |
source_current;
}
/*
* Register a Type-C class instance (/sys/class/typec/portX).
* Note this is different than the /sys/class/usbpd/ created above.

View file

@ -74,7 +74,7 @@
#define PD_MSG_HDR_REV(hdr) (((hdr) >> 6) & 3)
/* timers */
#define RECEIVER_RESPONSE_TIME 15 /* tReceiverResponse */
#define RECEIVER_RESPONSE_TIME 150 /* tReceiverResponse */
#define HARD_RESET_COMPLETE_TIME 5 /* tHardResetComplete */
struct usb_pdphy {

View file

@ -191,6 +191,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_CHARGE_EMPTY,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CHARGE_AVG,
POWER_SUPPLY_PROP_CHARGE_RATE,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
@ -256,6 +257,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_COLD_TEMP,
POWER_SUPPLY_PROP_HOT_TEMP,
POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
POWER_SUPPLY_PROP_NUM_SYSTEM_TEMP_LEVELS,
POWER_SUPPLY_PROP_RESISTANCE,
POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE,
POWER_SUPPLY_PROP_RESISTANCE_ID, /* in Ohms */
@ -346,6 +348,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_COMP_CLAMP_LEVEL,
POWER_SUPPLY_PROP_ADAPTER_CC_MODE,
POWER_SUPPLY_PROP_SKIN_HEALTH,
POWER_SUPPLY_PROP_VBUS_CONFLICT,
POWER_SUPPLY_PROP_AICL_DONE,
POWER_SUPPLY_PROP_VOLTAGE_STEP,
POWER_SUPPLY_PROP_APSD_RERUN,
@ -366,6 +369,21 @@ enum power_supply_property {
POWER_SUPPLY_PROP_CC_TOGGLE_ENABLE,
POWER_SUPPLY_PROP_FG_TYPE,
POWER_SUPPLY_PROP_CHARGER_STATUS,
POWER_SUPPLY_PROP_PTP_INTERNAL_SEND,
POWER_SUPPLY_PROP_PTP_INTERNAL_RECEIVE,
POWER_SUPPLY_PROP_PTP_EXTERNAL,
POWER_SUPPLY_PROP_PTP_CURRENT_FLOW,
POWER_SUPPLY_PROP_PTP_MAX_INPUT_CURRENT,
POWER_SUPPLY_PROP_PTP_MAX_OUTPUT_CURRENT,
POWER_SUPPLY_PROP_PTP_EXTERNAL_PRESENT,
POWER_SUPPLY_PROP_PTP_POWER_REQUIRED,
POWER_SUPPLY_PROP_PTP_POWER_AVAILABLE,
POWER_SUPPLY_PROP_PTP_POWER_SOURCE,
POWER_SUPPLY_PROP_PTP_MAX_OUTPUT_VOLTAGE,
POWER_SUPPLY_PROP_PTP_OUTPUT_VOLTAGE,
POWER_SUPPLY_PROP_PTP_MAX_INPUT_VOLTAGE,
POWER_SUPPLY_PROP_PTP_INPUT_VOLTAGE,
POWER_SUPPLY_PROP_AGE,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
@ -405,6 +423,7 @@ enum power_supply_type {
POWER_SUPPLY_TYPE_UFP, /* Type-C UFP */
POWER_SUPPLY_TYPE_DFP, /* Type-C DFP */
POWER_SUPPLY_TYPE_CHARGE_PUMP, /* Charge Pump */
POWER_SUPPLY_TYPE_PTP, /* Greybus power transfer protocol */
};
enum power_supply_usb_type {
@ -453,6 +472,8 @@ enum power_supply_typec_power_role {
enum power_supply_notifier_events {
PSY_EVENT_PROP_CHANGED,
PSY_EVENT_PROP_ADDED,
PSY_EVENT_PROP_REMOVED,
};
union power_supply_propval {
@ -461,6 +482,81 @@ union power_supply_propval {
int64_t int64val;
};
enum {
POWER_SUPPLY_CHARGE_RATE_NONE = 0,
POWER_SUPPLY_CHARGE_RATE_NORMAL,
POWER_SUPPLY_CHARGE_RATE_WEAK,
POWER_SUPPLY_CHARGE_RATE_TURBO,
POWER_SUPPLY_CHARGE_RATE_HYPER,
};
enum {
POWER_SUPPLY_EXTERN_STATE_DIS = 0,
POWER_SUPPLY_EXTERN_STATE_SINK,
POWER_SUPPLY_EXTERN_STATE_SRC,
POWER_SUPPLY_EXTERN_STATE_OFF,
};
enum {
POWER_SUPPLY_PTP_INT_SND_UNKNOWN = 0,
POWER_SUPPLY_PTP_INT_SND_NEVER,
POWER_SUPPLY_PTP_INT_SND_SUPPLEMENTAL,
POWER_SUPPLY_PTP_INT_SND_LOW_BATT_SAVER,
};
enum {
POWER_SUPPLY_PTP_INT_RCV_UNKNOWN = 0,
POWER_SUPPLY_PTP_INT_RCV_NEVER,
POWER_SUPPLY_PTP_INT_RCV_FIRST,
POWER_SUPPLY_PTP_INT_RCV_SECOND,
POWER_SUPPLY_PTP_INT_RCV_PARALLEL,
};
enum {
POWER_SUPPLY_PTP_EXT_SUPPORT_UNKNOWN = 0,
POWER_SUPPLY_PTP_EXT_NOT_SUPPORTED,
POWER_SUPPLY_PTP_EXT_SUPPORTED,
};
enum {
POWER_SUPPLY_PTP_CURRENT_OFF = 0,
POWER_SUPPLY_PTP_CURRENT_FROM_PHONE,
POWER_SUPPLY_PTP_CURRENT_TO_PHONE,
};
enum {
POWER_SUPPLY_PTP_EXT_PRESENCE_UNKNOWN = 0,
POWER_SUPPLY_PTP_EXT_NOT_PRESENT,
POWER_SUPPLY_PTP_EXT_WIRED_PRESENT,
POWER_SUPPLY_PTP_EXT_WIRELESS_PRESENT,
POWER_SUPPLY_PTP_EXT_WIRED_WIRELESS_PRESENT,
};
enum {
POWER_SUPPLY_PTP_POWER_REQUIREMENTS_UNKNOWN = 0,
POWER_SUPPLY_PTP_POWER_NOT_REQUIRED,
POWER_SUPPLY_PTP_POWER_REQUIRED,
};
enum {
POWER_SUPPLY_PTP_POWER_AVAILABILITY_UNKNOWN = 0,
POWER_SUPPLY_PTP_POWER_NOT_AVAILABLE,
POWER_SUPPLY_PTP_POWER_AVAILABLE_EXTERNAL,
POWER_SUPPLY_PTP_POWER_AVAILABLE_INTERNAL,
};
enum {
POWER_SUPPLY_PTP_POWER_SOURCE_UNKNOWN = 0,
POWER_SUPPLY_PTP_POWER_SOURCE_NONE,
POWER_SUPPLY_PTP_POWER_SOURCE_BATTERY,
POWER_SUPPLY_PTP_POWER_SOURCE_WIRED,
POWER_SUPPLY_PTP_POWER_SOURCE_WIRELESS,
POWER_SUPPLY_PTP_POWER_SOURCE_NONE_TURBO,
POWER_SUPPLY_PTP_POWER_SOURCE_BATTERY_TURBO,
POWER_SUPPLY_PTP_POWER_SOURCE_WIRED_TURBO,
POWER_SUPPLY_PTP_POWER_SOURCE_WIRELESS_TURBO,
};
struct device_node;
struct power_supply;
@ -474,6 +570,7 @@ struct power_supply_config {
char **supplied_to;
size_t num_supplicants;
bool free_drv_data;
};
/* Description of power supply */
@ -529,6 +626,7 @@ struct power_supply {
/* Driver private data */
void *drv_data;
bool free_pdd_on_release;
/* private */
struct device dev;

View file

@ -30,6 +30,7 @@ enum usbpd_svdm_cmd_type {
#define USBPD_SVDM_EXIT_MODE 0x5
#define USBPD_SVDM_ATTENTION 0x6
#define PD_MAX_PDO_NUM 7
/*
* Implemented by client
*/
@ -59,6 +60,14 @@ struct usbpd_svid_handler {
bool discovered;
};
struct usbpd_pdo_info {
int pdo_pos;
int uv_max;
int uv_min;
int ua;
int type;
};
enum plug_orientation {
ORIENTATION_NONE,
ORIENTATION_CC1,
@ -93,6 +102,26 @@ int usbpd_send_svdm(struct usbpd *pd, u16 svid, u8 cmd,
enum usbpd_svdm_cmd_type cmd_type, int obj_pos,
const u32 *vdos, int num_vdos);
/*
* Look for best match for PDO selection in Source Mode.
*/
int usbpd_select_pdo_match(struct usbpd *pd);
/*
* Grab Data Role
*/
int usbpd_get_current_dr(struct usbpd *pd);
/*
* support that directly set pdo which is need in Source Mode.
*/
int usbpd_select_pdo(struct usbpd *pd, int pdo_pos, int uv, int ua);
/*
* Transmit all effective pdo info.
*/
int usbpd_get_pdo_info(struct usbpd *pd, struct usbpd_pdo_info *pdo_info);
/*
* Get current status of CC pin orientation.
*
@ -133,6 +162,19 @@ static inline int usbpd_send_svdm(struct usbpd *pd, u16 svid, u8 cmd,
return -EINVAL;
}
/*
* Look for best match for PDO selection in Source Mode.
*/
static inline int usbpd_select_pdo_match(struct usbpd *pd)
{
return -EINVAL;
}
static inline int usbpd_get_current_dr(struct usbpd *pd)
{
return -EINVAL;
}
static inline enum plug_orientation usbpd_get_plug_orientation(struct usbpd *pd)
{
return ORIENTATION_NONE;