mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-11 23:24:22 -04:00
drv8424_mmi: support variable speed sequences
Support for accelerated motion. Only distinct status reported. Added position interface to shutdown motor based on signal from sensors Change-Id: I44f7eeb4b86f84c2542c0c29feec42bb7b346e16 Signed-off-by: Konstantin Makariev <hcv867@motorola.com> Reviewed-on: https://gerrit.mot.com/2231441 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Qing Chang <qing@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
f488925336
commit
9352766163
2 changed files with 215 additions and 328 deletions
|
|
@ -1,215 +0,0 @@
|
|||
&tlmm {
|
||||
drv8424_gpios {
|
||||
drv8424_mode0_low: drv8424_mode0_low {
|
||||
mux {
|
||||
pins = "gpio70";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio70";
|
||||
drive-strength = <2>; /* 2 MA */
|
||||
output-low;
|
||||
};
|
||||
};
|
||||
drv8424_mode0_high: drv8424_mode0_high {
|
||||
mux {
|
||||
pins = "gpio70";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio70";
|
||||
drive-strength = <2>; /* 2 MA */
|
||||
output-high;
|
||||
};
|
||||
};
|
||||
drv8424_mode0_disable: drv8424_mode0_disable {
|
||||
mux {
|
||||
pins = "gpio70";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio70";
|
||||
input-enable;
|
||||
bias-disable;
|
||||
};
|
||||
};
|
||||
|
||||
drv8424_mode1_low: drv8424_mode1_low {
|
||||
mux {
|
||||
pins = "gpio71";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio71";
|
||||
drive-strength = <2>; /* 2 MA */
|
||||
output-low;
|
||||
};
|
||||
};
|
||||
drv8424_mode1_high: drv8424_mode1_high {
|
||||
mux {
|
||||
pins = "gpio71";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio71";
|
||||
drive-strength = <2>; /* 2 MA */
|
||||
output-high;
|
||||
};
|
||||
};
|
||||
drv8424_mode1_disable: drv8424_mode1_disable {
|
||||
mux {
|
||||
pins = "gpio71";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio71";
|
||||
input-enable;
|
||||
bias-disable;
|
||||
};
|
||||
};
|
||||
|
||||
drv8424_t0_low: drv8424_t0_low {
|
||||
mux {
|
||||
pins = "gpio49";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio49";
|
||||
drive-strength = <2>; /* 2 MA */
|
||||
output-low;
|
||||
};
|
||||
};
|
||||
drv8424_t0_high: drv8424_t0_high {
|
||||
mux {
|
||||
pins = "gpio49";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio49";
|
||||
drive-strength = <2>; /* 2 MA */
|
||||
output-high;
|
||||
};
|
||||
};
|
||||
drv8424_t0_disable: drv8424_t0_disable {
|
||||
mux {
|
||||
pins = "gpio49";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio49";
|
||||
input-enable;
|
||||
bias-disable;
|
||||
};
|
||||
};
|
||||
|
||||
drv8424_t1_low: drv8424_t1_low {
|
||||
mux {
|
||||
pins = "gpio33";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio33";
|
||||
drive-strength = <2>; /* 2 MA */
|
||||
output-low;
|
||||
};
|
||||
};
|
||||
drv8424_t1_high: drv8424_t1_high {
|
||||
mux {
|
||||
pins = "gpio33";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio33";
|
||||
drive-strength = <2>; /* 2 MA */
|
||||
output-high;
|
||||
};
|
||||
};
|
||||
drv8424_t1_disable: drv8424_t1_disable {
|
||||
mux {
|
||||
pins = "gpio33";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio33";
|
||||
input-enable;
|
||||
bias-disable;
|
||||
};
|
||||
};
|
||||
|
||||
drv8424_int_default: drv8424_int_default {
|
||||
mux {
|
||||
pins = "gpio57";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio57";
|
||||
drive-strength = <6>;
|
||||
input-enable;
|
||||
bias-disable;
|
||||
};
|
||||
};
|
||||
|
||||
drv8424_clk_active: drv8424_clk_active {
|
||||
mux {
|
||||
pins = "gpio21";
|
||||
function = "gcc_gp2";
|
||||
};
|
||||
config {
|
||||
pins = "gpio21";
|
||||
drive-strength = <2>; /* 2 MA */
|
||||
bias-pull-none;
|
||||
};
|
||||
};
|
||||
drv8424_clk_sleep: drv8424_clk_sleep {
|
||||
mux {
|
||||
pins = "gpio21";
|
||||
function = "gpio";
|
||||
};
|
||||
config {
|
||||
pins = "gpio21";
|
||||
/* drive-strength = <2>; */ /* 2 MA */
|
||||
/* bias-pull-down; */
|
||||
input-enable;
|
||||
bias-disable;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&soc {
|
||||
moto_drv8424_support {
|
||||
compatible = "moto,drv8424";
|
||||
status = "ok"
|
||||
pinctrl-names = "m0_low", "m0_high", "m0_disable",
|
||||
"m1_low", "m1_high", "m1_disable",
|
||||
"t0_low", "t0_high", "t0_disable",
|
||||
"t1_low", "t1_high", "t1_disable",
|
||||
"drv8424_int_default",
|
||||
"drv8424_clk_active", "drv8424_clk_sleep";
|
||||
pinctrl-0 = <&drv8424_mode0_low>;
|
||||
pinctrl-1 = <&drv8424_mode0_high>;
|
||||
pinctrl-2 = <&drv8424_mode0_disable>;
|
||||
pinctrl-3 = <&drv8424_mode1_low>;
|
||||
pinctrl-4 = <&drv8424_mode1_high>;
|
||||
pinctrl-5 = <&drv8424_mode1_disable>;
|
||||
pinctrl-6 = <&drv8424_t0_low>;
|
||||
pinctrl-7 = <&drv8424_t0_high>;
|
||||
pinctrl-8 = <&drv8424_t0_disable>;
|
||||
pinctrl-9 = <&drv8424_t1_low>;
|
||||
pinctrl-10 = <&drv8424_t1_high>;
|
||||
pinctrl-11 = <&drv8424_t1_disable>;
|
||||
pinctrl-12 = <&drv8424_int_default>;
|
||||
pinctrl-13 = <&drv8424_clk_active>;
|
||||
pinctrl-14 = <&drv8424_clk_sleep>;
|
||||
interrupt-parent = <&tlmm>;
|
||||
interrupts = <57 0x2002>;
|
||||
drv8424-gpios = <52 57 21 32 30 51 29 50 49 33>;
|
||||
drv8424-gpios-cells = <10>;
|
||||
drv8424-max-freq = <250000>;
|
||||
clocks = <&clock_gcc 36>;
|
||||
clock-names = "gcc_gp2";
|
||||
vdd-supply = <&pm6150_l13>;
|
||||
enable-hw-clock;
|
||||
power-default-off;
|
||||
};
|
||||
};
|
||||
|
|
@ -58,9 +58,7 @@ static const char *position_labels[] = {
|
|||
|
||||
enum status_id {
|
||||
STATUS_UNKNOWN,
|
||||
STATUS_STOPPED_COMPACT,
|
||||
STATUS_STOPPED_EXPANDED,
|
||||
STATUS_STOPPED_PEEK,
|
||||
STATUS_STOPPED,
|
||||
STATUS_MOVING_IN,
|
||||
STATUS_MOVING_OUT,
|
||||
};
|
||||
|
|
@ -176,6 +174,47 @@ static const char* const pins_state[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
enum regime_idx {
|
||||
SQ_FULL,
|
||||
SQ_SHORTENED,
|
||||
SQ_SHORT,
|
||||
SQ_TINY,
|
||||
SQ_MAX
|
||||
};
|
||||
|
||||
static const char *regime_names[SQ_MAX] = {
|
||||
"FULL",
|
||||
"SHORTENED",
|
||||
"SHORT",
|
||||
"TINY"
|
||||
};
|
||||
|
||||
/* PPS Pulses
|
||||
stage 1: 400 24
|
||||
stage 2: 1400 56
|
||||
stage 3: 3000 6252
|
||||
stage 4: 2000 12
|
||||
*/
|
||||
#define MAX_STAGE_LEGS 10
|
||||
typedef struct {
|
||||
unsigned freq, ceiling;
|
||||
} motor_stage;
|
||||
|
||||
static motor_stage initial_data[SQ_MAX][MAX_STAGE_LEGS] = {
|
||||
{ /* FULL 44mm */
|
||||
{400,24}, {1400,56}, {3000,6252}, {2000,12}
|
||||
},
|
||||
{ /* SHORTENED 39mm */
|
||||
{400,24}, {1400,56}, {3000,5530}, {2000,12}
|
||||
},
|
||||
{ /* SHORT 5mm */
|
||||
{400,24}, {1400,56}, {3000,630}, {2000,12}
|
||||
},
|
||||
{ /* TINY 1mm */
|
||||
{400,24}, {1400,56}, {2000,65}
|
||||
}
|
||||
};
|
||||
|
||||
#define MAX_GPIOS MOTOR_UNKNOWN
|
||||
typedef struct motor_control {
|
||||
struct regulator *vdd;
|
||||
|
|
@ -184,7 +223,7 @@ typedef struct motor_control {
|
|||
struct pinctrl* pins;
|
||||
struct pinctrl_state *pin_state[PINS_END];
|
||||
const char* const * plabels;
|
||||
}motor_control;
|
||||
} motor_control;
|
||||
|
||||
#define CLOCK_NAME_LEN 16
|
||||
typedef struct motor_device {
|
||||
|
|
@ -217,6 +256,8 @@ typedef struct motor_device {
|
|||
unsigned time_out;
|
||||
unsigned half;
|
||||
unsigned stage, max_stages;
|
||||
unsigned regime;
|
||||
motor_stage sequencer[SQ_MAX][MAX_STAGE_LEGS];
|
||||
bool double_edge;
|
||||
bool hw_clock;
|
||||
bool power_default_off;
|
||||
|
|
@ -237,7 +278,6 @@ typedef struct motor_device {
|
|||
|
||||
static int set_pinctrl_state(motor_device* md, unsigned state_index);
|
||||
static void moto_drv8424_set_step_freq(motor_device* md, unsigned freq);
|
||||
static bool motor_drive_stage_init(motor_device* md, int step_count);
|
||||
|
||||
static ktime_t adapt_time_helper(ktime_t usec)
|
||||
{
|
||||
|
|
@ -547,7 +587,7 @@ static void moto_drv8424_set_power_en(motor_device* md)
|
|||
usleep_range(500, 1000);
|
||||
/* signal sensor hub to start/stop sampling hall effect */
|
||||
GPIO_OUTPUT_DIR(mc->ptable[MOTOR_ACTIVE], md->power_en);
|
||||
LOGD("gpios BOOST & ACTIVE updated\n");
|
||||
LOGD("gpios BOOST & ACTIVE set: %u\n", md->power_en);
|
||||
}
|
||||
|
||||
//Power sequence: PowerEn On->nSleep On->nSleep Off->PowerEn Off
|
||||
|
|
@ -580,6 +620,28 @@ static int moto_drv8424_set_power(motor_device* md, unsigned power)
|
|||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void moto_drv8424_set_regime(motor_device *md, unsigned regime)
|
||||
{
|
||||
unsigned msn;
|
||||
unsigned long flags;
|
||||
|
||||
for (msn = 0; msn < MAX_STAGE_LEGS; msn++) {
|
||||
if (md->sequencer[regime][msn].freq && md->sequencer[regime][msn].ceiling)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&md->mlock, flags);
|
||||
md->regime = regime;
|
||||
md->stage = 0;
|
||||
md->max_stages = msn;
|
||||
spin_unlock_irqrestore(&md->mlock, flags);
|
||||
|
||||
dev_info(md->dev, "Set active regime: %s, stages # %u\n",
|
||||
regime_names[md->regime], msn);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int moto_drv8424_enable_clk(motor_device* md, bool en)
|
||||
{
|
||||
|
|
@ -588,31 +650,45 @@ static int moto_drv8424_enable_clk(motor_device* md, bool en)
|
|||
#endif
|
||||
#ifdef MOTOR_SLOT_DBG
|
||||
static ktime_t timesA[20];
|
||||
static unsigned slot;
|
||||
|
||||
static void inline logtime_store(motor_device* md)
|
||||
static void inline logtime_store(void)
|
||||
{
|
||||
if ((md->slot + 1) < sizeof(timesA)/sizeof(timesA[0])) {
|
||||
timesA[md->slot++] = ktime_get();
|
||||
if ((slot + 1) < sizeof(timesA)/sizeof(timesA[0])) {
|
||||
timesA[slot++] = ktime_get();
|
||||
}
|
||||
}
|
||||
|
||||
static void logtime_show(motor_device* md)
|
||||
static void logtime_show(void)
|
||||
{
|
||||
int i;
|
||||
ktime_t diff;
|
||||
|
||||
for (i = 1; i < md->slot; i++) {
|
||||
if (!slot)
|
||||
return;
|
||||
|
||||
for (i = 1; i < slot; i++) {
|
||||
diff = ktime_sub(timesA[i], timesA[i-1]);
|
||||
pr_err("step[%d]=%lldus\n", i, ktime_to_us(diff));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
static void moto_drv8424_drive_init(motor_device* md, int step_count)
|
||||
{
|
||||
md->slot = 0U;
|
||||
atomic_set(&md->stepping, 1);
|
||||
atomic_set(&md->step_count, step_count);
|
||||
|
||||
static void inline logtime_reset(void)
|
||||
{
|
||||
slot = 0U;
|
||||
}
|
||||
#else
|
||||
#define logtime_store()
|
||||
#define logtime_show()
|
||||
#define logtime_reset()
|
||||
#endif
|
||||
|
||||
static void moto_drv8424_drive_stage_init(motor_device* md)
|
||||
{
|
||||
logtime_reset();
|
||||
|
||||
atomic_set(&md->stepping, 1);
|
||||
atomic_set(&md->step_count, 1);
|
||||
md->double_edge = false;
|
||||
md->half = md->step_period >> 1;
|
||||
md->level = 1;
|
||||
|
|
@ -621,22 +697,41 @@ static void moto_drv8424_drive_init(motor_device* md, int step_count)
|
|||
|| md->mode == STEP_32_BOTH_EDEG) {
|
||||
md->double_edge = true;
|
||||
}
|
||||
atomic_set(&md->status, md->dir ? STATUS_MOVING_IN : STATUS_MOVING_OUT);
|
||||
}
|
||||
|
||||
static bool moto_drv8424_next_stage(motor_device* md)
|
||||
{
|
||||
unsigned freq;
|
||||
motor_stage *ms;
|
||||
|
||||
if (++md->stage > md->max_stages) {
|
||||
md->max_stages = 0;
|
||||
md->stage = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
logtime_show();
|
||||
|
||||
ms = &md->sequencer[md->regime][md->stage - 1];
|
||||
freq = ms->freq;
|
||||
md->step_ceiling = ms->ceiling;
|
||||
moto_drv8424_set_step_freq(md, freq);
|
||||
moto_drv8424_drive_stage_init(md);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int moto_drv8424_drive_sequencer(motor_device* md)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&md->mlock, flags);
|
||||
moto_drv8424_drive_init(md, 0);
|
||||
spin_unlock_irqrestore(&md->mlock, flags);
|
||||
LOGD("ceiling %lu, freq %uHz period %luns, half %uns\n", md->step_ceiling, md->step_freq, md->step_period, md->half);
|
||||
moto_drv8424_next_stage(md);
|
||||
moto_drv8424_set_motor_torque(md);
|
||||
moto_drv8424_set_motor_dir(md);
|
||||
moto_drv8424_set_motor_mode(md);
|
||||
moto_drv8424_set_motor_opmode(md);
|
||||
LOGD("sequencer init done\n");
|
||||
atomic_set(&md->status, md->dir ? STATUS_MOVING_IN : STATUS_MOVING_OUT);
|
||||
LOGD("sequencer init: stages %u ceiling %lu, freq %uHz period %luns, half %uns\n",
|
||||
md->max_stages, md->step_ceiling, md->step_freq, md->step_period, md->half);
|
||||
|
||||
if(atomic_read(&md->stepping)) {
|
||||
motor_control* mc = &md->mc;
|
||||
|
||||
|
|
@ -644,9 +739,7 @@ static int moto_drv8424_drive_sequencer(motor_device* md)
|
|||
GPIO_OUTPUT_DIR(mc->ptable[MOTOR_STEP], md->level);
|
||||
atomic_inc(&md->step_count);
|
||||
hrtimer_start(&md->stepping_timer, adapt_time_helper(md->half), HRTIMER_MODE_REL);
|
||||
#ifdef MOTOR_SLOT_DBG
|
||||
logtime_store(md);
|
||||
#endif
|
||||
logtime_store();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -674,7 +767,7 @@ static __ref int motor_kthread(void *arg)
|
|||
|
||||
sched_setscheduler(current, SCHED_FIFO, ¶m);
|
||||
while (!kthread_should_stop()) {
|
||||
dev_info(md->dev, "wait for event\n");
|
||||
LOGD("wait for event\n");
|
||||
do {
|
||||
ret = wait_event_interruptible(md->sync_complete,
|
||||
md->user_sync_complete || kthread_should_stop());
|
||||
|
|
@ -689,7 +782,7 @@ static __ref int motor_kthread(void *arg)
|
|||
dev_info(md->dev, "vdd power off\n");
|
||||
moto_drv8424_set_regulator_power(md, false);
|
||||
}
|
||||
|
||||
#if 0
|
||||
switch (atomic_read(&md->position)) {
|
||||
case POS_COMPACT:
|
||||
value = STATUS_STOPPED_COMPACT;
|
||||
|
|
@ -702,13 +795,13 @@ static __ref int motor_kthread(void *arg)
|
|||
break;
|
||||
default: value = STATUS_UNKNOWN;
|
||||
}
|
||||
#endif
|
||||
value = STATUS_STOPPED;
|
||||
atomic_set(&md->status, value);
|
||||
dev_info(md->dev, "status %d, position %d\n",
|
||||
LOGD("status %d, position %d\n",
|
||||
atomic_read(&md->status), atomic_read(&md->position));
|
||||
sysfs_notify(&md->dev->kobj, NULL, "status");
|
||||
#ifdef MOTOR_SLOT_DBG
|
||||
logtime_show(md);
|
||||
#endif
|
||||
logtime_show();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -756,12 +849,8 @@ static enum hrtimer_restart motor_stepping_timer_action(struct hrtimer *h)
|
|||
|
||||
spin_lock_irqsave(&md->mlock, flags);
|
||||
|
||||
if(!atomic_read(&md->stepping)) {
|
||||
motor_stop(md, true);
|
||||
GPIO_OUTPUT_DIR(md->mc.ptable[MOTOR_STEP], 0);
|
||||
spin_unlock_irqrestore(&md->mlock, flags);
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
if(!atomic_read(&md->stepping))
|
||||
goto next_stage;
|
||||
|
||||
md->level = !md->level;
|
||||
GPIO_OUTPUT_DIR(md->mc.ptable[MOTOR_STEP], md->level);
|
||||
|
|
@ -771,12 +860,13 @@ static enum hrtimer_restart motor_stepping_timer_action(struct hrtimer *h)
|
|||
} else if(md->level) {
|
||||
atomic_inc(&md->step_count);
|
||||
}
|
||||
#ifdef MOTOR_SLOT_DBG
|
||||
logtime_store(md); /* log timestamp */
|
||||
#endif
|
||||
|
||||
logtime_store();
|
||||
|
||||
if(md->step_ceiling && atomic_read(&md->step_count) > md->step_ceiling) {
|
||||
next_stage:
|
||||
/* multi stage sequence */
|
||||
if (!(md->max_stages && motor_drive_stage_init(md, 1))) {
|
||||
if (!moto_drv8424_next_stage(md)) {
|
||||
motor_stop(md, true);
|
||||
GPIO_OUTPUT_DIR(md->mc.ptable[MOTOR_STEP], 0);
|
||||
spin_unlock_irqrestore(&md->mlock, flags);
|
||||
|
|
@ -1176,112 +1266,117 @@ exit:
|
|||
return len;
|
||||
}
|
||||
|
||||
/* PPS Pulses
|
||||
stage 1: 400 24
|
||||
stage 2: 1400 56
|
||||
stage 3: 3000 6252
|
||||
stage 4: 2000 12
|
||||
*/
|
||||
#define MAX_STAGE_LEGS 10
|
||||
struct stage_data {
|
||||
unsigned freq, ceiling;
|
||||
} multi_stage_sequencer[MAX_STAGE_LEGS];
|
||||
|
||||
static int motor_stage_sequence_init(char *buffer, size_t len, motor_device* md)
|
||||
{
|
||||
char *next, *pair = buffer;
|
||||
int msn;
|
||||
unsigned freq, ceiling;
|
||||
|
||||
for (msn = 0; pair && msn < MAX_STAGE_LEGS; msn++, pair = next ) {
|
||||
next = strnchr(pair, len, ' ');
|
||||
if (next) {
|
||||
*next++ = '\0';
|
||||
len -= strlen(pair);
|
||||
}
|
||||
if (sscanf(pair, "%u:%u", &freq, &ceiling) == 2) {
|
||||
multi_stage_sequencer[msn].freq = freq;
|
||||
multi_stage_sequencer[msn].ceiling = ceiling;
|
||||
dev_info(md->dev, "stage[%d]: freq=%u, ceiling=%u\n", msn, freq, ceiling);
|
||||
}
|
||||
}
|
||||
|
||||
return msn;
|
||||
}
|
||||
|
||||
static bool motor_drive_stage_init(motor_device* md, int step_count)
|
||||
{
|
||||
unsigned freq;
|
||||
|
||||
if (++md->stage > md->max_stages) {
|
||||
md->max_stages = 0;
|
||||
md->stage = 0;
|
||||
return false;
|
||||
}
|
||||
#ifdef MOTOR_SLOT_DBG
|
||||
if (md->slot)
|
||||
logtime_show(md);
|
||||
#endif
|
||||
freq = multi_stage_sequencer[md->stage - 1].freq;
|
||||
md->step_ceiling = multi_stage_sequencer[md->stage - 1].ceiling;
|
||||
|
||||
//LOGD("stage %u, freq %u, ceiling %lu\n", md->stage, freq, md->step_ceiling);
|
||||
//FIXME the next function calls spinlock!!!
|
||||
moto_drv8424_set_step_freq(md, freq);
|
||||
moto_drv8424_drive_init(md, step_count);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* main interface to control motor via sysfs */
|
||||
/* valid parameter values: 0 - roll in, 1 - roll out */
|
||||
static ssize_t motor_command_store(struct device *dev, struct device_attribute *attr,
|
||||
/* store new motor sequencer */
|
||||
/* Format: index freq0:ceiling0 [... freqN:ceilingN] */
|
||||
/* Example: 0 400:24 1400:56 3000:6252 2000:12 */
|
||||
static ssize_t motor_sequencer_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
motor_device* md = (motor_device*)dev_get_drvdata(dev);
|
||||
//unsigned long flags;
|
||||
char *buffer;
|
||||
|
||||
if(md->faulting) {
|
||||
dev_err(dev, "Device faulting\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
char *buffer, *next, *pair;
|
||||
unsigned msn = 0;
|
||||
unsigned value, idx, freq, ceiling;
|
||||
|
||||
buffer = kmalloc(len + 1, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
strlcpy(buffer, buf, len);
|
||||
buffer[len + 1] = '\0';
|
||||
md->max_stages = motor_stage_sequence_init(buffer, len, md);
|
||||
|
||||
next = strnchr(buffer, len, ' ');
|
||||
if(kstrtouint(buffer, 10, &value) ||
|
||||
(value < 0 || value >= SQ_MAX)) {
|
||||
dev_err(dev, "Invalid index: %s\n", buffer);
|
||||
goto exit;
|
||||
}
|
||||
idx = value;
|
||||
for (msn = 0, pair = next; pair && msn < MAX_STAGE_LEGS; msn++, pair = next ) {
|
||||
next = strnchr(pair, len, ' ');
|
||||
if (next) {
|
||||
*next++ = '\0';
|
||||
len -= strlen(pair);
|
||||
}
|
||||
if (sscanf(pair, "%u:%u", &freq, &ceiling) == 2) {
|
||||
md->sequencer[idx][msn].freq = freq;
|
||||
md->sequencer[idx][msn].ceiling = ceiling;
|
||||
dev_info(md->dev, "[%u][%u]: freq=%u, ceiling=%u\n", idx, msn, freq, ceiling);
|
||||
}
|
||||
}
|
||||
exit:
|
||||
md->max_stages = msn;
|
||||
kfree(buffer);
|
||||
|
||||
if (md->max_stages == 0) {
|
||||
dev_err(dev, "Error value: %s\n", buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOGD("max_stages %u\n", md->max_stages);
|
||||
//spin_lock_irqsave(&md->mlock, flags);
|
||||
/* hrtimer controlled stepper mechanism */
|
||||
md->stage = 0;
|
||||
motor_drive_stage_init(md, 0);
|
||||
//spin_unlock_irqrestore(&md->mlock, flags);
|
||||
moto_drv8424_drive_sequencer(md);
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t motor_sequencer_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
motor_device* md = (motor_device*)dev_get_drvdata(dev);
|
||||
ssize_t blen = 0;
|
||||
unsigned idx, msn;
|
||||
|
||||
for (idx = 0; idx < SQ_MAX; idx++) {
|
||||
blen += snprintf(buf + blen, PAGE_SIZE - blen, "regime %s: ",
|
||||
regime_names[idx]);
|
||||
for (msn = 0; msn < MAX_STAGE_LEGS; msn++) {
|
||||
if (md->sequencer[idx][msn].freq == 0 &&
|
||||
md->sequencer[idx][msn].ceiling == 0)
|
||||
continue;
|
||||
|
||||
blen += snprintf(buf + blen, PAGE_SIZE - blen, "%u:%u ",
|
||||
md->sequencer[idx][msn].freq,
|
||||
md->sequencer[idx][msn].ceiling);
|
||||
}
|
||||
blen += snprintf(buf + blen, PAGE_SIZE - blen, "\n");
|
||||
}
|
||||
|
||||
return blen;
|
||||
}
|
||||
|
||||
static ssize_t motor_regime_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
motor_device* md = (motor_device*)dev_get_drvdata(dev);
|
||||
unsigned value;
|
||||
|
||||
if(kstrtouint(buf, 10, &value) ||
|
||||
(value < SQ_FULL || value >= SQ_MAX)) {
|
||||
dev_err(dev, "Error value: %s\n", buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
moto_drv8424_set_regime(md, value);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t motor_regime_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
motor_device* md = (motor_device*)dev_get_drvdata(dev);
|
||||
|
||||
return snprintf(buf, 20, "%s\n", regime_names[md->regime]);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP, motor_enable_show, motor_enable_store);
|
||||
static DEVICE_ATTR(dir, S_IRUGO|S_IWUSR|S_IWGRP, motor_dir_show, motor_dir_store);
|
||||
static DEVICE_ATTR(step, S_IRUGO|S_IWUSR|S_IWGRP, motor_step_show, motor_step_store);
|
||||
static DEVICE_ATTR(ceiling, S_IRUGO|S_IWUSR|S_IWGRP, motor_ceiling_show, motor_ceiling_store);
|
||||
static DEVICE_ATTR(mode, S_IRUGO|S_IWUSR|S_IWGRP, motor_mode_show, motor_mode_store);
|
||||
static DEVICE_ATTR(sequencer, S_IRUGO|S_IWUSR|S_IWGRP, motor_sequencer_show, motor_sequencer_store);
|
||||
static DEVICE_ATTR(torque, S_IRUGO|S_IWUSR|S_IWGRP, motor_torque_show, motor_torque_store);
|
||||
static DEVICE_ATTR(time_out, S_IRUGO|S_IWUSR|S_IWGRP, motor_time_out_show, motor_time_out_store);
|
||||
static DEVICE_ATTR(reset, S_IRUGO|S_IWUSR|S_IWGRP, NULL, motor_reset_store);
|
||||
static DEVICE_ATTR(command, S_IRUGO|S_IWUSR|S_IWGRP, NULL, motor_command_store);
|
||||
static DEVICE_ATTR(regime, S_IRUGO|S_IWUSR|S_IWGRP, motor_regime_show, motor_regime_store);
|
||||
|
||||
#define ATTRS_STATIC 7
|
||||
#define ATTRS_MAX 10
|
||||
#define ATTRS_STATIC 8
|
||||
#define ATTRS_MAX 11
|
||||
|
||||
static int last_idx = ATTRS_STATIC;
|
||||
|
||||
|
|
@ -1292,7 +1387,8 @@ static struct attribute *motor_attributes[ATTRS_MAX + 1] = {
|
|||
&dev_attr_ceiling.attr,
|
||||
&dev_attr_reset.attr,
|
||||
&dev_attr_time_out.attr,
|
||||
&dev_attr_command.attr,
|
||||
&dev_attr_regime.attr,
|
||||
&dev_attr_sequencer.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -1427,7 +1523,7 @@ static int moto_drv8424_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device* dev = &pdev->dev;
|
||||
motor_device* md;
|
||||
int i = MOTOR_POWER_EN;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
md = kzalloc(sizeof(motor_device), GFP_KERNEL);
|
||||
|
|
@ -1444,6 +1540,10 @@ static int moto_drv8424_probe(struct platform_device *pdev)
|
|||
moto_drv8424_set_step_freq(md, DEFAULT_STEP_FREQ);
|
||||
md->time_out = MOTOR_DEFAULT_EXPIRE;
|
||||
|
||||
/* populate sequencer with initial values */
|
||||
for (i = SQ_FULL; i < SQ_MAX; i++)
|
||||
memcpy(md->sequencer[i], initial_data[i], sizeof(initial_data[i]));
|
||||
|
||||
/* assign default values for optional parameters */
|
||||
md->mode = FULL_STEP;
|
||||
md->torque = TORQUE_FULL;
|
||||
|
|
@ -1477,8 +1577,9 @@ static int moto_drv8424_probe(struct platform_device *pdev)
|
|||
|
||||
md->user_sync_complete = false;
|
||||
init_waitqueue_head(&md->sync_complete);
|
||||
atomic_set(&md->position, POS_COMPACT);
|
||||
atomic_set(&md->status, STATUS_STOPPED_COMPACT);
|
||||
atomic_set(&md->position, POS_UNKNOWN);
|
||||
//atomic_set(&md->status, STATUS_STOPPED_COMPACT);
|
||||
atomic_set(&md->status, STATUS_STOPPED);
|
||||
md->motor_task = kthread_create(motor_kthread, md, "motor_task");
|
||||
if (IS_ERR(md->motor_task)) {
|
||||
ret = PTR_ERR(md->motor_task);
|
||||
|
|
@ -1545,6 +1646,7 @@ static int moto_drv8424_probe(struct platform_device *pdev)
|
|||
/*Here motor can work, but have not irq*/
|
||||
dev_info(dev, "Failed to set device irq\n");
|
||||
}
|
||||
|
||||
dev_info(dev, "Success init device\n");
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue