ASoC: cs43130: Allow driver to work without IRQ connection
Add a polling mechanism that will keep the driver operational even in absence of physical IRQ connection. If IRQ line is detected, the driver will continue working as usual, in case of missing IRQ line it will fallback to the polling mechanism introduced in this change. This will support users which choose not to connect an IRQ line as it is not critical to part's operation. Signed-off-by: Maciej Strozek <mstrozek@opensource.cirrus.com> Acked-by: Charles Keepax <ckeepax@opensource.cirrus.com> Link: https://lore.kernel.org/r/20231123090658.10418-1-mstrozek@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
b1cea462a7
commit
fa91703dc2
@ -326,6 +326,34 @@ static int cs43130_set_pll(struct snd_soc_component *component, int pll_id, int
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs43130_wait_for_completion(struct cs43130_private *cs43130, struct completion *to_poll,
|
||||
int time)
|
||||
{
|
||||
int stickies, offset, flag, ret;
|
||||
|
||||
if (cs43130->has_irq_line) {
|
||||
ret = wait_for_completion_timeout(to_poll, msecs_to_jiffies(time));
|
||||
if (ret == 0)
|
||||
return -ETIMEDOUT;
|
||||
else
|
||||
return 0; // Discard number of jiffies left till timeout and return success
|
||||
}
|
||||
|
||||
if (to_poll == &cs43130->xtal_rdy) {
|
||||
offset = 0;
|
||||
flag = CS43130_XTAL_RDY_INT;
|
||||
} else if (to_poll == &cs43130->pll_rdy) {
|
||||
offset = 0;
|
||||
flag = CS43130_PLL_RDY_INT;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_read_poll_timeout(cs43130->regmap, CS43130_INT_STATUS_1 + offset,
|
||||
stickies, (stickies & flag),
|
||||
1000, time * 1000);
|
||||
}
|
||||
|
||||
static int cs43130_change_clksrc(struct snd_soc_component *component,
|
||||
enum cs43130_mclk_src_sel src)
|
||||
{
|
||||
@ -364,14 +392,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component,
|
||||
CS43130_XTAL_RDY_INT_MASK, 0);
|
||||
regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
|
||||
CS43130_PDN_XTAL_MASK, 0);
|
||||
ret = wait_for_completion_timeout(&cs43130->xtal_rdy,
|
||||
msecs_to_jiffies(100));
|
||||
ret = cs43130_wait_for_completion(cs43130, &cs43130->xtal_rdy, 100);
|
||||
regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
|
||||
CS43130_XTAL_RDY_INT_MASK,
|
||||
1 << CS43130_XTAL_RDY_INT_SHIFT);
|
||||
if (ret == 0) {
|
||||
dev_err(cs43130->dev, "Timeout waiting for XTAL_READY interrupt\n");
|
||||
return -ETIMEDOUT;
|
||||
if (ret) {
|
||||
dev_err(cs43130->dev, "Error waiting for XTAL_READY interrupt: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,14 +427,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component,
|
||||
CS43130_XTAL_RDY_INT_MASK, 0);
|
||||
regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
|
||||
CS43130_PDN_XTAL_MASK, 0);
|
||||
ret = wait_for_completion_timeout(&cs43130->xtal_rdy,
|
||||
msecs_to_jiffies(100));
|
||||
ret = cs43130_wait_for_completion(cs43130, &cs43130->xtal_rdy, 100);
|
||||
regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
|
||||
CS43130_XTAL_RDY_INT_MASK,
|
||||
1 << CS43130_XTAL_RDY_INT_SHIFT);
|
||||
if (ret == 0) {
|
||||
dev_err(cs43130->dev, "Timeout waiting for XTAL_READY interrupt\n");
|
||||
return -ETIMEDOUT;
|
||||
if (ret) {
|
||||
dev_err(cs43130->dev, "Error waiting for XTAL_READY interrupt: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -416,14 +442,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component,
|
||||
CS43130_PLL_RDY_INT_MASK, 0);
|
||||
regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
|
||||
CS43130_PDN_PLL_MASK, 0);
|
||||
ret = wait_for_completion_timeout(&cs43130->pll_rdy,
|
||||
msecs_to_jiffies(100));
|
||||
ret = cs43130_wait_for_completion(cs43130, &cs43130->pll_rdy, 100);
|
||||
regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
|
||||
CS43130_PLL_RDY_INT_MASK,
|
||||
1 << CS43130_PLL_RDY_INT_SHIFT);
|
||||
if (ret == 0) {
|
||||
dev_err(cs43130->dev, "Timeout waiting for PLL_READY interrupt\n");
|
||||
return -ETIMEDOUT;
|
||||
if (ret) {
|
||||
dev_err(cs43130->dev, "Error waiting for PLL_READY interrupt: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
|
||||
@ -2015,7 +2040,7 @@ static int cs43130_hpload_proc(struct cs43130_private *cs43130,
|
||||
regmap_read(cs43130->regmap, CS43130_INT_MASK_4, &msk);
|
||||
if (!ret) {
|
||||
dev_err(cs43130->dev, "Timeout waiting for HPLOAD interrupt\n");
|
||||
return -1;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
dev_dbg(cs43130->dev, "HP load stat: %x, INT_MASK_4: %x\n",
|
||||
@ -2510,13 +2535,19 @@ static int cs43130_i2c_probe(struct i2c_client *client)
|
||||
init_completion(&cs43130->pll_rdy);
|
||||
init_completion(&cs43130->hpload_evt);
|
||||
|
||||
ret = devm_request_threaded_irq(cs43130->dev, client->irq,
|
||||
NULL, cs43130_irq_thread,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
|
||||
"cs43130", cs43130);
|
||||
if (ret != 0) {
|
||||
dev_err(cs43130->dev, "Failed to request IRQ: %d\n", ret);
|
||||
goto err;
|
||||
if (!client->irq) {
|
||||
dev_dbg(cs43130->dev, "IRQ not found, will poll instead\n");
|
||||
cs43130->has_irq_line = 0;
|
||||
} else {
|
||||
ret = devm_request_threaded_irq(cs43130->dev, client->irq,
|
||||
NULL, cs43130_irq_thread,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
|
||||
"cs43130", cs43130);
|
||||
if (ret != 0) {
|
||||
dev_err(cs43130->dev, "Failed to request IRQ: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
cs43130->has_irq_line = 1;
|
||||
}
|
||||
|
||||
cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO;
|
||||
|
@ -507,6 +507,7 @@ struct cs43130_private {
|
||||
struct gpio_desc *reset_gpio;
|
||||
unsigned int dev_id; /* codec device ID */
|
||||
int xtal_ibias;
|
||||
bool has_irq_line;
|
||||
|
||||
/* shared by both DAIs */
|
||||
struct mutex clk_mutex;
|
||||
|
Loading…
x
Reference in New Issue
Block a user