diff --git a/drivers/misc/cs40l2x.c b/drivers/misc/cs40l2x.c index 824332238447..738d1783c113 100644 --- a/drivers/misc/cs40l2x.c +++ b/drivers/misc/cs40l2x.c @@ -828,6 +828,172 @@ static ssize_t cs40l2x_dig_scale_store(struct device *dev, return count; } +static int cs40l2x_gpio1_dig_scale_get(struct cs40l2x_private *cs40l2x, + unsigned int *dig_scale) +{ + int ret; + unsigned int val; + + if (!mutex_is_locked(&cs40l2x->lock)) + return -EACCES; + + ret = regmap_read(cs40l2x->regmap, + cs40l2x_dsp_reg(cs40l2x, "GAIN_CONTROL", + CS40L2X_XM_UNPACKED_TYPE), &val); + if (ret) + return ret; + + *dig_scale = (val & CS40L2X_GAIN_CTRL_GPIO_MASK) + >> CS40L2X_GAIN_CTRL_GPIO_SHIFT; + + return 0; +} + +static int cs40l2x_gpio1_dig_scale_set(struct cs40l2x_private *cs40l2x, + unsigned int dig_scale) +{ + if (!mutex_is_locked(&cs40l2x->lock)) + return -EACCES; + + if (dig_scale == CS40L2X_DIG_SCALE_RESET) + return -EINVAL; + + return regmap_update_bits(cs40l2x->regmap, + cs40l2x_dsp_reg(cs40l2x, "GAIN_CONTROL", + CS40L2X_XM_UNPACKED_TYPE), + CS40L2X_GAIN_CTRL_GPIO_MASK, + dig_scale << CS40L2X_GAIN_CTRL_GPIO_SHIFT); +} + +static ssize_t cs40l2x_gpio1_dig_scale_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cs40l2x_private *cs40l2x = cs40l2x_get_private(dev); + int ret; + unsigned int dig_scale; + + mutex_lock(&cs40l2x->lock); + ret = cs40l2x_gpio1_dig_scale_get(cs40l2x, &dig_scale); + mutex_unlock(&cs40l2x->lock); + + if (ret) { + pr_err("Failed to read digital scale\n"); + return ret; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", dig_scale); +} + +static ssize_t cs40l2x_gpio1_dig_scale_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cs40l2x_private *cs40l2x = cs40l2x_get_private(dev); + int ret; + unsigned int dig_scale; + + ret = kstrtou32(buf, 10, &dig_scale); + if (ret) + return -EINVAL; + + if (dig_scale > CS40L2X_DIG_SCALE_MAX) + return -EINVAL; + + mutex_lock(&cs40l2x->lock); + ret = cs40l2x_gpio1_dig_scale_set(cs40l2x, dig_scale); + mutex_unlock(&cs40l2x->lock); + + if (ret) { + pr_err("Failed to write digital scale\n"); + return ret; + } + + return count; +} + +static int cs40l2x_cp_dig_scale_get(struct cs40l2x_private *cs40l2x, + unsigned int *dig_scale) +{ + int ret; + unsigned int val; + + if (!mutex_is_locked(&cs40l2x->lock)) + return -EACCES; + + ret = regmap_read(cs40l2x->regmap, + cs40l2x_dsp_reg(cs40l2x, "GAIN_CONTROL", + CS40L2X_XM_UNPACKED_TYPE), &val); + if (ret) + return ret; + + *dig_scale = (val & CS40L2X_GAIN_CTRL_TRIG_MASK) + >> CS40L2X_GAIN_CTRL_TRIG_SHIFT; + + return 0; +} + +static int cs40l2x_cp_dig_scale_set(struct cs40l2x_private *cs40l2x, + unsigned int dig_scale) +{ + if (!mutex_is_locked(&cs40l2x->lock)) + return -EACCES; + + if (dig_scale == CS40L2X_DIG_SCALE_RESET) + return -EINVAL; + + return regmap_update_bits(cs40l2x->regmap, + cs40l2x_dsp_reg(cs40l2x, "GAIN_CONTROL", + CS40L2X_XM_UNPACKED_TYPE), + CS40L2X_GAIN_CTRL_TRIG_MASK, + dig_scale << CS40L2X_GAIN_CTRL_TRIG_SHIFT); +} + +static ssize_t cs40l2x_cp_dig_scale_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cs40l2x_private *cs40l2x = cs40l2x_get_private(dev); + int ret; + unsigned int dig_scale; + + mutex_lock(&cs40l2x->lock); + ret = cs40l2x_cp_dig_scale_get(cs40l2x, &dig_scale); + mutex_unlock(&cs40l2x->lock); + + if (ret) { + pr_err("Failed to read digital scale\n"); + return ret; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", dig_scale); +} + +static ssize_t cs40l2x_cp_dig_scale_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cs40l2x_private *cs40l2x = cs40l2x_get_private(dev); + int ret; + unsigned int dig_scale; + + ret = kstrtou32(buf, 10, &dig_scale); + if (ret) + return -EINVAL; + + if (dig_scale > CS40L2X_DIG_SCALE_MAX) + return -EINVAL; + + mutex_lock(&cs40l2x->lock); + ret = cs40l2x_cp_dig_scale_set(cs40l2x, dig_scale); + mutex_unlock(&cs40l2x->lock); + + if (ret) { + pr_err("Failed to write digital scale\n"); + return ret; + } + + return count; +} + static ssize_t cs40l2x_heartbeat_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -935,6 +1101,10 @@ static DEVICE_ATTR(comp_enable, 0660, cs40l2x_comp_enable_show, cs40l2x_comp_enable_store); static DEVICE_ATTR(dig_scale, 0660, cs40l2x_dig_scale_show, cs40l2x_dig_scale_store); +static DEVICE_ATTR(gpio1_dig_scale, 0660, cs40l2x_gpio1_dig_scale_show, + cs40l2x_gpio1_dig_scale_store); +static DEVICE_ATTR(cp_dig_scale, 0660, cs40l2x_cp_dig_scale_show, + cs40l2x_cp_dig_scale_store); static DEVICE_ATTR(heartbeat, 0660, cs40l2x_heartbeat_show, NULL); static DEVICE_ATTR(num_waves, 0660, cs40l2x_num_waves_show, NULL); static DEVICE_ATTR(aoh_auto_enable, 0660, cs40l2x_aoh_auto_enable_show, @@ -953,6 +1123,8 @@ static struct attribute *cs40l2x_dev_attrs[] = { &dev_attr_redc_stored.attr, &dev_attr_comp_enable.attr, &dev_attr_dig_scale.attr, + &dev_attr_gpio1_dig_scale.attr, + &dev_attr_cp_dig_scale.attr, &dev_attr_heartbeat.attr, &dev_attr_num_waves.attr, &dev_attr_aoh_auto_enable.attr, diff --git a/drivers/misc/cs40l2x.h b/drivers/misc/cs40l2x.h index 2adb5b9d1f4c..bbf208b4bf85 100644 --- a/drivers/misc/cs40l2x.h +++ b/drivers/misc/cs40l2x.h @@ -617,6 +617,12 @@ #define CS40L2X_AMP_VOL_PCM_MASK 0x00003FF8 #define CS40L2X_AMP_VOL_PCM_SHIFT 3 +#define CS40L2X_GAIN_CTRL_GPIO_MASK 0x00FFC000 +#define CS40L2X_GAIN_CTRL_GPIO_SHIFT 14 + +#define CS40L2X_GAIN_CTRL_TRIG_MASK 0x00003FF0 +#define CS40L2X_GAIN_CTRL_TRIG_SHIFT 4 + #define CS40L2X_OTP_BOOT_ERR 0x80000000 #define CS40L2X_OTP_BOOT_DONE 0x00000002 @@ -665,7 +671,7 @@ #define CS40L2X_ALGO_REV_MASK 0xFF0000 #define CS40L2X_NUM_ALGOS_MAX 16 -#define CS40L2X_FW_REV_MIN 0x030000 +#define CS40L2X_FW_REV_MIN 0x040100 #define CS40L2X_ALGO_ID_SIZE 4 #define CS40L2X_COEFF_COUNT_SIZE 4 @@ -724,6 +730,7 @@ #define CS40L2X_DIG_SCALE_MAX 816 /* -102 dB */ #define CS40L2X_DIG_SCALE_ZERO 0x800 #define CS40L2X_DIG_SCALE_MASK 0x7FF +#define CS40L2X_DIG_SCALE_RESET 0x80000000 #define CS40L2X_MAX_WLEN 4096