Merge "asoc: wcd939x: Add xtalk/linearizer sysfs params"
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

commit
9b48000bd5
@@ -20,6 +20,8 @@
|
|||||||
#include <sound/soc-dapm.h>
|
#include <sound/soc-dapm.h>
|
||||||
#include <asoc/wcdcal-hwdep.h>
|
#include <asoc/wcdcal-hwdep.h>
|
||||||
#include <asoc/wcd-mbhc-v2-api.h>
|
#include <asoc/wcd-mbhc-v2-api.h>
|
||||||
|
#include <linux/sysfs.h>
|
||||||
|
#include <linux/kobject.h>
|
||||||
#include "wcd939x-registers.h"
|
#include "wcd939x-registers.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
|
#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
|
||||||
@@ -952,6 +954,310 @@ err_data:
|
|||||||
*gnd_tap = 0;
|
*gnd_tap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct usbcss_hs_attr {
|
||||||
|
struct wcd939x_priv *priv;
|
||||||
|
struct kobj_attribute attr;
|
||||||
|
int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *usbcss_sysfs_files[] = {
|
||||||
|
"rdson",
|
||||||
|
"r2",
|
||||||
|
"r3",
|
||||||
|
"r4",
|
||||||
|
"r5",
|
||||||
|
"r6",
|
||||||
|
"r7",
|
||||||
|
"lin-k-aud",
|
||||||
|
"lin-k-gnd",
|
||||||
|
"xtalk_config",
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t usbcss_sysfs_store(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr, const char *buf,
|
||||||
|
size_t count)
|
||||||
|
{
|
||||||
|
struct usbcss_hs_attr *usbc_attr;
|
||||||
|
struct wcd939x_priv *wcd939x;
|
||||||
|
struct wcd939x_pdata *pdata;
|
||||||
|
struct wcd939x_usbcss_hs_params *usbcss_hs;
|
||||||
|
long val;
|
||||||
|
int rc;
|
||||||
|
u32 aud_tap = 0, gnd_tap = 0;
|
||||||
|
bool update_xtalk = false, update_linearizer = false;
|
||||||
|
|
||||||
|
usbc_attr = container_of(attr, struct usbcss_hs_attr, attr);
|
||||||
|
wcd939x = usbc_attr->priv;
|
||||||
|
pdata = dev_get_platdata(wcd939x->dev);
|
||||||
|
|
||||||
|
if (!wcd939x || !pdata)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
usbcss_hs = &pdata->usbcss_hs;
|
||||||
|
|
||||||
|
rc = kstrtol(buf, 0, &val);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (strcmp(attr->attr.name, "rdson") == 0) {
|
||||||
|
if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
|
||||||
|
dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
|
||||||
|
__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
usbcss_hs->r_gnd_ext_fet_customer_mohms = val;
|
||||||
|
update_linearizer = usbcss_hs->xtalk_config == XTALK_ANALOG;
|
||||||
|
} else if (strcmp(attr->attr.name, "r2") == 0) {
|
||||||
|
if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
|
||||||
|
dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
|
||||||
|
__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
usbcss_hs->r_conn_par_load_pos_mohms = val;
|
||||||
|
} else if (strcmp(attr->attr.name, "r3") == 0) {
|
||||||
|
if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
|
||||||
|
dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
|
||||||
|
__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
usbcss_hs->r3 = val;
|
||||||
|
update_linearizer = true;
|
||||||
|
} else if (strcmp(attr->attr.name, "r4") == 0) {
|
||||||
|
if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
|
||||||
|
dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
|
||||||
|
__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
usbcss_hs->r4 = val;
|
||||||
|
update_xtalk = true;
|
||||||
|
update_linearizer = true;
|
||||||
|
|
||||||
|
switch (usbcss_hs->xtalk_config) {
|
||||||
|
case XTALK_DIGITAL:
|
||||||
|
usbcss_hs->r_gnd_par_route2_mohms = usbcss_hs->r6 + val;
|
||||||
|
break;
|
||||||
|
case XTALK_ANALOG:
|
||||||
|
usbcss_hs->r_gnd_par_route1_mohms = usbcss_hs->r5 + val;
|
||||||
|
break;
|
||||||
|
case XTALK_NONE:
|
||||||
|
fallthrough;
|
||||||
|
default:
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
} else if (strcmp(attr->attr.name, "r5") == 0) {
|
||||||
|
if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
|
||||||
|
dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
|
||||||
|
__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
usbcss_hs->r5 = val;
|
||||||
|
|
||||||
|
switch (usbcss_hs->xtalk_config) {
|
||||||
|
case XTALK_ANALOG:
|
||||||
|
update_xtalk = true;
|
||||||
|
update_linearizer = true;
|
||||||
|
usbcss_hs->r_gnd_par_route1_mohms = val + usbcss_hs->r4;
|
||||||
|
break;
|
||||||
|
case XTALK_DIGITAL:
|
||||||
|
fallthrough;
|
||||||
|
case XTALK_NONE:
|
||||||
|
fallthrough;
|
||||||
|
default:
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
} else if (strcmp(attr->attr.name, "r6") == 0) {
|
||||||
|
if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
|
||||||
|
dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
|
||||||
|
__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
usbcss_hs->r6 = val;
|
||||||
|
|
||||||
|
switch (usbcss_hs->xtalk_config) {
|
||||||
|
case XTALK_DIGITAL:
|
||||||
|
update_xtalk = true;
|
||||||
|
update_linearizer = true;
|
||||||
|
usbcss_hs->r_gnd_par_route2_mohms = val + usbcss_hs->r4;
|
||||||
|
break;
|
||||||
|
case XTALK_ANALOG:
|
||||||
|
fallthrough;
|
||||||
|
case XTALK_NONE:
|
||||||
|
fallthrough;
|
||||||
|
default:
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
} else if (strcmp(attr->attr.name, "r7") == 0) {
|
||||||
|
if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) {
|
||||||
|
dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n",
|
||||||
|
__func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
usbcss_hs->r7 = val;
|
||||||
|
|
||||||
|
switch (usbcss_hs->xtalk_config) {
|
||||||
|
case XTALK_DIGITAL:
|
||||||
|
update_xtalk = true;
|
||||||
|
update_linearizer = true;
|
||||||
|
usbcss_hs->r_gnd_par_route1_mohms = val;
|
||||||
|
break;
|
||||||
|
case XTALK_ANALOG:
|
||||||
|
fallthrough;
|
||||||
|
case XTALK_NONE:
|
||||||
|
fallthrough;
|
||||||
|
default:
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
} else if (strcmp(attr->attr.name, "lin-k-aud") == 0) {
|
||||||
|
if (val < MIN_K_TIMES_100 || val > MAX_K_TIMES_100) {
|
||||||
|
dev_err(wcd939x->dev, "%s: Value %d out of bounds. Min: %d, Max: %d\n",
|
||||||
|
__func__, val, MIN_K_TIMES_100, MAX_K_TIMES_100);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
usbcss_hs->k_aud_times_100 = val;
|
||||||
|
update_linearizer = true;
|
||||||
|
} else if (strcmp(attr->attr.name, "lin-k-gnd") == 0) {
|
||||||
|
if (val < MIN_K_TIMES_100 || val > MAX_K_TIMES_100) {
|
||||||
|
dev_err(wcd939x->dev, "%s: Value %d out of bounds. Min: %d, Max: %d\n",
|
||||||
|
__func__, val, MIN_K_TIMES_100, MAX_K_TIMES_100);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
usbcss_hs->k_gnd_times_100 = val;
|
||||||
|
update_linearizer = true;
|
||||||
|
} else if (strcmp(attr->attr.name, "xtalk_config") == 0) {
|
||||||
|
pdata->usbcss_hs.xtalk_config = val;
|
||||||
|
update_xtalk = true;
|
||||||
|
|
||||||
|
switch (val) {
|
||||||
|
case XTALK_NONE:
|
||||||
|
usbcss_hs->scale_l = MAX_XTALK_SCALE;
|
||||||
|
usbcss_hs->scale_r = MAX_XTALK_SCALE;
|
||||||
|
usbcss_hs->alpha_l = MIN_XTALK_ALPHA;
|
||||||
|
usbcss_hs->alpha_r = MIN_XTALK_ALPHA;
|
||||||
|
break;
|
||||||
|
case XTALK_DIGITAL:
|
||||||
|
usbcss_hs->r_gnd_par_route2_mohms = usbcss_hs->r6 + usbcss_hs->r4;
|
||||||
|
usbcss_hs->r_gnd_par_route1_mohms = usbcss_hs->r7;
|
||||||
|
update_linearizer = true;
|
||||||
|
break;
|
||||||
|
case XTALK_ANALOG:
|
||||||
|
usbcss_hs->r_gnd_par_route1_mohms = usbcss_hs->r5 + usbcss_hs->r4;
|
||||||
|
usbcss_hs->r_gnd_par_route2_mohms = 1;
|
||||||
|
update_linearizer = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update_xtalk) {
|
||||||
|
update_xtalk_scale_and_alpha(pdata, wcd939x->regmap);
|
||||||
|
regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC0,
|
||||||
|
0x1F, pdata->usbcss_hs.scale_l);
|
||||||
|
regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC1,
|
||||||
|
0xFF, pdata->usbcss_hs.alpha_l);
|
||||||
|
regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC0 + 1,
|
||||||
|
0x1F, pdata->usbcss_hs.scale_r);
|
||||||
|
regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC1 + 1,
|
||||||
|
0xFF, pdata->usbcss_hs.alpha_r);
|
||||||
|
dev_err(wcd939x->dev, "%s: Updated xtalk thru sysfs\n",
|
||||||
|
__func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update_linearizer) {
|
||||||
|
get_linearizer_taps(pdata, &aud_tap, &gnd_tap);
|
||||||
|
wcd_usbss_set_linearizer_sw_tap(aud_tap, gnd_tap);
|
||||||
|
dev_err(wcd939x->dev, "%s: Updated linearizer thru sysfs\n",
|
||||||
|
__func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t usbcss_sysfs_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct usbcss_hs_attr *usbc_attr;
|
||||||
|
struct wcd939x_priv *wcd939x;
|
||||||
|
struct wcd939x_pdata *pdata;
|
||||||
|
|
||||||
|
usbc_attr = container_of(attr, struct usbcss_hs_attr, attr);
|
||||||
|
wcd939x = usbc_attr->priv;
|
||||||
|
pdata = dev_get_platdata(wcd939x->dev);
|
||||||
|
|
||||||
|
if (strcmp(attr->attr.name, "rdson") == 0)
|
||||||
|
return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r_gnd_ext_fet_customer_mohms);
|
||||||
|
else if (strcmp(attr->attr.name, "r2") == 0)
|
||||||
|
return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r_conn_par_load_pos_mohms);
|
||||||
|
else if (strcmp(attr->attr.name, "r3") == 0)
|
||||||
|
return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r3);
|
||||||
|
else if (strcmp(attr->attr.name, "r4") == 0)
|
||||||
|
return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r4);
|
||||||
|
else if (strcmp(attr->attr.name, "r5") == 0)
|
||||||
|
return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r5);
|
||||||
|
else if (strcmp(attr->attr.name, "r6") == 0)
|
||||||
|
return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r6);
|
||||||
|
else if (strcmp(attr->attr.name, "r7") == 0)
|
||||||
|
return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.r7);
|
||||||
|
else if (strcmp(attr->attr.name, "lin-k-aud") == 0)
|
||||||
|
return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.k_aud_times_100);
|
||||||
|
else if (strcmp(attr->attr.name, "lin-k-gnd") == 0)
|
||||||
|
return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.k_gnd_times_100);
|
||||||
|
else if (strcmp(attr->attr.name, "xtalk_config") == 0)
|
||||||
|
return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.xtalk_config);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create_sysfs_entry_file(struct wcd939x_priv *wcd939x, char *name, int mode,
|
||||||
|
int index, struct kobject *parent)
|
||||||
|
{
|
||||||
|
struct usbcss_hs_attr *usbc_attr;
|
||||||
|
char *name_copy;
|
||||||
|
|
||||||
|
usbc_attr = devm_kmalloc(wcd939x->dev, sizeof(*usbc_attr), GFP_KERNEL);
|
||||||
|
if (!usbc_attr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
name_copy = devm_kstrdup(wcd939x->dev, name, GFP_KERNEL);
|
||||||
|
if (!name_copy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
usbc_attr->priv = wcd939x;
|
||||||
|
usbc_attr->index = index;
|
||||||
|
usbc_attr->attr.attr.name = name_copy;
|
||||||
|
usbc_attr->attr.attr.mode = mode;
|
||||||
|
usbc_attr->attr.show = usbcss_sysfs_show;
|
||||||
|
usbc_attr->attr.store = usbcss_sysfs_store;
|
||||||
|
sysfs_attr_init(&usbc_attr->attr.attr);
|
||||||
|
|
||||||
|
return sysfs_create_file(parent, &usbc_attr->attr.attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int usbcss_hs_sysfs_init(struct wcd939x_priv *wcd939x)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
int i = 0;
|
||||||
|
struct kobject *kobj = NULL;
|
||||||
|
|
||||||
|
if (!wcd939x || !wcd939x->dev) {
|
||||||
|
pr_err("%s: Invalid wcd939x private data.\n", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
kobj = kobject_create_and_add("usbcss_hs", kernel_kobj);
|
||||||
|
if (!kobj) {
|
||||||
|
dev_err(wcd939x->dev, "%s: Could not create the USBC-SS HS kobj.\n", __func__);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(usbcss_sysfs_files); i++) {
|
||||||
|
rc = create_sysfs_entry_file(wcd939x, usbcss_sysfs_files[i],
|
||||||
|
0644, i, kobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void wcd939x_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr)
|
static void wcd939x_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr)
|
||||||
{
|
{
|
||||||
struct snd_soc_component *component = mbhc->component;
|
struct snd_soc_component *component = mbhc->component;
|
||||||
@@ -1607,6 +1913,7 @@ int wcd939x_mbhc_init(struct wcd939x_mbhc **mbhc,
|
|||||||
struct wcd_mbhc *wcd_mbhc = NULL;
|
struct wcd_mbhc *wcd_mbhc = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct wcd939x_pdata *pdata;
|
struct wcd939x_pdata *pdata;
|
||||||
|
struct wcd939x_priv *wcd939x;
|
||||||
|
|
||||||
if (!component) {
|
if (!component) {
|
||||||
pr_err("%s: component is NULL\n", __func__);
|
pr_err("%s: component is NULL\n", __func__);
|
||||||
@@ -1659,6 +1966,14 @@ int wcd939x_mbhc_init(struct wcd939x_mbhc **mbhc,
|
|||||||
snd_soc_add_component_controls(component, hph_type_detect_controls,
|
snd_soc_add_component_controls(component, hph_type_detect_controls,
|
||||||
ARRAY_SIZE(hph_type_detect_controls));
|
ARRAY_SIZE(hph_type_detect_controls));
|
||||||
|
|
||||||
|
wcd939x = dev_get_drvdata(component->dev);
|
||||||
|
if (!wcd939x) {
|
||||||
|
dev_err(component->dev, "%s: wcd939x pointer is NULL\n", __func__);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
usbcss_hs_sysfs_init(wcd939x);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
if (wcd939x_mbhc)
|
if (wcd939x_mbhc)
|
||||||
|
Reference in New Issue
Block a user