From ef350cb89f46bebd583fd7cf23e1bb33d697f208 Mon Sep 17 00:00:00 2001 From: Konstantin Makariev Date: Mon, 29 Aug 2022 18:25:45 -0500 Subject: [PATCH] drv8424_mmi: handling corner cases Added handling for the following operations whether they time out or come short, e.g. incomplete in some way or another: 1) initial position detection and transition to known position if necessary 2) transition from one known position to another In case (1) when initial position cannot be determined, enforce withdrawal to COMPACT. In case (2) when destination position is not reached at the end of transition sequence, keep driving with max torque. Panic if high torque transition recovery fails to allow for traces collection Change-Id: I990888baa2f14919793934eb5dbf9d255d2e5c20 Signed-off-by: Konstantin Makariev Reviewed-on: https://gerrit.mot.com/2374097 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Sridhar Vashist Reviewed-by: Qing Chang Submit-Approved: Jira Key --- drivers/misc/drv8424/drv8424.c | 97 +++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 30 deletions(-) diff --git a/drivers/misc/drv8424/drv8424.c b/drivers/misc/drv8424/drv8424.c index f4c26b5b4c53..15b9b58de1f6 100644 --- a/drivers/misc/drv8424/drv8424.c +++ b/drivers/misc/drv8424/drv8424.c @@ -37,8 +37,8 @@ #define MOTOR_HW_CLK_NAME "gcc_gp3" #define MOTOR_DEFAULT_EXPIRE 5000000 //5s timeout -#define MOTOR_DETECT_EXPIRE 10000000 //10s timeout -#define INT_50MS 50 +#define MOTOR_DETECT_EXPIRE 3000000 //3s timeout +#define INT_20MS 20 #define MOTOR_MODE_SPEED 0 #define MOTOR_MODE_STEP 1 @@ -217,8 +217,9 @@ enum regime_idx { SQ_PROLONGED, SQ_SHORT, SQ_TINY, - SQ_MAX, + SQ_SHOW_MAX, SQ_SLOWMO, + SQ_MAX, }; static const char *regime_names[] = { @@ -242,7 +243,7 @@ typedef struct { } motor_stage; /* Default sequences for 2.3pitch */ -static motor_stage initial_data_2p3[SQ_SLOWMO + 1][MAX_STAGE_LEGS] = { +static motor_stage initial_data_2p3[SQ_MAX][MAX_STAGE_LEGS] = { { /* FULL 39mm */ {400,60}, {600,60}, {800,60}, {1000,60}, {1200,60}, {1600,60}, {1700,4400}, }, @@ -255,16 +256,16 @@ static motor_stage initial_data_2p3[SQ_SLOWMO + 1][MAX_STAGE_LEGS] = { { /* TINY 1mm */ {600,60}, {1000,68}, }, - { /* dummy to continue beyond SQ_MAX */ + { /* dummy to continue beyond SQ_SHOW_MAX */ {0, 0}, }, { /* SLOWMO */ - {400,100}, {400,200}, {400,400}, {400,800}, {400,1600}, + {500,200}, {500,400}, {500,800}, {500,1200}, {500,1600}, }, }; /* Sequences for 2.8pitch */ -static motor_stage initial_data_2p8[SQ_SLOWMO + 1][MAX_STAGE_LEGS] = { +static motor_stage initial_data_2p8[SQ_MAX][MAX_STAGE_LEGS] = { { /* FULL 39mm */ {400,60}, {600,60}, {800,60}, {1000,60}, {1200,3780}, }, @@ -277,11 +278,11 @@ static motor_stage initial_data_2p8[SQ_SLOWMO + 1][MAX_STAGE_LEGS] = { { /* TINY 1mm */ {600,108}, }, - { /* dummy to continue beyond SQ_MAX */ + { /* dummy to continue beyond SQ_SHOW_MAX */ {0, 0}, }, { /* SLOWMO */ - {400,100}, {400,200}, {400,400}, {400,800}, {400,1600}, + {400,200}, {400,400}, {400,800}, {400,1200}, {400,1600}, }, }; /* 10,000,000 10,000,000 4,000,000 2,000,000 15,000,000 */ @@ -742,7 +743,7 @@ static void moto_drv8424_set_sensing(motor_device* md, bool en) /* declare sensor querying stage when powered off */ /* when motor powered status will indicate direction */ atomic_set(&md->status, STATUS_QUERYING_POS); - moto_drv8424_cmd_push(md, CMD_STATUS, msecs_to_jiffies(INT_50MS)); + moto_drv8424_cmd_push(md, CMD_STATUS, msecs_to_jiffies(INT_20MS)); } } else { GPIO_OUTPUT_DIR(mc->ptable[MOTOR_ACTIVE], 0); @@ -972,6 +973,15 @@ static __ref int motor_kthread(void *arg) * be unknown even though stepper sequence completed. */ if (md->detect_incomplete) { + if (md->regime == SQ_SLOWMO) { + /* Unrecoverable motor fault. + * Force kernel panic to get a ramdump + */ + dev_warn(md->dev, "forced panic due to motor fault\n"); + BUG_ON(1); + mdelay(20000); + } + /* Recovery from incomplete transition */ moto_drv8424_cmd_push(md, CMD_RECOVERY, 0); dev_warn(md->dev, "position recovery!!!\n"); goto show_stats; @@ -1005,12 +1015,12 @@ static __ref int motor_kthread(void *arg) atomic_set(&md->status, value); moto_drv8424_cmd_push(md, CMD_STATUS, 0); - LOGD("update: status %d, position %d\n", + PARANOIC("update: status %d, position %d\n", atomic_read(&md->status), atomic_read(&md->position)); logtime_show(); show_stats: - LOGD("semaphore=%u samples=%d\n", md->data_ready.count, atomic_read(&md->samples)); + PARANOIC("semaphore=%u samples=%d\n", md->data_ready.count, atomic_read(&md->samples)); atomic_set(&md->samples, 0); } @@ -1067,6 +1077,10 @@ static void motor_set_motion_params(motor_device *md, int start, int end) { int regime = SQ_FULL; + if (start == POS_UNKNOWN || end == POS_UNKNOWN) { + dev_err(md->dev, "unknown src | dest!!!\n"); + } + if (start == POS_EXPANDED) { md->dir = DIR_WITHDRAW; if (end == POS_COMPACT) @@ -1089,6 +1103,11 @@ static void motor_set_motion_params(motor_device *md, int start, int end) regime = SQ_SHORT; } + if (!md->sensors_off && md->detect_incomplete) { + regime = SQ_SLOWMO; + PARANOIC("engage SLOWMO in recovery\n"); + } + moto_drv8424_set_motor_dir(md); moto_drv8424_set_regime(md, regime); } @@ -1117,8 +1136,13 @@ next_stage: if (!moto_drv8424_next_stage(md)) { /* wake up motor thread at the end of sequence */ /* when sensors unavailable */ - if (md->sensors_off || md->detect_incomplete) + if (md->sensors_off || md->detect_incomplete) { + PARANOIC("sequence ended!!! last data: %d %d %d\n", + md->sensor_data[0], + md->sensor_data[1], + md->sensor_data[2]); motor_stop(md, true); + } GPIO_OUTPUT_DIR(md->mc.ptable[MOTOR_STEP], 0); spin_unlock_irqrestore(&md->mlock, flags); return HRTIMER_NORESTART; @@ -1184,7 +1208,7 @@ static enum hrtimer_restart motor_timeout_timer_action(struct hrtimer *h) atomic_set(&md->destination, POS_COMPACT); LOGD("Timeout position detection\n"); } - moto_drv8424_cmd_push(md, CMD_TIMEOUT, INT_50MS); + moto_drv8424_cmd_push(md, CMD_TIMEOUT, msecs_to_jiffies(INT_20MS)); exit: return ret; } @@ -1283,14 +1307,20 @@ static __ref int detection_kthread(void *arg) } } while (position == POS_UNKNOWN); - moto_drv8424_set_sensing(md, false); - /* polling might occur without driving motor - * we need to release kthread that will trigger position change - * and set destination to properly complete detection - */ - atomic_set(&md->destination, position); - atomic_set(&md->stepping, 1); - motor_stop(md, true); + if (!md->cancel_thread) { + /* in case of successful initial position detection */ + /* timeout timer still running, thus need to cancel */ + /* assuming it does not hurt to attempt cancelling */ + /* the timer that has not been armed */ + moto_drv8424_cmd_push(md, CMD_TIMER_STOP, 0); + /* polling might occur without driving motor + * we need to release kthread that will trigger position change + * and set destination to properly complete detection + */ + atomic_set(&md->destination, position); + atomic_set(&md->stepping, 1); + motor_stop(md, true); + } if (position != POS_UNKNOWN) dev_info(md->dev, "detected position: %s\n", position_labels[position]); @@ -1370,7 +1400,7 @@ static void motor_cmd_work(struct work_struct *work) break; case CMD_RECOVERY: case CMD_TIMEOUT: - /* pos & dest depends on timed out operation */ + /* pos & dest depends on recovery cause */ md->power_en = 0; motor_set_motion_params(md, atomic_read(&md->position), atomic_read(&md->destination)); @@ -1457,7 +1487,7 @@ exit: static void moto_drv8424_set_step_freq(motor_device* md, unsigned freq) { if (md->step_freq == freq) { - dev_err(md->dev, "Unchanged the freq, ignore\n"); + dev_dbg(md->dev, "Unchanged the freq, ignore\n"); return; } else if(freq == 0) { dev_err(md->dev, "Invalid frequency, ignore\n"); @@ -1476,7 +1506,7 @@ static int moto_drv8424_set_ceiling(motor_device* md, unsigned ceiling) spin_lock_irqsave(&md->mlock, flags); if (md->step_ceiling == ceiling) { - dev_info(md->dev, "Unchanged the ceiling, ignore\n"); + dev_dbg(md->dev, "Unchanged the ceiling, ignore\n"); ret = -EINVAL; goto exit; } @@ -1826,7 +1856,7 @@ static ssize_t motor_sequencer_store(struct device *dev, struct device_attribute } *next++ = '\0'; if (kstrtouint(buffer, 10, &value) || - (value < 0 || value >= SQ_MAX)) { + (value < 0 || value >= SQ_SHOW_MAX)) { dev_err(dev, "Invalid index: %s\n", buffer); goto exit; } @@ -1878,7 +1908,7 @@ static ssize_t motor_sequencer_show(struct device *dev, struct device_attribute ssize_t blen = 0; unsigned idx, msn; - for (idx = 0; idx < SQ_MAX; idx++) { + for (idx = 0; idx < SQ_SHOW_MAX; idx++) { blen += snprintf(buf + blen, PAGE_SIZE - blen, "regime %s: ", regime_names[idx]); for (msn = 0; msn < MAX_STAGE_LEGS; msn++) { @@ -1902,7 +1932,7 @@ static ssize_t motor_regime_store(struct device *dev, struct device_attribute *a unsigned value; if (kstrtouint(buf, 10, &value) || - (value < SQ_FULL || value >= SQ_MAX)) { + (value < SQ_FULL || value >= SQ_SHOW_MAX)) { dev_err(dev, "Error value: %s\n", buf); return -EINVAL; } @@ -2208,6 +2238,10 @@ static void motor_set_sequencer(motor_device* md) int s, i; for (s = SQ_FULL; s < SQ_MAX; s++) { + PARANOIC("regime %s\n", regime_names[s]); + /* skip dummy */ + if (s == SQ_SHOW_MAX) + continue; if (md->use_2p8_pitch) stages = initial_data_2p8[s]; else @@ -2218,9 +2252,12 @@ static void motor_set_sequencer(motor_device* md) md->sequencer[s][i].freq = (stages+i)->freq; md->sequencer[s][i].ceiling = (stages+i)->ceiling; } - if (md->sensors_off) + PARANOIC("has %d pairs\n", i); + /* skip adding slow down stage if running in no */ + /* sensors mode and for TINY & SLOWMO regimes */ + if (md->sensors_off || s == SQ_TINY || s == SQ_SLOWMO) continue; - if ((s != SQ_TINY) && (++i < MAX_STAGE_LEGS)) { + if (++i < MAX_STAGE_LEGS) { md->sequencer[s][i].freq = 800; md->sequencer[s][i].ceiling = 60; LOGD("added slow down stage to %s\n", regime_names[s]);