ASoC: cs35l45: IRQ support

Adds IRQ handlers

Signed-off-by: Vlad Karpovich <vkarpovi@opensource.cirrus.com>
Link: https://lore.kernel.org/r/167933510218.26.11092784685990338045@mailman-core.alsa-project.org
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Vlad.Karpovich 2023-03-15 10:47:20 -05:00 committed by Mark Brown
parent c6cec088ab
commit 6085f9e6dc
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0
5 changed files with 245 additions and 4 deletions

View file

@ -32,6 +32,7 @@ static int cs35l45_i2c_probe(struct i2c_client *client)
}
cs35l45->dev = dev;
cs35l45->irq = client->irq;
return cs35l45_probe(cs35l45);
}

View file

@ -32,6 +32,7 @@ static int cs35l45_spi_probe(struct spi_device *spi)
}
cs35l45->dev = dev;
cs35l45->irq = spi->irq;
return cs35l45_probe(cs35l45);
}

View file

@ -64,6 +64,25 @@ static const struct reg_default cs35l45_defaults[] = {
{ CS35L45_ASPTX4_INPUT, 0x00000028 },
{ CS35L45_ASPTX5_INPUT, 0x00000048 },
{ CS35L45_AMP_PCM_CONTROL, 0x00100000 },
{ CS35L45_IRQ1_CFG, 0x00000000 },
{ CS35L45_IRQ1_MASK_1, 0xBFEFFFBF },
{ CS35L45_IRQ1_MASK_2, 0xFFFFFFFF },
{ CS35L45_IRQ1_MASK_3, 0xFFFF87FF },
{ CS35L45_IRQ1_MASK_4, 0xF8FFFFFF },
{ CS35L45_IRQ1_MASK_5, 0x0EF80000 },
{ CS35L45_IRQ1_MASK_6, 0x00000000 },
{ CS35L45_IRQ1_MASK_7, 0xFFFFFF78 },
{ CS35L45_IRQ1_MASK_8, 0x00003FFF },
{ CS35L45_IRQ1_MASK_9, 0x00000000 },
{ CS35L45_IRQ1_MASK_10, 0x00000000 },
{ CS35L45_IRQ1_MASK_11, 0x00000000 },
{ CS35L45_IRQ1_MASK_12, 0x00000000 },
{ CS35L45_IRQ1_MASK_13, 0x00000000 },
{ CS35L45_IRQ1_MASK_14, 0x00000001 },
{ CS35L45_IRQ1_MASK_15, 0x00000000 },
{ CS35L45_IRQ1_MASK_16, 0x00000000 },
{ CS35L45_IRQ1_MASK_17, 0x00000000 },
{ CS35L45_IRQ1_MASK_18, 0x3FE5D0FF },
{ CS35L45_GPIO1_CTRL1, 0x81000001 },
{ CS35L45_GPIO2_CTRL1, 0x81000001 },
{ CS35L45_GPIO3_CTRL1, 0x81000001 },
@ -100,7 +119,11 @@ static bool cs35l45_readable_reg(struct device *dev, unsigned int reg)
case CS35L45_ASPTX5_INPUT:
case CS35L45_AMP_PCM_CONTROL:
case CS35L45_AMP_PCM_HPF_TST:
case CS35L45_IRQ1_EINT_4:
case CS35L45_IRQ1_CFG:
case CS35L45_IRQ1_STATUS:
case CS35L45_IRQ1_EINT_1 ... CS35L45_IRQ1_EINT_18:
case CS35L45_IRQ1_STS_1 ... CS35L45_IRQ1_STS_18:
case CS35L45_IRQ1_MASK_1 ... CS35L45_IRQ1_MASK_18:
case CS35L45_GPIO_STATUS1:
case CS35L45_GPIO1_CTRL1:
case CS35L45_GPIO2_CTRL1:
@ -119,7 +142,9 @@ static bool cs35l45_volatile_reg(struct device *dev, unsigned int reg)
case CS35L45_GLOBAL_ENABLES:
case CS35L45_ERROR_RELEASE:
case CS35L45_AMP_PCM_HPF_TST: /* not cachable */
case CS35L45_IRQ1_EINT_4:
case CS35L45_IRQ1_STATUS:
case CS35L45_IRQ1_EINT_1 ... CS35L45_IRQ1_EINT_18:
case CS35L45_IRQ1_STS_1 ... CS35L45_IRQ1_STS_18:
case CS35L45_GPIO_STATUS1:
return true;
default:

View file

@ -586,10 +586,13 @@ static int cs35l45_apply_property_config(struct cs35l45_private *cs35l45)
val << CS35L45_GPIO_CTRL_SHIFT);
ret = of_property_read_u32(child, "gpio-invert", &val);
if (!ret)
if (!ret) {
regmap_update_bits(cs35l45->regmap, pad_regs[i],
CS35L45_GPIO_INVERT_MASK,
val << CS35L45_GPIO_INVERT_SHIFT);
if (i == 1)
cs35l45->irq_invert = val;
}
of_node_put(child);
}
@ -604,6 +607,78 @@ static int cs35l45_apply_property_config(struct cs35l45_private *cs35l45)
return 0;
}
static irqreturn_t cs35l45_pll_unlock(int irq, void *data)
{
struct cs35l45_private *cs35l45 = data;
dev_dbg(cs35l45->dev, "PLL unlock detected!");
return IRQ_HANDLED;
}
static irqreturn_t cs35l45_pll_lock(int irq, void *data)
{
struct cs35l45_private *cs35l45 = data;
dev_dbg(cs35l45->dev, "PLL lock detected!");
return IRQ_HANDLED;
}
static irqreturn_t cs35l45_spk_safe_err(int irq, void *data);
static const struct cs35l45_irq cs35l45_irqs[] = {
CS35L45_IRQ(AMP_SHORT_ERR, "Amplifier short error", cs35l45_spk_safe_err),
CS35L45_IRQ(UVLO_VDDBATT_ERR, "VDDBATT undervoltage error", cs35l45_spk_safe_err),
CS35L45_IRQ(BST_SHORT_ERR, "Boost inductor error", cs35l45_spk_safe_err),
CS35L45_IRQ(BST_UVP_ERR, "Boost undervoltage error", cs35l45_spk_safe_err),
CS35L45_IRQ(TEMP_ERR, "Overtemperature error", cs35l45_spk_safe_err),
CS35L45_IRQ(AMP_CAL_ERR, "Amplifier calibration error", cs35l45_spk_safe_err),
CS35L45_IRQ(UVLO_VDDLV_ERR, "LV threshold detector error", cs35l45_spk_safe_err),
CS35L45_IRQ(GLOBAL_ERROR, "Global error", cs35l45_spk_safe_err),
CS35L45_IRQ(DSP_WDT_EXPIRE, "DSP Watchdog Timer", cs35l45_spk_safe_err),
CS35L45_IRQ(PLL_UNLOCK_FLAG_RISE, "PLL unlock", cs35l45_pll_unlock),
CS35L45_IRQ(PLL_LOCK_FLAG, "PLL lock", cs35l45_pll_lock),
};
static irqreturn_t cs35l45_spk_safe_err(int irq, void *data)
{
struct cs35l45_private *cs35l45 = data;
int i;
i = irq - regmap_irq_get_virq(cs35l45->irq_data, 0);
dev_err(cs35l45->dev, "%s condition detected!\n", cs35l45_irqs[i].name);
return IRQ_HANDLED;
}
static const struct regmap_irq cs35l45_reg_irqs[] = {
CS35L45_REG_IRQ(IRQ1_EINT_1, AMP_SHORT_ERR),
CS35L45_REG_IRQ(IRQ1_EINT_1, UVLO_VDDBATT_ERR),
CS35L45_REG_IRQ(IRQ1_EINT_1, BST_SHORT_ERR),
CS35L45_REG_IRQ(IRQ1_EINT_1, BST_UVP_ERR),
CS35L45_REG_IRQ(IRQ1_EINT_1, TEMP_ERR),
CS35L45_REG_IRQ(IRQ1_EINT_3, AMP_CAL_ERR),
CS35L45_REG_IRQ(IRQ1_EINT_18, UVLO_VDDLV_ERR),
CS35L45_REG_IRQ(IRQ1_EINT_18, GLOBAL_ERROR),
CS35L45_REG_IRQ(IRQ1_EINT_2, DSP_WDT_EXPIRE),
CS35L45_REG_IRQ(IRQ1_EINT_3, PLL_UNLOCK_FLAG_RISE),
CS35L45_REG_IRQ(IRQ1_EINT_3, PLL_LOCK_FLAG),
};
static const struct regmap_irq_chip cs35l45_regmap_irq_chip = {
.name = "cs35l45 IRQ1 Controller",
.main_status = CS35L45_IRQ1_STATUS,
.status_base = CS35L45_IRQ1_EINT_1,
.mask_base = CS35L45_IRQ1_MASK_1,
.ack_base = CS35L45_IRQ1_EINT_1,
.num_regs = 18,
.irqs = cs35l45_reg_irqs,
.num_irqs = ARRAY_SIZE(cs35l45_reg_irqs),
.runtime_pm = true,
};
static int cs35l45_initialize(struct cs35l45_private *cs35l45)
{
struct device *dev = cs35l45->dev;
@ -660,7 +735,8 @@ static int cs35l45_initialize(struct cs35l45_private *cs35l45)
int cs35l45_probe(struct cs35l45_private *cs35l45)
{
struct device *dev = cs35l45->dev;
int ret;
unsigned long irq_pol = IRQF_ONESHOT | IRQF_SHARED;
int ret, i, irq;
cs35l45->vdd_batt = devm_regulator_get(dev, "vdd-batt");
if (IS_ERR(cs35l45->vdd_batt))
@ -705,6 +781,37 @@ int cs35l45_probe(struct cs35l45_private *cs35l45)
if (ret < 0)
goto err_reset;
if (cs35l45->irq) {
if (cs35l45->irq_invert)
irq_pol |= IRQF_TRIGGER_HIGH;
else
irq_pol |= IRQF_TRIGGER_LOW;
ret = devm_regmap_add_irq_chip(dev, cs35l45->regmap, cs35l45->irq, irq_pol, 0,
&cs35l45_regmap_irq_chip, &cs35l45->irq_data);
if (ret) {
dev_err(dev, "Failed to register IRQ chip: %d\n", ret);
goto err_reset;
}
for (i = 0; i < ARRAY_SIZE(cs35l45_irqs); i++) {
irq = regmap_irq_get_virq(cs35l45->irq_data, cs35l45_irqs[i].irq);
if (irq < 0) {
dev_err(dev, "Failed to get %s\n", cs35l45_irqs[i].name);
ret = irq;
goto err_reset;
}
ret = devm_request_threaded_irq(dev, irq, NULL, cs35l45_irqs[i].handler,
irq_pol, cs35l45_irqs[i].name, cs35l45);
if (ret) {
dev_err(dev, "Failed to request IRQ %s: %d\n",
cs35l45_irqs[i].name, ret);
goto err_reset;
}
}
}
ret = devm_snd_soc_register_component(dev, &cs35l45_component,
cs35l45_dai,
ARRAY_SIZE(cs35l45_dai));

View file

@ -51,7 +51,42 @@
#define CS35L45_LDPM_CONFIG 0x00006404
#define CS35L45_AMP_PCM_CONTROL 0x00007000
#define CS35L45_AMP_PCM_HPF_TST 0x00007004
#define CS35L45_IRQ1_CFG 0x0000E000
#define CS35L45_IRQ1_STATUS 0x0000E004
#define CS35L45_IRQ1_EINT_1 0x0000E010
#define CS35L45_IRQ1_EINT_2 0x0000E014
#define CS35L45_IRQ1_EINT_3 0x0000E018
#define CS35L45_IRQ1_EINT_4 0x0000E01C
#define CS35L45_IRQ1_EINT_5 0x0000E020
#define CS35L45_IRQ1_EINT_7 0x0000E028
#define CS35L45_IRQ1_EINT_8 0x0000E02C
#define CS35L45_IRQ1_EINT_18 0x0000E054
#define CS35L45_IRQ1_STS_1 0x0000E090
#define CS35L45_IRQ1_STS_2 0x0000E094
#define CS35L45_IRQ1_STS_3 0x0000E098
#define CS35L45_IRQ1_STS_4 0x0000E09C
#define CS35L45_IRQ1_STS_5 0x0000E0A0
#define CS35L45_IRQ1_STS_7 0x0000E0A8
#define CS35L45_IRQ1_STS_8 0x0000E0AC
#define CS35L45_IRQ1_STS_18 0x0000E0D4
#define CS35L45_IRQ1_MASK_1 0x0000E110
#define CS35L45_IRQ1_MASK_2 0x0000E114
#define CS35L45_IRQ1_MASK_3 0x0000E118
#define CS35L45_IRQ1_MASK_4 0x0000E11C
#define CS35L45_IRQ1_MASK_5 0x0000E120
#define CS35L45_IRQ1_MASK_6 0x0000E124
#define CS35L45_IRQ1_MASK_7 0x0000E128
#define CS35L45_IRQ1_MASK_8 0x0000E12C
#define CS35L45_IRQ1_MASK_9 0x0000E130
#define CS35L45_IRQ1_MASK_10 0x0000E134
#define CS35L45_IRQ1_MASK_11 0x0000E138
#define CS35L45_IRQ1_MASK_12 0x0000E13C
#define CS35L45_IRQ1_MASK_13 0x0000E140
#define CS35L45_IRQ1_MASK_14 0x0000E144
#define CS35L45_IRQ1_MASK_15 0x0000E148
#define CS35L45_IRQ1_MASK_16 0x0000E14C
#define CS35L45_IRQ1_MASK_17 0x0000E150
#define CS35L45_IRQ1_MASK_18 0x0000E154
#define CS35L45_GPIO_STATUS1 0x0000F000
#define CS35L45_GPIO1_CTRL1 0x0000F008
#define CS35L45_GPIO2_CTRL1 0x0000F00C
@ -188,6 +223,38 @@
#define CS35L45_GPIO_INVERT_SHIFT 19
#define CS35L45_GPIO_INVERT_MASK BIT(19)
/* CS35L45_IRQ1_EINT_1 */
#define CS35L45_BST_UVP_ERR_SHIFT 7
#define CS35L45_BST_UVP_ERR_MASK BIT(7)
#define CS35L45_BST_SHORT_ERR_SHIFT 8
#define CS35L45_BST_SHORT_ERR_MASK BIT(8)
#define CS35L45_TEMP_ERR_SHIFT 17
#define CS35L45_TEMP_ERR_MASK BIT(17)
#define CS35L45_MSM_GLOBAL_EN_ASSERT_SHIFT 22
#define CS35L45_MSM_GLOBAL_EN_ASSERT_MASK BIT(22)
#define CS35L45_UVLO_VDDBATT_ERR_SHIFT 29
#define CS35L45_UVLO_VDDBATT_ERR_MASK BIT(29)
#define CS35L45_AMP_SHORT_ERR_SHIFT 31
#define CS35L45_AMP_SHORT_ERR_MASK BIT(31)
/* CS35L45_IRQ1_EINT_2 */
#define CS35L45_DSP_WDT_EXPIRE_SHIFT 4
#define CS35L45_DSP_WDT_EXPIRE_MASK BIT(4)
/* CS35L45_IRQ1_EINT_3 */
#define CS35L45_PLL_LOCK_FLAG_SHIFT 1
#define CS35L45_PLL_LOCK_FLAG_MASK BIT(1)
#define CS35L45_PLL_UNLOCK_FLAG_RISE_SHIFT 4
#define CS35L45_PLL_UNLOCK_FLAG_RISE_MASK BIT(4)
#define CS35L45_AMP_CAL_ERR_SHIFT 25
#define CS35L45_AMP_CAL_ERR_MASK BIT(25)
/* CS35L45_IRQ1_EINT_18 */
#define CS35L45_GLOBAL_ERROR_SHIFT 15
#define CS35L45_GLOBAL_ERROR_MASK BIT(15)
#define CS35L45_UVLO_VDDLV_ERR_SHIFT 16
#define CS35L45_UVLO_VDDLV_ERR_MASK BIT(16)
/* Mixer sources */
#define CS35L45_PCM_SRC_MASK 0x7F
#define CS35L45_PCM_SRC_ZERO 0x00
@ -217,6 +284,43 @@
SNDRV_PCM_RATE_88200 | \
SNDRV_PCM_RATE_96000)
/*
* IRQs
*/
#define CS35L45_IRQ(_irq, _name, _hand) \
{ \
.irq = CS35L45_ ## _irq ## _IRQ,\
.name = _name, \
.handler = _hand, \
}
struct cs35l45_irq {
int irq;
const char *name;
irqreturn_t (*handler)(int irq, void *data);
};
#define CS35L45_REG_IRQ(_reg, _irq) \
[CS35L45_ ## _irq ## _IRQ] = { \
.reg_offset = (CS35L45_ ## _reg) - CS35L45_IRQ1_EINT_1, \
.mask = CS35L45_ ## _irq ## _MASK \
}
enum cs35l45_irq_list {
CS35L45_AMP_SHORT_ERR_IRQ,
CS35L45_UVLO_VDDBATT_ERR_IRQ,
CS35L45_BST_SHORT_ERR_IRQ,
CS35L45_BST_UVP_ERR_IRQ,
CS35L45_TEMP_ERR_IRQ,
CS35L45_AMP_CAL_ERR_IRQ,
CS35L45_UVLO_VDDLV_ERR_IRQ,
CS35L45_GLOBAL_ERROR_IRQ,
CS35L45_DSP_WDT_EXPIRE_IRQ,
CS35L45_PLL_UNLOCK_FLAG_RISE_IRQ,
CS35L45_PLL_LOCK_FLAG_IRQ,
CS35L45_NUM_IRQ
};
struct cs35l45_private {
struct device *dev;
struct regmap *regmap;
@ -227,6 +331,9 @@ struct cs35l45_private {
bool sysclk_set;
u8 slot_width;
u8 slot_count;
int irq_invert;
int irq;
struct regmap_irq_chip_data *irq_data;
};
extern const struct dev_pm_ops cs35l45_pm_ops;