misc: cs40l2x: Add support for Always-On Haptics

* Removed write to GLOBAL_EN during initialization as this control is
  now managed autonomously by firmware.
* Replaced trigger control DSP memory addresses with their fixed-address
  representations in the mailbox space.
* Added sysfs controls for the firmware's GPIO1 falling edge timeout and
  standby timeout controls.
* Increased the minimum supported firmware revision to 2.1.0.

Change-Id: I38cdac4e6ac79fb8f354750ac724ce119eb7764c
Signed-off-by: Jeff LaBundy <jeff.labundy@cirrus.com>
Signed-off-by: Ravi Vembu <raviv@motorola.com>
This commit is contained in:
Jeff LaBundy 2018-04-09 14:45:33 -05:00 • committed by a7301c
commit fca66161fa
2 changed files with 111 additions and 26 deletions

View file

@ -245,6 +245,100 @@ static ssize_t cs40l2x_gpio1_fall_index_store(struct device *dev,
return count;
}
static ssize_t cs40l2x_gpio1_fall_timeout_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cs40l2x_private *cs40l2x = cs40l2x_get_private(dev);
int ret;
unsigned int val;
mutex_lock(&cs40l2x->lock);
ret = regmap_read(cs40l2x->regmap,
cs40l2x_dsp_reg(cs40l2x, "PRESS_RELEASE_TIMEOUT",
CS40L2X_XM_UNPACKED_TYPE), &val);
mutex_unlock(&cs40l2x->lock);
if (ret) {
pr_err("Failed to read GPIO1 falling-edge timeout\n");
return ret;
}
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t cs40l2x_gpio1_fall_timeout_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 val;
ret = kstrtou32(buf, 10, &val);
if (ret)
return -EINVAL;
mutex_lock(&cs40l2x->lock);
ret = regmap_write(cs40l2x->regmap,
cs40l2x_dsp_reg(cs40l2x, "PRESS_RELEASE_TIMEOUT",
CS40L2X_XM_UNPACKED_TYPE), val);
mutex_unlock(&cs40l2x->lock);
if (ret) {
pr_err("Failed to write GPIO1 falling-edge timeout\n");
return ret;
}
return count;
}
static ssize_t cs40l2x_standby_timeout_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cs40l2x_private *cs40l2x = cs40l2x_get_private(dev);
int ret;
unsigned int val;
mutex_lock(&cs40l2x->lock);
ret = regmap_read(cs40l2x->regmap,
cs40l2x_dsp_reg(cs40l2x, "EVENT_TIMEOUT",
CS40L2X_XM_UNPACKED_TYPE), &val);
mutex_unlock(&cs40l2x->lock);
if (ret) {
pr_err("Failed to read standby timeout\n");
return ret;
}
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t cs40l2x_standby_timeout_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 val;
ret = kstrtou32(buf, 10, &val);
if (ret)
return -EINVAL;
mutex_lock(&cs40l2x->lock);
ret = regmap_write(cs40l2x->regmap,
cs40l2x_dsp_reg(cs40l2x, "EVENT_TIMEOUT",
CS40L2X_XM_UNPACKED_TYPE), val);
mutex_unlock(&cs40l2x->lock);
if (ret) {
pr_err("Failed to write standby timeout\n");
return ret;
}
return count;
}
static ssize_t cs40l2x_f0_measured_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@ -501,6 +595,10 @@ static DEVICE_ATTR(gpio1_rise_index, 0660, cs40l2x_gpio1_rise_index_show,
cs40l2x_gpio1_rise_index_store);
static DEVICE_ATTR(gpio1_fall_index, 0660, cs40l2x_gpio1_fall_index_show,
cs40l2x_gpio1_fall_index_store);
static DEVICE_ATTR(gpio1_fall_timeout, 0660, cs40l2x_gpio1_fall_timeout_show,
cs40l2x_gpio1_fall_timeout_store);
static DEVICE_ATTR(standby_timeout, 0660, cs40l2x_standby_timeout_show,
cs40l2x_standby_timeout_store);
static DEVICE_ATTR(f0_measured, 0660, cs40l2x_f0_measured_show, NULL);
static DEVICE_ATTR(f0_stored, 0660, cs40l2x_f0_stored_show,
cs40l2x_f0_stored_store);
@ -518,6 +616,8 @@ static struct attribute *cs40l2x_dev_attrs[] = {
&dev_attr_cp_trigger_index.attr,
&dev_attr_gpio1_rise_index.attr,
&dev_attr_gpio1_fall_index.attr,
&dev_attr_gpio1_fall_timeout.attr,
&dev_attr_standby_timeout.attr,
&dev_attr_f0_measured.attr,
&dev_attr_f0_stored.attr,
&dev_attr_redc_measured.attr,
@ -581,20 +681,15 @@ static void cs40l2x_vibe_start_worker(struct work_struct *work)
switch (cs40l2x->cp_trailer_index) {
case 0x0000:
case 0x8000 ... 0xFFFE:
ret = regmap_write(regmap,
cs40l2x_dsp_reg(cs40l2x, "TRIGGER_MS",
CS40L2X_XM_UNPACKED_TYPE),
cs40l2x->cp_trailer_index
& CS40L2X_INDEX_MASK);
ret = regmap_write(regmap, CS40L2X_MBOX_TRIGGER_MS,
cs40l2x->cp_trailer_index & CS40L2X_INDEX_MASK);
if (ret)
dev_err(dev, "Failed to start playback\n");
break;
case 0x0001 ... 0x7FFF:
ret = regmap_write(regmap,
cs40l2x_dsp_reg(cs40l2x, "TRIGGERINDEX",
CS40L2X_XM_UNPACKED_TYPE),
cs40l2x->cp_trailer_index);
ret = regmap_write(regmap, CS40L2X_MBOX_TRIGGERINDEX,
cs40l2x->cp_trailer_index);
if (ret)
dev_err(dev, "Failed to start playback\n");
break;
@ -618,9 +713,7 @@ static void cs40l2x_vibe_start_worker(struct work_struct *work)
goto err_mutex;
}
ret = regmap_write(regmap,
cs40l2x_dsp_reg(cs40l2x, "STIMULUS_MODE",
CS40L2X_XM_UNPACKED_TYPE), 1);
ret = regmap_write(regmap, CS40L2X_MBOX_STIMULUS_MODE, 1);
if (ret) {
dev_err(dev, "Failed to enable stimulus mode\n");
goto err_mutex;
@ -663,9 +756,7 @@ static void cs40l2x_vibe_stop_worker(struct work_struct *work)
if (ret)
dev_err(dev, "Failed to capture f0 and ReDC\n");
ret = regmap_write(regmap,
cs40l2x_dsp_reg(cs40l2x, "STIMULUS_MODE",
CS40L2X_XM_UNPACKED_TYPE), 0);
ret = regmap_write(regmap, CS40L2X_MBOX_STIMULUS_MODE, 0);
if (ret)
dev_err(dev, "Failed to disable stimulus mode\n");
@ -1560,13 +1651,6 @@ static int cs40l2x_init(struct cs40l2x_private *cs40l2x)
return ret;
}
ret = regmap_update_bits(regmap, CS40L2X_PWR_CTRL1,
CS40L2X_GLOBAL_EN_MASK, 1 << CS40L2X_GLOBAL_EN_SHIFT);
if (ret) {
dev_err(dev, "Failed to enable device\n");
return ret;
}
return 0;
}

View file

@ -537,9 +537,6 @@
#define CS40L2X_OTP_TRIM_35 0x0000400C
#define CS40L2X_OTP_TRIM_36 0x00002030
#define CS40L2X_GLOBAL_EN_MASK 0x01
#define CS40L2X_GLOBAL_EN_SHIFT 0
#define CS40L2X_GP2_CTRL_MASK 0x07000000
#define CS40L2X_GP2_CTRL_SHIFT 24
#define CS40L2X_GP2_CTRL_MCLK 0x3
@ -631,7 +628,7 @@
#define CS40L2X_ALGO_REV_MASK 0xFF0000
#define CS40L2X_NUM_ALGOS_MAX 16
#define CS40L2X_FW_REV_MIN 0x010000
#define CS40L2X_FW_REV_MIN 0x020100
#define CS40L2X_ALGO_ID_SIZE 4
#define CS40L2X_COEFF_COUNT_SIZE 4
@ -642,6 +639,10 @@
#define CS40L2X_TIMEOUT_MS_MAX 0x02AAAA /* ~174 sec */
#define CS40L2X_HALO_STATE_RUNNING 0x2
#define CS40L2X_MBOX_TRIGGERINDEX CS40L2X_DSP_VIRT1_MBOX_1
#define CS40L2X_MBOX_TRIGGER_MS CS40L2X_DSP_VIRT1_MBOX_2
#define CS40L2X_MBOX_STIMULUS_MODE CS40L2X_DSP_VIRT1_MBOX_3
#define CS40L2X_INDEX_MASK 0x7FFF
#define CS40L2X_INDEX_DIAG 0xFFFF