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

committed by
Gerrit - the friendly Code Review server

melakukan
9b48000bd5
@@ -20,6 +20,8 @@
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <asoc/wcdcal-hwdep.h>
|
||||
#include <asoc/wcd-mbhc-v2-api.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/kobject.h>
|
||||
#include "wcd939x-registers.h"
|
||||
#include "internal.h"
|
||||
#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C)
|
||||
@@ -952,6 +954,310 @@ err_data:
|
||||
*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)
|
||||
{
|
||||
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;
|
||||
int ret = 0;
|
||||
struct wcd939x_pdata *pdata;
|
||||
struct wcd939x_priv *wcd939x;
|
||||
|
||||
if (!component) {
|
||||
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,
|
||||
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;
|
||||
err:
|
||||
if (wcd939x_mbhc)
|
||||
|
Reference in New Issue
Block a user