misc: cs40l2x: Add basic-mode haptics shutdown sequence

Added a shutdown sequence to safely exit basic-mode haptics following
device power-on, prior to re-initializing the device and booting the
DSP into normal operation.

Change-Id: I3955f60fa736071d0af80edc65777100ef9865b0
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-12 19:26:36 -05:00 • committed by a7301c
commit 98d5fb77b8
2 changed files with 112 additions and 2 deletions

View file

@ -1591,8 +1591,6 @@ static void cs40l2x_dsp_start(struct cs40l2x_private *cs40l2x)
return;
}
dev_info(dev, "Haptics algorithm started\n");
ret = regmap_write(regmap, cs40l2x_dsp_reg(cs40l2x, "TIMEOUT_MS",
CS40L2X_XM_UNPACKED_TYPE), CS40L2X_TIMEOUT_MS_MAX);
if (ret) {
@ -1612,6 +1610,8 @@ static void cs40l2x_dsp_start(struct cs40l2x_private *cs40l2x)
return;
}
dev_info(dev, "Normal-mode haptics successfully started\n");
cs40l2x_vibe_init(cs40l2x);
}
@ -2286,6 +2286,67 @@ static int cs40l2x_handle_of_data(struct i2c_client *i2c_client,
return 0;
}
static int cs40l2x_basic_mode_exit(struct cs40l2x_private *cs40l2x)
{
struct regmap *regmap = cs40l2x->regmap;
struct device *dev = cs40l2x->dev;
unsigned int val;
int shutdown_timeout = CS40L2X_BASIC_TIMEOUT_COUNT;
int ret;
ret = regmap_read(regmap, CS40L2X_BASIC_AMP_STATUS, &val);
if (ret) {
dev_err(dev, "Failed to read basic-mode status\n");
return ret;
}
if (val != CS40L2X_BASIC_BOOT_DONE) {
dev_err(dev, "Unexpected basic-mode status: %02X\n", val);
return -EIO;
}
ret = regmap_write(regmap, CS40L2X_BASIC_SHUTDOWNREQUEST, 1);
if (ret) {
dev_err(dev, "Failed to write shutdown request\n");
return ret;
}
while (shutdown_timeout > 0) {
usleep_range(10000, 10100);
ret = regmap_read(regmap, CS40L2X_BASIC_SHUTDOWNREQUEST, &val);
if (ret) {
dev_err(dev, "Failed to read shutdown request\n");
return ret;
}
if (!val)
break;
shutdown_timeout--;
}
if (shutdown_timeout == 0) {
dev_err(dev, "Timed out waiting for basic-mode shutdown\n");
return -ETIME;
}
ret = regmap_read(regmap, CS40L2X_BASIC_STATEMACHINE, &val);
if (ret) {
dev_err(dev, "Failed to read basic-mode state\n");
return ret;
}
if (val != CS40L2X_BASIC_SHUTDOWN) {
dev_err(dev, "Unexpected basic-mode state: %02X\n", val);
return -EBUSY;
}
dev_info(dev, "Basic-mode haptics successfully stopped\n");
return 0;
}
static const struct reg_sequence cs40l2x_rev_a0_errata[] = {
{CS40L2X_OTP_TRIM_30, 0x9091A1C8},
{CS40L2X_PLL_LOOP_PARAM, 0x00001837},
@ -2301,6 +2362,13 @@ static const struct reg_sequence cs40l2x_rev_b0_errata[] = {
{CS40L2X_PLL_MISC_CTRL, 0x03008E0E},
};
static const struct reg_sequence cs40l2x_basic_mode_revert[] = {
{CS40L2X_PWR_CTRL1, 0x00000000},
{CS40L2X_PWR_CTRL2, 0x00003321},
{CS40L2X_IRQ2_MASK1, 0xFFFFFFFF},
{CS40L2X_IRQ2_MASK2, 0xFFFFFFFF},
};
static int cs40l2x_part_num_resolve(struct cs40l2x_private *cs40l2x)
{
struct regmap *regmap = cs40l2x->regmap;
@ -2390,6 +2458,17 @@ static int cs40l2x_part_num_resolve(struct cs40l2x_private *cs40l2x)
if (revid < CS40L2X_REVID_B1)
goto err_revid;
ret = cs40l2x_basic_mode_exit(cs40l2x);
if (ret)
return ret;
ret = regmap_multi_reg_write(regmap, cs40l2x_basic_mode_revert,
ARRAY_SIZE(cs40l2x_basic_mode_revert));
if (ret) {
dev_err(dev, "Failed to revert basic-mode fields\n");
return ret;
}
ret = regmap_register_patch(regmap, cs40l2x_rev_b0_errata,
ARRAY_SIZE(cs40l2x_rev_b0_errata));
if (ret) {

View file

@ -538,6 +538,35 @@
#define CS40L2X_OTP_TRIM_35 0x0000400C
#define CS40L2X_OTP_TRIM_36 0x00002030
/* basic mode (ROM) fields */
#define CS40L2X_BASIC_HALO_STATE 0x02800154
#define CS40L2X_BASIC_HALO_HEARTBEAT 0x02800158
#define CS40L2X_BASIC_STATEMACHINE 0X0280015C
#define CS40L2X_BASIC_F0_STORED 0X02800174
#define CS40L2X_BASIC_GPIO_TRIGGER_EDGE 0x02800178
#define CS40L2X_BASIC_BUZZ_FREQ 0x0280017C
#define CS40L2X_BASIC_BUZZ_LEVEL 0x02800180
#define CS40L2X_BASIC_BUZZ_DURATION 0x02800184
#define CS40L2X_BASIC_BUZZ_TRIGGER 0x02800188
#define CS40L2X_BASIC_AMP_STATUS 0x0280018C
#define CS40L2X_BASIC_SHUTDOWNREQUEST 0x02800190
/* basic mode (ROM) states */
#define CS40L2X_BASIC_IDLE 0
#define CS40L2X_BASIC_PLAY_TONE 1
#define CS40L2X_BASIC_CONTINUE_TONE 2
#define CS40L2X_BASIC_SHUTTINGDOWN 3
#define CS40L2X_BASIC_SHUTDOWN 4
/* basic mode (ROM) status flags */
#define CS40L2X_BASIC_NO_STATUS 0x00
#define CS40L2X_BASIC_BOOT_DONE 0x01
#define CS40L2X_BASIC_OTP_ERROR 0x02
#define CS40L2X_BASIC_AMP_ERROR 0x04
#define CS40L2X_BASIC_TEMP_RISE_WARN 0x08
#define CS40L2X_BASIC_TEMP_ERROR 0x10
#define CS40L2X_BASIC_SA_ERROR 0x20
#define CS40L2X_GLOBAL_EN_MASK 0x00000001
#define CS40L2X_GLOBAL_EN_SHIFT 0
@ -678,6 +707,8 @@
#define CS40L2X_DSP_TIMEOUT_COUNT 10 /* 1 count = 10 ms */
#define CS40L2X_OTP_TIMEOUT_COUNT 10
#define CS40L2X_BASIC_TIMEOUT_COUNT 10
#define CS40L2X_NUM_OTP_MAPS 3
#define CS40L2X_NUM_OTP_WORDS 32