On Mon 07 Nov 04:37 PST 2016, Avaneesh Kumar Dwivedi wrote:
Handling of clock and regulator resources as well as resetIt would be much easier to review this if you didn't do all three
register programing differ according to version of hexagon
dsp hardware. Different version require different resources
and different parameters for same resource. Hence it is
needed that resource handling is generic and independent of
hexagon dsp version.
changes in the same patch, and at the same time changed the function
names. There's large parts of this patch where it's not obvious what the
actual changes are.
since i do not know how many resource of a particular type will be needed on new version of new class of hexagon that is why i am working with pointers.
Signed-off-by: Avaneesh Kumar Dwivedi <akdwived@xxxxxxxxxxxxxx>Keeping these as statically sized arrays, potentially with unused
---
drivers/remoteproc/qcom_q6v5_pil.c | 471 +++++++++++++++++++++++++++----------
1 file changed, 344 insertions(+), 127 deletions(-)
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c
index b60dff3..1fc505b 100644
--- a/drivers/remoteproc/qcom_q6v5_pil.c
+++ b/drivers/remoteproc/qcom_q6v5_pil.c
@@ -30,6 +30,7 @@
#include <linux/reset.h>
#include <linux/soc/qcom/smem.h>
#include <linux/soc/qcom/smem_state.h>
+#include <linux/mutex.h>
#include <linux/of_device.h>
#include "remoteproc_internal.h"
@@ -93,6 +94,8 @@
#define QDSS_BHS_ON BIT(21)
#define QDSS_LDO_BYP BIT(22)
+#define QDSP6v56_CLAMP_WL BIT(21)
+#define QDSP6v56_CLAMP_QMC_MEM BIT(22)
struct q6_rproc_res {
char **proxy_clks;
int proxy_clk_cnt;
@@ -129,11 +132,11 @@ struct q6v5 {
struct qcom_smem_state *state;
unsigned stop_bit;
- struct regulator_bulk_data supply[4];
const struct q6_rproc_res *q6_rproc_res;
- struct clk *ahb_clk;
- struct clk *axi_clk;
- struct clk *rom_clk;
+ struct clk **active_clks;
+ struct clk **proxy_clks;
+ struct regulator **proxy_regs;
+ struct regulator **active_regs;
elements at the end removes the need for allocating the storage and the
double pointers.
I agree, Have removed them.
struct completion start_done;I still don't see the need for these 3 attributes.
struct completion stop_done;
@@ -147,67 +150,245 @@ struct q6v5 {
phys_addr_t mpss_reloc;
void *mpss_region;
size_t mpss_size;
+ struct mutex q6_lock;
+ bool proxy_unvote_reg;
+ bool proxy_unvote_clk;
Agree, have removed check.
};If you keep proxy_regs and active_regs as arrays you don't need this
-enum {
- Q6V5_SUPPLY_CX,
- Q6V5_SUPPLY_MX,
- Q6V5_SUPPLY_MSS,
- Q6V5_SUPPLY_PLL,
-};
+static int q6_regulator_init(struct q6v5 *qproc)
+{
+ struct regulator **reg_arr;
+ int i;
+
+ if (qproc->q6_rproc_res->proxy_reg_cnt) {
check.
the way i have reorganized code in next patchset i found using devm_regulator_get() more convenient, can i keep using them? as i am reading string one by one and based on read string filling a regulator struct with its voltage and load and handle info.
+ reg_arr = devm_kzalloc(qproc->dev,Please keep active_regs and proxy_regs as regulator_bulk_data and
+ sizeof(reg_arr) * qproc->q6_rproc_res->proxy_reg_cnt,
+ GFP_KERNEL);
+
+ for (i = 0; i < qproc->q6_rproc_res->proxy_reg_cnt; i++) {
+ reg_arr[i] = devm_regulator_get(qproc->dev,
+ qproc->q6_rproc_res->proxy_regs[i]);
+ if (IS_ERR(reg_arr[i]))
+ return PTR_ERR(reg_arr[i]);
+ qproc->proxy_regs = reg_arr;
+ }
+ }
+
+ if (qproc->q6_rproc_res->active_reg_cnt) {
+ reg_arr = devm_kzalloc(qproc->dev,
+ sizeof(reg_arr) * qproc->q6_rproc_res->active_reg_cnt,
+ GFP_KERNEL);
+
+ for (i = 0; i < qproc->q6_rproc_res->active_reg_cnt; i++) {
+ reg_arr[i] = devm_regulator_get(qproc->dev,
+ qproc->q6_rproc_res->active_regs[i]);
+
+ if (IS_ERR(reg_arr[i]))
+ return PTR_ERR(reg_arr[i]);
+ qproc->active_regs = reg_arr;
+ }
+ }
continue to use devm_regulator_bulk_get(), it should make this code
cleaner.
Have modified as per suggestion.
+Rather then keeping these properties on int-arrays I strongly prefer
+ return 0;
+}
-static int q6v5_regulator_init(struct q6v5 *qproc)
+static int q6_proxy_regulator_enable(struct q6v5 *qproc)
{
- int ret;
+ int i, j, ret = 0;
+ int **reg_loadnvoltsetflag;
+ int *reg_load;
+ int *reg_voltage;
+
+ reg_loadnvoltsetflag = qproc->q6_rproc_res->proxy_reg_action;
+ reg_load = qproc->q6_rproc_res->proxy_reg_load;
+ reg_voltage = qproc->q6_rproc_res->proxy_reg_voltage;
that you would have a struct { uV, uA } for each regulator.
Sorry for mess, have simplified and cleaned.
+I'm sorry, but this is not clean. Please use the fact that we're not
+ for (i = 0; i < qproc->q6_rproc_res->proxy_reg_cnt; i++) {
+ for (j = 0; j <= 1; j++) {
+ if (j == 0 && *(reg_loadnvoltsetflag + i*j + j))
writing assembly code and use the language to your advantage.
As replied above i am going with getting sigle regulator handle one time.
+ regulator_set_load(qproc->proxy_regs[i],If you just keep your regulators in a regulator_bulk_data array then you
+ reg_load[i]);
+ if (j == 1 && *(reg_loadnvoltsetflag + i*j + j))
+ regulator_set_voltage(qproc->proxy_regs[i],
+ reg_voltage[i], INT_MAX);
+ }
+ }
- qproc->supply[Q6V5_SUPPLY_CX].supply = "cx";
- qproc->supply[Q6V5_SUPPLY_MX].supply = "mx";
- qproc->supply[Q6V5_SUPPLY_MSS].supply = "mss";
- qproc->supply[Q6V5_SUPPLY_PLL].supply = "pll";
+ for (i = 0; i < qproc->q6_rproc_res->proxy_reg_cnt; i++) {
+ ret = regulator_enable(qproc->proxy_regs[i]);
+ if (ret) {
+ for (; i > 0; --i) {
+ regulator_disable(qproc->proxy_regs[i]);
+ return ret;
+ }
+ }
+ }
can replace this with regulator_bulk_enable(proxy_reg_cnt, proxy_regs);
Yes Removed
- ret = devm_regulator_bulk_get(qproc->dev,This should still not be needed.
- ARRAY_SIZE(qproc->supply), qproc->supply);
- if (ret < 0) {
- dev_err(qproc->dev, "failed to get supplies\n");
- return ret;
+ qproc->proxy_unvote_reg = true;
Agreed, have modified
+q6_active_regulator_enable() is a no-op if active_reg_cnt is 0, so no
+ return 0;
+}
+
+static int q6_active_regulator_enable(struct q6v5 *qproc)
+{
+ int i, j, ret = 0;
+ int **reg_loadnvoltsetflag;
+ int *reg_load;
+ int *reg_voltage;
+
+ reg_loadnvoltsetflag = qproc->q6_rproc_res->active_reg_action;
+ reg_load = qproc->q6_rproc_res->active_reg_load;
+ reg_voltage = qproc->q6_rproc_res->active_reg_voltage;
+
+ for (i = 0; i < qproc->q6_rproc_res->active_reg_cnt; i++) {
+ for (j = 0; j <= 1; j++) {
+ if (j == 0 && *(reg_loadnvoltsetflag + i*j + j))
+ regulator_set_load(qproc->active_regs[i],
+ reg_load[i]);
+ if (j == 1 && *(reg_loadnvoltsetflag + i*j + j))
+ regulator_set_voltage(qproc->active_regs[i],
+ reg_voltage[i], INT_MAX);
+ }
}
- regulator_set_load(qproc->supply[Q6V5_SUPPLY_CX].consumer, 100000);
- regulator_set_load(qproc->supply[Q6V5_SUPPLY_MSS].consumer, 100000);
- regulator_set_load(qproc->supply[Q6V5_SUPPLY_PLL].consumer, 10000);
+ for (i = 0; i < qproc->q6_rproc_res->active_reg_cnt; i++) {
+ ret = regulator_enable(qproc->active_regs[i]);
+ if (ret) {
+ for (; i > 0; --i) {
+ regulator_disable(qproc->active_regs[i]);
+ return ret;
+ }
+ }
+ }
return 0;
}
-static int q6v5_regulator_enable(struct q6v5 *qproc)
+static int q6_regulator_enable(struct q6v5 *qproc)
{
- struct regulator *mss = qproc->supply[Q6V5_SUPPLY_MSS].consumer;
- struct regulator *mx = qproc->supply[Q6V5_SUPPLY_MX].consumer;
int ret;
- /* TODO: Q6V5_SUPPLY_CX is supposed to be set to super-turbo here */
+ if (qproc->q6_rproc_res->proxy_reg_cnt)
+ ret = q6_proxy_regulator_enable(qproc);
- ret = regulator_set_voltage(mx, 1050000, INT_MAX);
- if (ret)
- return ret;
+ if (qproc->q6_rproc_res->active_reg_cnt)
need to check that. Rather than having two functions, try to
parameterize the regulator enable functions so that you can have a
single function that you pass the active or proxy list.
Yes , modified.
+ ret = q6_active_regulator_enable(qproc);This is really the same as active_clk_enable(), so you should just have
- regulator_set_voltage(mss, 1000000, 1150000);
+ return ret;
+}
- return regulator_bulk_enable(ARRAY_SIZE(qproc->supply), qproc->supply);
+static int q6_proxy_regulator_disable(struct q6v5 *qproc)
+{
+ int i, j;
+ int **reg_loadnvoltsetflag;
+
+ reg_loadnvoltsetflag = qproc->q6_rproc_res->proxy_reg_action;
+ if (!qproc->proxy_unvote_reg)
+ return 0;
+ for (i = qproc->q6_rproc_res->proxy_reg_cnt-1; i >= 0; i--) {
+ for (j = 0; j <= 1; j++) {
+ if (j == 0 && *(reg_loadnvoltsetflag + i*j + j))
+ regulator_set_load(qproc->proxy_regs[i], 0);
+ if (j == 1 && *(reg_loadnvoltsetflag + i*j + j))
+ regulator_set_voltage(qproc->proxy_regs[i],
+ 0, INT_MAX);
+ }
+ }
+ for (i = qproc->q6_rproc_res->proxy_reg_cnt-1; i >= 0; i--)
+ regulator_disable(qproc->proxy_regs[i]);
+ qproc->proxy_unvote_reg = false;
+ return 0;
}
-static void q6v5_regulator_disable(struct q6v5 *qproc)
+static int q6_active_regulator_disable(struct q6v5 *qproc)
{
- struct regulator *mss = qproc->supply[Q6V5_SUPPLY_MSS].consumer;
- struct regulator *mx = qproc->supply[Q6V5_SUPPLY_MX].consumer;
+ int i, j, ret = 0;
+ int **reg_loadnvoltsetflag;
+
+ reg_loadnvoltsetflag = qproc->q6_rproc_res->active_reg_action;
+
+ for (i = qproc->q6_rproc_res->active_reg_cnt-1; i > 0; i--) {
+ for (j = 0; j <= 1; j++) {
+ if (j == 0 && *(reg_loadnvoltsetflag + i*j + j))
+ regulator_set_load(qproc->active_regs[i], 0);
+ if (j == 1 && *(reg_loadnvoltsetflag + i*j + j))
+ regulator_set_voltage(qproc->active_regs[i],
+ 0, INT_MAX);
+ }
+ }
+ for (i = qproc->q6_rproc_res->active_reg_cnt-1; i >= 0; i--)
+ ret = regulator_disable(qproc->proxy_regs[i]);
+ return 0;
+}
+
+static void q6_regulator_disable(struct q6v5 *qproc)
+{
+ if (qproc->q6_rproc_res->proxy_reg_cnt)
+ q6_proxy_regulator_disable(qproc);
- /* TODO: Q6V5_SUPPLY_CX corner votes should be released */
+ if (qproc->q6_rproc_res->active_reg_cnt)
+ q6_active_regulator_disable(qproc);
+}
- regulator_bulk_disable(ARRAY_SIZE(qproc->supply), qproc->supply);
- regulator_set_voltage(mx, 0, INT_MAX);
- regulator_set_voltage(mss, 0, 1150000);
+static int q6_proxy_clk_enable(struct q6v5 *qproc)
a function that you pass an array of clocks and a count to - similar to
regulator_bulk_enable().
OK
+{No need to initialize ret, as its first use is an assignment.
+ int i, ret = 0;
+
+ for (i = 0; i < qproc->q6_rproc_res->proxy_clk_cnt; i++) {
+ ret = clk_prepare_enable(qproc->proxy_clks[i]);
+ if (ret) {
+ for (; i > 0; --i) {
+ clk_disable_unprepare(qproc->proxy_clks[i]);
+ return ret;
+ }
+ }
+ }
+ qproc->proxy_unvote_clk = true;
+ return 0;
}
+static void q6_proxy_clk_disable(struct q6v5 *qproc)
+{
+ int i;
+
+ if (!qproc->proxy_unvote_clk)
+ return;
+ for (i = qproc->q6_rproc_res->proxy_clk_cnt-1; i >= 0; i--)
+ clk_disable_unprepare(qproc->proxy_clks[i]);
+ qproc->proxy_unvote_clk = false;
+}
+
+static int q6_active_clk_enable(struct q6v5 *qproc)
+{
+ int i, ret = 0;
+Use goto here, rather than nesting a error return in here.
+ for (i = 0; i < qproc->q6_rproc_res->active_clk_cnt; i++) {
+ ret = clk_prepare_enable(qproc->active_clks[i]);
+ if (ret) {
+ for (; i > 0; i--) {Please put this in its own commit and describe why it can't be there on
+ clk_disable_unprepare(qproc->active_clks[i]);
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+static void q6_active_clk_disable(struct q6v5 *qproc)
+{
+ int i;
+
+ for (i = qproc->q6_rproc_res->active_clk_cnt-1; i >= 0; i--)
+ clk_disable_unprepare(qproc->active_clks[i]);
+}
+
+static void pil_mss_restart_reg(struct q6v5 *qproc, u32 mss_restart)
+{
+ if (qproc->restart_reg) {
+ writel_relaxed(mss_restart, qproc->restart_reg);
+ udelay(2);
+ }
+}
static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
{
struct q6v5 *qproc = rproc->priv;
@@ -340,11 +521,6 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
unsigned int val;
int ret;
- /* Check if we're already idle */
- ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
- if (!ret && val)
- return;
-
8996 and why it's okay to drop on 8974 and 8916.
/* Assert halt request */Most of the changes in this function are renaming of functions and
regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
@@ -366,7 +542,7 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
}
-static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
+static int q6_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
{
unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
dma_addr_t phys;
@@ -395,7 +571,7 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
return ret < 0 ? ret : 0;
}
-static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw)
+static int q6_mpss_validate(struct q6v5 *qproc, const struct firmware *fw)
{
const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr;
@@ -451,7 +627,7 @@ static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw)
return ret < 0 ? ret : 0;
}
-static int q6v5_mpss_load(struct q6v5 *qproc)
+static int q6_mpss_load(struct q6v5 *qproc)
{
const struct firmware *fw;
phys_addr_t fw_addr;
@@ -476,7 +652,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
/* Initialize the RMB validator */
writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
- ret = q6v5_mpss_init_image(qproc, fw);
+ ret = q6_mpss_init_image(qproc, fw);
if (ret)
goto release_firmware;
@@ -484,7 +660,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
if (ret)
goto release_firmware;
- ret = q6v5_mpss_validate(qproc, fw);
+ ret = q6_mpss_validate(qproc, fw);
release_firmware:
release_firmware(fw);
@@ -492,36 +668,41 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
return ret < 0 ? ret : 0;
}
-static int q6v5_start(struct rproc *rproc)
+static int q6_start(struct rproc *rproc)
variables, please don't do this as part of a functional change.
Best would be if you start with a commit that renames the necessary
parts and where you specify that there's "no functional change".
Sure, Removed.
{We should already be protected by the rproc->lock here, please let me
struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
int ret;
- ret = q6v5_regulator_enable(qproc);
+ mutex_lock(&qproc->q6_lock);
know if there are any gaps.
OK, Done.
+ ret = q6_regulator_enable(qproc);Supplies are regulators, but if you find this confusing then you
if (ret) {
- dev_err(qproc->dev, "failed to enable supplies\n");
+ dev_err(qproc->dev, "failed to enable reg supplies\n");
shouldn't abbreviate regulators as "reg".
No, deassert need to be done before Q6 clocks are enabled, Done.
return ret;So the correct order is: enable clocks, then deassert reset?
}
- ret = reset_control_deassert(qproc->mss_restart);
OK, Done.
+ ret = q6_proxy_clk_enable(qproc);There's no functional reason for changing writel to writel_relaxed, so
if (ret) {
- dev_err(qproc->dev, "failed to deassert mss restart\n");
- goto disable_vdd;
+ dev_err(qproc->dev, "failed to enable proxy_clk\n");
+ goto err_proxy_clk;
}
- ret = clk_prepare_enable(qproc->ahb_clk);
- if (ret)
- goto assert_reset;
-
- ret = clk_prepare_enable(qproc->axi_clk);
- if (ret)
- goto disable_ahb_clk;
+ ret = q6_active_clk_enable(qproc);
+ if (ret) {
+ dev_err(qproc->dev, "failed to enable active clocks\n");
+ goto err_active_clks;
+ }
- ret = clk_prepare_enable(qproc->rom_clk);
- if (ret)
- goto disable_axi_clk;
+ if (!strcmp(qproc->q6_rproc_res->q6_version, "v56"))
+ pil_mss_restart_reg(qproc, 0);
+ else {
+ ret = reset_control_deassert(qproc->mss_restart);
+ if (ret) {
+ dev_err(qproc->dev, "failed to deassert mss restart\n");
+ goto err_deassert;
+ }
+ }
- writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
+ writel_relaxed(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
please do this in a separate commit and motivate it well.
It was an experimental change made during validation, found its way in patch. have reverted it back.
ret = q6v5proc_reset(qproc);Please put this in a separate commit and describe why 10 seconds is
if (ret)
@@ -539,13 +720,11 @@ static int q6v5_start(struct rproc *rproc)
}
dev_info(qproc->dev, "MBA booted, loading mpss\n");
-
- ret = q6v5_mpss_load(qproc);
+ ret = q6_mpss_load(qproc);
if (ret)
goto halt_axi_ports;
-
ret = wait_for_completion_timeout(&qproc->start_done,
- msecs_to_jiffies(5000));
+ msecs_to_jiffies(10000));
better than 5.
Ok, Done.
if (ret == 0) {This is good, please drop the TODO comment now that we're done.
dev_err(qproc->dev, "start timed out\n");
ret = -ETIMEDOUT;
@@ -553,36 +732,33 @@ static int q6v5_start(struct rproc *rproc)
}
qproc->running = true;
-
/* TODO: All done, release the handover resources */
-
+ q6_proxy_clk_disable(qproc);
+ q6_proxy_regulator_disable(qproc);
Yes needed, have corrected.
+ mutex_unlock(&qproc->q6_lock);Don't we need to assert the reset again?
return 0;
halt_axi_ports:
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
-
- clk_disable_unprepare(qproc->rom_clk);
-disable_axi_clk:
- clk_disable_unprepare(qproc->axi_clk);
-disable_ahb_clk:
- clk_disable_unprepare(qproc->ahb_clk);
-assert_reset:
- reset_control_assert(qproc->mss_restart);
OK, Done.
-disable_vdd:It's better if the labels describe the action than the source of the
- q6v5_regulator_disable(qproc);
-
+err_deassert:
+ q6_active_clk_disable(qproc);
+err_active_clks:
+ q6_proxy_clk_disable(qproc);
+err_proxy_clk:
jump, so please keep the "disable_vdd" label for this - it also makes
your patch cleaner.
+ q6_regulator_disable(qproc);This would be much better as an enum than a string. But I keep wonder if
+ mutex_unlock(&qproc->q6_lock);
return ret;
}
-static int q6v5_stop(struct rproc *rproc)
+static int q6_stop(struct rproc *rproc)
{
struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
int ret;
+ u64 val;
- qproc->running = false;
-
+ mutex_lock(&qproc->q6_lock);
qcom_smem_state_update_bits(qproc->state,
BIT(qproc->stop_bit), BIT(qproc->stop_bit));
@@ -597,16 +773,30 @@ static int q6v5_stop(struct rproc *rproc)
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
- reset_control_assert(qproc->mss_restart);
- clk_disable_unprepare(qproc->rom_clk);
- clk_disable_unprepare(qproc->axi_clk);
- clk_disable_unprepare(qproc->ahb_clk);
- q6v5_regulator_disable(qproc);
-
+ if (!strcmp(qproc->q6_rproc_res->q6_version, "v56")) {
this is only for v5.6 of the Hexagon - perhaps should we clamp different
things on the various versions?.
As i informed MSS RESET REGISTER was never a block control reset or BCR (a term used to define those reset register which control a clock or pll ) so clock control reset framework can not be used to do reset programming for MSS
+ /*And by using the reset framework for mss_restart this will fall out of
+ * Assert QDSP6 I/O clamp, memory wordline clamp, and compiler
+ * memory clamp as a software workaround to avoid high MX
+ * current during LPASS/MSS restart.
+ */
+
+ val = readl_relaxed(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+ val |= (Q6SS_CLAMP_IO | QDSP6v56_CLAMP_WL |
+ QDSP6v56_CLAMP_QMC_MEM);
+ writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+ pil_mss_restart_reg(qproc, 1);
the conditional segment and the else is gone.
+ } elseRegards,
+ reset_control_assert(qproc->mss_restart);
+ q6_active_clk_disable(qproc);
+ q6_proxy_clk_disable(qproc);
+ q6_proxy_regulator_disable(qproc);
+ q6_active_regulator_disable(qproc);
+ qproc->running = false;
+ mutex_unlock(&qproc->q6_lock);
return 0;
}
Bjorn