mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 21:59:12 -04:00
misc: cs40l2x: Add nested loops to playback queue
Added the ability to group multiple segments together and repeat them multiple times within the queue. Change-Id: I0eb3a4931092961e8ac332ee5f4d5507a0128c20 Signed-off-by: Jeff LaBundy <jeff.labundy@cirrus.com> Signed-off-by: Ravi Vembu <raviv@motorola.com>
This commit is contained in:
parent
869f552313
commit
cc094c82cf
2 changed files with 155 additions and 73 deletions
|
|
@ -142,7 +142,6 @@ static ssize_t cs40l2x_cp_trigger_queue_show(struct device *dev,
|
|||
{
|
||||
struct cs40l2x_private *cs40l2x = cs40l2x_get_private(dev);
|
||||
ssize_t len = 0;
|
||||
unsigned int tag, mag;
|
||||
int i;
|
||||
|
||||
if (cs40l2x->pbq_depth == 0)
|
||||
|
|
@ -150,25 +149,29 @@ static ssize_t cs40l2x_cp_trigger_queue_show(struct device *dev,
|
|||
|
||||
mutex_lock(&cs40l2x->lock);
|
||||
|
||||
for (i = 0; i < cs40l2x->pbq_depth - 1; i++) {
|
||||
tag = cs40l2x->pbq_pairs[i].tag;
|
||||
mag = cs40l2x->pbq_pairs[i].mag;
|
||||
for (i = 0; i < cs40l2x->pbq_depth; i++) {
|
||||
switch (cs40l2x->pbq_pairs[i].tag) {
|
||||
case CS40L2X_PBQ_TAG_SILENCE:
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%d",
|
||||
cs40l2x->pbq_pairs[i].mag);
|
||||
break;
|
||||
case CS40L2X_PBQ_TAG_START:
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "!!");
|
||||
break;
|
||||
case CS40L2X_PBQ_TAG_STOP:
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%d!!",
|
||||
cs40l2x->pbq_pairs[i].repeat);
|
||||
break;
|
||||
default:
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%d.%d",
|
||||
cs40l2x->pbq_pairs[i].tag,
|
||||
cs40l2x->pbq_pairs[i].mag);
|
||||
}
|
||||
|
||||
if (tag)
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%d.%d, ",
|
||||
tag, mag);
|
||||
else
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%d, ",
|
||||
mag);
|
||||
if (i < (cs40l2x->pbq_depth - 1))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, ", ");
|
||||
}
|
||||
|
||||
tag = cs40l2x->pbq_pairs[i].tag;
|
||||
mag = cs40l2x->pbq_pairs[i].mag;
|
||||
if (tag)
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%d.%d", tag, mag);
|
||||
else
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%d", mag);
|
||||
|
||||
switch (cs40l2x->pbq_repeat) {
|
||||
case -1:
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, ", ~\n");
|
||||
|
|
@ -195,7 +198,8 @@ static ssize_t cs40l2x_cp_trigger_queue_store(struct device *dev,
|
|||
char *pbq_seg_alloc, *pbq_seg, *pbq_seg_tok;
|
||||
size_t pbq_seg_len;
|
||||
unsigned int pbq_depth = 0;
|
||||
unsigned int val;
|
||||
unsigned int val, num_empty;
|
||||
int pbq_marker = -1;
|
||||
int ret;
|
||||
|
||||
pbq_str_alloc = kzalloc(count, GFP_KERNEL);
|
||||
|
|
@ -259,22 +263,68 @@ static ssize_t cs40l2x_cp_trigger_queue_store(struct device *dev,
|
|||
|
||||
/* repetition specifier */
|
||||
} else if (strnchr(pbq_seg, CS40L2X_PBQ_SEG_LEN_MAX, '!')) {
|
||||
if (cs40l2x->pbq_repeat) {
|
||||
ret = -EINVAL;
|
||||
goto err_mutex;
|
||||
}
|
||||
val = 0;
|
||||
num_empty = 0;
|
||||
|
||||
pbq_seg_tok = strsep(&pbq_seg, "!");
|
||||
|
||||
ret = kstrtou32(pbq_seg_tok, 10, &val);
|
||||
if (ret) {
|
||||
while (pbq_seg_tok) {
|
||||
if (strnlen(pbq_seg_tok,
|
||||
CS40L2X_PBQ_SEG_LEN_MAX)) {
|
||||
ret = kstrtou32(pbq_seg_tok, 10, &val);
|
||||
if (ret) {
|
||||
ret = -EINVAL;
|
||||
goto err_mutex;
|
||||
}
|
||||
if (val > CS40L2X_PBQ_REPEAT_MAX) {
|
||||
ret = -EINVAL;
|
||||
goto err_mutex;
|
||||
}
|
||||
} else {
|
||||
num_empty++;
|
||||
}
|
||||
|
||||
pbq_seg_tok = strsep(&pbq_seg, "!");
|
||||
}
|
||||
|
||||
/* number of empty tokens reveals specifier type */
|
||||
switch (num_empty) {
|
||||
case 1: /* outer loop: "n!" or "!n" */
|
||||
if (cs40l2x->pbq_repeat) {
|
||||
ret = -EINVAL;
|
||||
goto err_mutex;
|
||||
}
|
||||
cs40l2x->pbq_repeat = val;
|
||||
break;
|
||||
|
||||
case 2: /* inner loop stop: "n!!" or "!!n" */
|
||||
if (pbq_marker < 0) {
|
||||
ret = -EINVAL;
|
||||
goto err_mutex;
|
||||
}
|
||||
|
||||
cs40l2x->pbq_pairs[pbq_depth].tag =
|
||||
CS40L2X_PBQ_TAG_STOP;
|
||||
cs40l2x->pbq_pairs[pbq_depth].mag = pbq_marker;
|
||||
cs40l2x->pbq_pairs[pbq_depth++].repeat = val;
|
||||
pbq_marker = -1;
|
||||
break;
|
||||
|
||||
case 3: /* inner loop start: "!!" */
|
||||
if (pbq_marker >= 0) {
|
||||
ret = -EINVAL;
|
||||
goto err_mutex;
|
||||
}
|
||||
|
||||
cs40l2x->pbq_pairs[pbq_depth].tag =
|
||||
CS40L2X_PBQ_TAG_START;
|
||||
pbq_marker = pbq_depth++;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err_mutex;
|
||||
}
|
||||
if (val > CS40L2X_PBQ_REPEAT_MAX) {
|
||||
ret = -EINVAL;
|
||||
goto err_mutex;
|
||||
}
|
||||
cs40l2x->pbq_repeat = val;
|
||||
|
||||
/* loop specifier */
|
||||
} else if (strnchr(pbq_seg, CS40L2X_PBQ_SEG_LEN_MAX, '~')) {
|
||||
|
|
@ -286,7 +336,8 @@ static ssize_t cs40l2x_cp_trigger_queue_store(struct device *dev,
|
|||
|
||||
/* duration specifier */
|
||||
} else {
|
||||
cs40l2x->pbq_pairs[pbq_depth].tag = 0;
|
||||
cs40l2x->pbq_pairs[pbq_depth].tag =
|
||||
CS40L2X_PBQ_TAG_SILENCE;
|
||||
|
||||
ret = kstrtou32(pbq_seg, 10, &val);
|
||||
if (ret) {
|
||||
|
|
@ -956,62 +1007,83 @@ static int cs40l2x_pbq_pair_launch(struct cs40l2x_private *cs40l2x)
|
|||
struct regmap *regmap = cs40l2x->regmap;
|
||||
unsigned int dig_scale = cs40l2x->dig_scale;
|
||||
unsigned int tag, mag;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
/* this function expects to be called from a locked worker function */
|
||||
if (!mutex_is_locked(&cs40l2x->lock))
|
||||
return -EACCES;
|
||||
|
||||
if (cs40l2x->pbq_index == cs40l2x->pbq_depth) {
|
||||
cs40l2x->pbq_index = 0;
|
||||
do {
|
||||
/* restart queue as necessary */
|
||||
if (cs40l2x->pbq_index == cs40l2x->pbq_depth) {
|
||||
cs40l2x->pbq_index = 0;
|
||||
for (i = 0; i < cs40l2x->pbq_depth; i++)
|
||||
cs40l2x->pbq_pairs[i].remain =
|
||||
cs40l2x->pbq_pairs[i].repeat;
|
||||
|
||||
switch (cs40l2x->pbq_remain) {
|
||||
case -1:
|
||||
/* loop until stopped */
|
||||
switch (cs40l2x->pbq_remain) {
|
||||
case -1:
|
||||
/* loop until stopped */
|
||||
break;
|
||||
case 0:
|
||||
/* queue is finished */
|
||||
cs40l2x->cp_trailer_index = 0;
|
||||
cs40l2x->pbq_state = CS40L2X_PBQ_STATE_IDLE;
|
||||
|
||||
ret = cs40l2x_dig_scale_set(cs40l2x, dig_scale);
|
||||
return ret;
|
||||
default:
|
||||
/* loop once more */
|
||||
cs40l2x->pbq_remain--;
|
||||
}
|
||||
}
|
||||
|
||||
tag = cs40l2x->pbq_pairs[cs40l2x->pbq_index].tag;
|
||||
mag = cs40l2x->pbq_pairs[cs40l2x->pbq_index].mag;
|
||||
|
||||
switch (tag) {
|
||||
case CS40L2X_PBQ_TAG_SILENCE:
|
||||
hrtimer_start(&cs40l2x->pbq_timer,
|
||||
ktime_set(mag / 1000,
|
||||
(mag % 1000) * 1000000),
|
||||
HRTIMER_MODE_REL);
|
||||
cs40l2x->pbq_state = CS40L2X_PBQ_STATE_SILENT;
|
||||
cs40l2x->pbq_index++;
|
||||
break;
|
||||
case 0:
|
||||
/* queue is finished */
|
||||
cs40l2x->cp_trailer_index = 0;
|
||||
cs40l2x->pbq_state = CS40L2X_PBQ_STATE_IDLE;
|
||||
case CS40L2X_PBQ_TAG_START:
|
||||
cs40l2x->pbq_index++;
|
||||
break;
|
||||
case CS40L2X_PBQ_TAG_STOP:
|
||||
if (cs40l2x->pbq_pairs[cs40l2x->pbq_index].remain) {
|
||||
cs40l2x->pbq_pairs[cs40l2x->pbq_index].remain--;
|
||||
cs40l2x->pbq_index = mag;
|
||||
} else {
|
||||
cs40l2x->pbq_index++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dig_scale += cs40l2x_pbq_scale[mag].dig_scale;
|
||||
if (dig_scale > CS40L2X_DIG_SCALE_MAX)
|
||||
dig_scale = CS40L2X_DIG_SCALE_MAX;
|
||||
|
||||
ret = cs40l2x_dig_scale_set(cs40l2x, dig_scale);
|
||||
return ret;
|
||||
default:
|
||||
/* loop once more */
|
||||
cs40l2x->pbq_remain--;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(regmap, CS40L2X_MBOX_TRIGGERINDEX,
|
||||
tag);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cs40l2x_pbq_poll(cs40l2x);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cs40l2x->pbq_state = CS40L2X_PBQ_STATE_PLAYING;
|
||||
cs40l2x->pbq_index++;
|
||||
}
|
||||
}
|
||||
|
||||
tag = cs40l2x->pbq_pairs[cs40l2x->pbq_index].tag;
|
||||
mag = cs40l2x->pbq_pairs[cs40l2x->pbq_index].mag;
|
||||
|
||||
/* zero tag indicates a period of silence */
|
||||
if (tag) {
|
||||
dig_scale += cs40l2x_pbq_scale[mag].dig_scale;
|
||||
if (dig_scale > CS40L2X_DIG_SCALE_MAX)
|
||||
dig_scale = CS40L2X_DIG_SCALE_MAX;
|
||||
|
||||
ret = cs40l2x_dig_scale_set(cs40l2x, dig_scale);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(regmap, CS40L2X_MBOX_TRIGGERINDEX, tag);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cs40l2x_pbq_poll(cs40l2x);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cs40l2x->pbq_state = CS40L2X_PBQ_STATE_PLAYING;
|
||||
} else {
|
||||
hrtimer_start(&cs40l2x->pbq_timer,
|
||||
ktime_set(mag / 1000, (mag % 1000) * 1000000),
|
||||
HRTIMER_MODE_REL);
|
||||
cs40l2x->pbq_state = CS40L2X_PBQ_STATE_SILENT;
|
||||
}
|
||||
|
||||
cs40l2x->pbq_index++;
|
||||
} while (tag == CS40L2X_PBQ_TAG_START || tag == CS40L2X_PBQ_TAG_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1107,7 +1179,7 @@ static void cs40l2x_vibe_start_worker(struct work_struct *work)
|
|||
container_of(work, struct cs40l2x_private, vibe_start_work);
|
||||
struct regmap *regmap = cs40l2x->regmap;
|
||||
struct device *dev = cs40l2x->dev;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
mutex_lock(&cs40l2x->lock);
|
||||
|
||||
|
|
@ -1159,6 +1231,11 @@ static void cs40l2x_vibe_start_worker(struct work_struct *work)
|
|||
case CS40L2X_INDEX_PBQ:
|
||||
cs40l2x->pbq_index = 0;
|
||||
cs40l2x->pbq_remain = cs40l2x->pbq_repeat;
|
||||
|
||||
for (i = 0; i < cs40l2x->pbq_depth; i++)
|
||||
cs40l2x->pbq_pairs[i].remain =
|
||||
cs40l2x->pbq_pairs[i].repeat;
|
||||
|
||||
ret = cs40l2x_pbq_pair_launch(cs40l2x);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to launch playback queue\n");
|
||||
|
|
|
|||
|
|
@ -700,6 +700,9 @@
|
|||
#define CS40L2X_PBQ_STATE_IDLE 0x00
|
||||
#define CS40L2X_PBQ_STATE_PLAYING 0x01
|
||||
#define CS40L2X_PBQ_STATE_SILENT 0x02
|
||||
#define CS40L2X_PBQ_TAG_SILENCE 0x0000
|
||||
#define CS40L2X_PBQ_TAG_START 0x8000
|
||||
#define CS40L2X_PBQ_TAG_STOP 0x8001
|
||||
|
||||
#define CS40L2X_DIAG_STATE_INIT 0x00
|
||||
#define CS40L2X_DIAG_STATE_RUN 0x01
|
||||
|
|
@ -760,6 +763,8 @@ struct cs40l2x_coeff_desc {
|
|||
struct cs40l2x_pbq_pair {
|
||||
unsigned int tag;
|
||||
unsigned int mag;
|
||||
unsigned int repeat;
|
||||
unsigned int remain;
|
||||
};
|
||||
|
||||
struct cs40l2x_dig_scale_map {
|
||||
|
|
|
|||
Loading…
Reference in a new issue