Commit 09d86dbf authored by Mark Brown's avatar Mark Brown

Improve CS35l41-based audio codec drivers

Merge series from Cristian Ciocaltea <cristian.ciocaltea@collabora.com>:

This patch series contains several fixes and improvements to drivers
based on the CS35l41 audio codec.

It has been verified on Valve's Steam Deck, except the HDA related patches.
parents 5b772c61 206b250c
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#define __CS35L41_H #define __CS35L41_H
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/completion.h>
#include <linux/firmware/cirrus/cs_dsp.h> #include <linux/firmware/cirrus/cs_dsp.h>
#define CS35L41_FIRSTREG 0x00000000 #define CS35L41_FIRSTREG 0x00000000
...@@ -902,7 +901,8 @@ int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap); ...@@ -902,7 +901,8 @@ int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap);
int cs35l41_init_boost(struct device *dev, struct regmap *regmap, int cs35l41_init_boost(struct device *dev, struct regmap *regmap,
struct cs35l41_hw_cfg *hw_cfg); struct cs35l41_hw_cfg *hw_cfg);
bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type); bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type);
int cs35l41_mdsync_up(struct regmap *regmap);
int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type, int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type,
int enable, struct completion *pll_lock, bool firmware_running); int enable, bool firmware_running);
#endif /* __CS35L41_H */ #endif /* __CS35L41_H */
...@@ -527,7 +527,7 @@ static void cs35l41_hda_play_done(struct device *dev) ...@@ -527,7 +527,7 @@ static void cs35l41_hda_play_done(struct device *dev)
dev_dbg(dev, "Play (Complete)\n"); dev_dbg(dev, "Play (Complete)\n");
cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1, NULL, cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1,
cs35l41->firmware_running); cs35l41->firmware_running);
if (cs35l41->firmware_running) { if (cs35l41->firmware_running) {
regmap_multi_reg_write(reg, cs35l41_hda_unmute_dsp, regmap_multi_reg_write(reg, cs35l41_hda_unmute_dsp,
...@@ -546,7 +546,7 @@ static void cs35l41_hda_pause_start(struct device *dev) ...@@ -546,7 +546,7 @@ static void cs35l41_hda_pause_start(struct device *dev)
dev_dbg(dev, "Pause (Start)\n"); dev_dbg(dev, "Pause (Start)\n");
regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute)); regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0, NULL, cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0,
cs35l41->firmware_running); cs35l41->firmware_running);
} }
...@@ -1550,27 +1550,27 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i ...@@ -1550,27 +1550,27 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS4, int_status, ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS4, int_status,
int_status & CS35L41_OTP_BOOT_DONE, 1000, 100000); int_status & CS35L41_OTP_BOOT_DONE, 1000, 100000);
if (ret) { if (ret) {
dev_err(cs35l41->dev, "Failed waiting for OTP_BOOT_DONE: %d\n", ret); dev_err_probe(cs35l41->dev, ret, "Failed waiting for OTP_BOOT_DONE\n");
goto err; goto err;
} }
ret = regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_sts); ret = regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_sts);
if (ret || (int_sts & CS35L41_OTP_BOOT_ERR)) { if (ret || (int_sts & CS35L41_OTP_BOOT_ERR)) {
dev_err(cs35l41->dev, "OTP Boot status %x error: %d\n", dev_err_probe(cs35l41->dev, ret, "OTP Boot status %x error\n",
int_sts & CS35L41_OTP_BOOT_ERR, ret); int_sts & CS35L41_OTP_BOOT_ERR);
ret = -EIO; ret = -EIO;
goto err; goto err;
} }
ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, &regid); ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, &regid);
if (ret) { if (ret) {
dev_err(cs35l41->dev, "Get Device ID failed: %d\n", ret); dev_err_probe(cs35l41->dev, ret, "Get Device ID failed\n");
goto err; goto err;
} }
ret = regmap_read(cs35l41->regmap, CS35L41_REVID, &reg_revid); ret = regmap_read(cs35l41->regmap, CS35L41_REVID, &reg_revid);
if (ret) { if (ret) {
dev_err(cs35l41->dev, "Get Revision ID failed: %d\n", ret); dev_err_probe(cs35l41->dev, ret, "Get Revision ID failed\n");
goto err; goto err;
} }
...@@ -1593,7 +1593,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i ...@@ -1593,7 +1593,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap); ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
if (ret) { if (ret) {
dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret); dev_err_probe(cs35l41->dev, ret, "OTP Unpack failed\n");
goto err; goto err;
} }
...@@ -1624,9 +1624,8 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i ...@@ -1624,9 +1624,8 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
ret = component_add(cs35l41->dev, &cs35l41_hda_comp_ops); ret = component_add(cs35l41->dev, &cs35l41_hda_comp_ops);
if (ret) { if (ret) {
dev_err(cs35l41->dev, "Register component failed: %d\n", ret); dev_err_probe(cs35l41->dev, ret, "Register component failed\n");
pm_runtime_disable(cs35l41->dev); goto err_pm;
goto err;
} }
dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", regid, reg_revid); dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", regid, reg_revid);
...@@ -1634,6 +1633,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i ...@@ -1634,6 +1633,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
return 0; return 0;
err_pm: err_pm:
pm_runtime_dont_use_autosuspend(cs35l41->dev);
pm_runtime_disable(cs35l41->dev); pm_runtime_disable(cs35l41->dev);
pm_runtime_put_noidle(cs35l41->dev); pm_runtime_put_noidle(cs35l41->dev);
...@@ -1652,6 +1652,7 @@ void cs35l41_hda_remove(struct device *dev) ...@@ -1652,6 +1652,7 @@ void cs35l41_hda_remove(struct device *dev)
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
pm_runtime_get_sync(cs35l41->dev); pm_runtime_get_sync(cs35l41->dev);
pm_runtime_dont_use_autosuspend(cs35l41->dev);
pm_runtime_disable(cs35l41->dev); pm_runtime_disable(cs35l41->dev);
if (cs35l41->halo_initialized) if (cs35l41->halo_initialized)
......
...@@ -35,7 +35,6 @@ static int cs35l41_i2c_probe(struct i2c_client *client) ...@@ -35,7 +35,6 @@ static int cs35l41_i2c_probe(struct i2c_client *client)
struct device *dev = &client->dev; struct device *dev = &client->dev;
struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(dev); struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(dev);
const struct regmap_config *regmap_config = &cs35l41_regmap_i2c; const struct regmap_config *regmap_config = &cs35l41_regmap_i2c;
int ret;
cs35l41 = devm_kzalloc(dev, sizeof(struct cs35l41_private), GFP_KERNEL); cs35l41 = devm_kzalloc(dev, sizeof(struct cs35l41_private), GFP_KERNEL);
...@@ -47,11 +46,9 @@ static int cs35l41_i2c_probe(struct i2c_client *client) ...@@ -47,11 +46,9 @@ static int cs35l41_i2c_probe(struct i2c_client *client)
i2c_set_clientdata(client, cs35l41); i2c_set_clientdata(client, cs35l41);
cs35l41->regmap = devm_regmap_init_i2c(client, regmap_config); cs35l41->regmap = devm_regmap_init_i2c(client, regmap_config);
if (IS_ERR(cs35l41->regmap)) { if (IS_ERR(cs35l41->regmap))
ret = PTR_ERR(cs35l41->regmap); return dev_err_probe(cs35l41->dev, PTR_ERR(cs35l41->regmap),
dev_err(cs35l41->dev, "Failed to allocate register map: %d\n", ret); "Failed to allocate register map\n");
return ret;
}
return cs35l41_probe(cs35l41, hw_cfg); return cs35l41_probe(cs35l41, hw_cfg);
} }
...@@ -83,7 +80,7 @@ MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match); ...@@ -83,7 +80,7 @@ MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match);
static struct i2c_driver cs35l41_i2c_driver = { static struct i2c_driver cs35l41_i2c_driver = {
.driver = { .driver = {
.name = "cs35l41", .name = "cs35l41",
.pm = &cs35l41_pm_ops, .pm = pm_ptr(&cs35l41_pm_ops),
.of_match_table = of_match_ptr(cs35l41_of_match), .of_match_table = of_match_ptr(cs35l41_of_match),
.acpi_match_table = ACPI_PTR(cs35l41_acpi_match), .acpi_match_table = ACPI_PTR(cs35l41_acpi_match),
}, },
......
...@@ -1192,8 +1192,28 @@ bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type) ...@@ -1192,8 +1192,28 @@ bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type)
} }
EXPORT_SYMBOL_GPL(cs35l41_safe_reset); EXPORT_SYMBOL_GPL(cs35l41_safe_reset);
/*
* Enabling the CS35L41_SHD_BOOST_ACTV and CS35L41_SHD_BOOST_PASS shared boosts
* does also require a call to cs35l41_mdsync_up(), but not before getting the
* PLL Lock signal.
*
* PLL Lock seems to be triggered soon after snd_pcm_start() is executed and
* SNDRV_PCM_TRIGGER_START command is processed, which happens (long) after the
* SND_SOC_DAPM_PRE_PMU event handler is invoked as part of snd_pcm_prepare().
*
* This event handler is where cs35l41_global_enable() is normally called from,
* but waiting for PLL Lock here will time out. Increasing the wait duration
* will not help, as the only consequence of it would be to add an unnecessary
* delay in the invocation of snd_pcm_start().
*
* Trying to move the wait in the SNDRV_PCM_TRIGGER_START callback is not a
* solution either, as the trigger is executed in an IRQ-off atomic context.
*
* The current approach is to invoke cs35l41_mdsync_up() right after receiving
* the PLL Lock interrupt, in the IRQ handler.
*/
int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type, int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type,
int enable, struct completion *pll_lock, bool firmware_running) int enable, bool firmware_running)
{ {
int ret; int ret;
unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3, int_status, pup_pdn_mask; unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3, int_status, pup_pdn_mask;
...@@ -1203,11 +1223,6 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 ...@@ -1203,11 +1223,6 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4
{CS35L41_GPIO_PAD_CONTROL, 0}, {CS35L41_GPIO_PAD_CONTROL, 0},
{CS35L41_PWR_CTRL1, 0, 3000}, {CS35L41_PWR_CTRL1, 0, 3000},
}; };
struct reg_sequence cs35l41_mdsync_up_seq[] = {
{CS35L41_PWR_CTRL3, 0},
{CS35L41_PWR_CTRL1, 0x00000000, 3000},
{CS35L41_PWR_CTRL1, 0x00000001, 3000},
};
pup_pdn_mask = enable ? CS35L41_PUP_DONE_MASK : CS35L41_PDN_DONE_MASK; pup_pdn_mask = enable ? CS35L41_PUP_DONE_MASK : CS35L41_PDN_DONE_MASK;
...@@ -1241,24 +1256,12 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 ...@@ -1241,24 +1256,12 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4
cs35l41_mdsync_down_seq[0].def = pwr_ctrl3; cs35l41_mdsync_down_seq[0].def = pwr_ctrl3;
cs35l41_mdsync_down_seq[1].def = pad_control; cs35l41_mdsync_down_seq[1].def = pad_control;
cs35l41_mdsync_down_seq[2].def = pwr_ctrl1; cs35l41_mdsync_down_seq[2].def = pwr_ctrl1;
ret = regmap_multi_reg_write(regmap, cs35l41_mdsync_down_seq, ret = regmap_multi_reg_write(regmap, cs35l41_mdsync_down_seq,
ARRAY_SIZE(cs35l41_mdsync_down_seq)); ARRAY_SIZE(cs35l41_mdsync_down_seq));
if (!enable) /* Activation to be completed later via cs35l41_mdsync_up() */
break; if (ret || enable)
return ret;
if (!pll_lock)
return -EINVAL;
ret = wait_for_completion_timeout(pll_lock, msecs_to_jiffies(1000));
if (ret == 0) {
ret = -ETIMEDOUT;
} else {
regmap_read(regmap, CS35L41_PWR_CTRL3, &pwr_ctrl3);
pwr_ctrl3 |= CS35L41_SYNC_EN_MASK;
cs35l41_mdsync_up_seq[0].def = pwr_ctrl3;
ret = regmap_multi_reg_write(regmap, cs35l41_mdsync_up_seq,
ARRAY_SIZE(cs35l41_mdsync_up_seq));
}
ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1,
int_status, int_status & pup_pdn_mask, int_status, int_status & pup_pdn_mask,
...@@ -1266,7 +1269,7 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 ...@@ -1266,7 +1269,7 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4
if (ret) if (ret)
dev_err(dev, "Enable(%d) failed: %d\n", enable, ret); dev_err(dev, "Enable(%d) failed: %d\n", enable, ret);
// Clear PUP/PDN status /* Clear PUP/PDN status */
regmap_write(regmap, CS35L41_IRQ1_STATUS1, pup_pdn_mask); regmap_write(regmap, CS35L41_IRQ1_STATUS1, pup_pdn_mask);
break; break;
case CS35L41_INT_BOOST: case CS35L41_INT_BOOST:
...@@ -1348,6 +1351,17 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 ...@@ -1348,6 +1351,17 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4
} }
EXPORT_SYMBOL_GPL(cs35l41_global_enable); EXPORT_SYMBOL_GPL(cs35l41_global_enable);
/*
* To be called after receiving the IRQ Lock interrupt, in order to complete
* any shared boost activation initiated by cs35l41_global_enable().
*/
int cs35l41_mdsync_up(struct regmap *regmap)
{
return regmap_update_bits(regmap, CS35L41_PWR_CTRL3,
CS35L41_SYNC_EN_MASK, CS35L41_SYNC_EN_MASK);
}
EXPORT_SYMBOL_GPL(cs35l41_mdsync_up);
int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg) int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg)
{ {
struct cs35l41_gpio_cfg *gpio1 = &hw_cfg->gpio1; struct cs35l41_gpio_cfg *gpio1 = &hw_cfg->gpio1;
......
...@@ -32,7 +32,6 @@ static int cs35l41_spi_probe(struct spi_device *spi) ...@@ -32,7 +32,6 @@ static int cs35l41_spi_probe(struct spi_device *spi)
const struct regmap_config *regmap_config = &cs35l41_regmap_spi; const struct regmap_config *regmap_config = &cs35l41_regmap_spi;
struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(&spi->dev); struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(&spi->dev);
struct cs35l41_private *cs35l41; struct cs35l41_private *cs35l41;
int ret;
cs35l41 = devm_kzalloc(&spi->dev, sizeof(struct cs35l41_private), GFP_KERNEL); cs35l41 = devm_kzalloc(&spi->dev, sizeof(struct cs35l41_private), GFP_KERNEL);
if (!cs35l41) if (!cs35l41)
...@@ -43,11 +42,9 @@ static int cs35l41_spi_probe(struct spi_device *spi) ...@@ -43,11 +42,9 @@ static int cs35l41_spi_probe(struct spi_device *spi)
spi_set_drvdata(spi, cs35l41); spi_set_drvdata(spi, cs35l41);
cs35l41->regmap = devm_regmap_init_spi(spi, regmap_config); cs35l41->regmap = devm_regmap_init_spi(spi, regmap_config);
if (IS_ERR(cs35l41->regmap)) { if (IS_ERR(cs35l41->regmap))
ret = PTR_ERR(cs35l41->regmap); return dev_err_probe(cs35l41->dev, PTR_ERR(cs35l41->regmap),
dev_err(&spi->dev, "Failed to allocate register map: %d\n", ret); "Failed to allocate register map\n");
return ret;
}
cs35l41->dev = &spi->dev; cs35l41->dev = &spi->dev;
cs35l41->irq = spi->irq; cs35l41->irq = spi->irq;
...@@ -83,7 +80,7 @@ MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match); ...@@ -83,7 +80,7 @@ MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match);
static struct spi_driver cs35l41_spi_driver = { static struct spi_driver cs35l41_spi_driver = {
.driver = { .driver = {
.name = "cs35l41", .name = "cs35l41",
.pm = &cs35l41_pm_ops, .pm = pm_ptr(&cs35l41_pm_ops),
.of_match_table = of_match_ptr(cs35l41_of_match), .of_match_table = of_match_ptr(cs35l41_of_match),
.acpi_match_table = ACPI_PTR(cs35l41_acpi_match), .acpi_match_table = ACPI_PTR(cs35l41_acpi_match),
}, },
......
...@@ -386,10 +386,18 @@ static irqreturn_t cs35l41_irq(int irq, void *data) ...@@ -386,10 +386,18 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
struct cs35l41_private *cs35l41 = data; struct cs35l41_private *cs35l41 = data;
unsigned int status[4] = { 0, 0, 0, 0 }; unsigned int status[4] = { 0, 0, 0, 0 };
unsigned int masks[4] = { 0, 0, 0, 0 }; unsigned int masks[4] = { 0, 0, 0, 0 };
int ret = IRQ_NONE;
unsigned int i; unsigned int i;
int ret;
pm_runtime_get_sync(cs35l41->dev); ret = pm_runtime_resume_and_get(cs35l41->dev);
if (ret < 0) {
dev_err(cs35l41->dev,
"pm_runtime_resume_and_get failed in %s: %d\n",
__func__, ret);
return IRQ_NONE;
}
ret = IRQ_NONE;
for (i = 0; i < ARRAY_SIZE(status); i++) { for (i = 0; i < ARRAY_SIZE(status); i++) {
regmap_read(cs35l41->regmap, regmap_read(cs35l41->regmap,
...@@ -459,7 +467,19 @@ static irqreturn_t cs35l41_irq(int irq, void *data) ...@@ -459,7 +467,19 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
if (status[2] & CS35L41_PLL_LOCK) { if (status[2] & CS35L41_PLL_LOCK) {
regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS3, CS35L41_PLL_LOCK); regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS3, CS35L41_PLL_LOCK);
complete(&cs35l41->pll_lock);
if (cs35l41->hw_cfg.bst_type == CS35L41_SHD_BOOST_ACTV ||
cs35l41->hw_cfg.bst_type == CS35L41_SHD_BOOST_PASS) {
ret = cs35l41_mdsync_up(cs35l41->regmap);
if (ret)
dev_err(cs35l41->dev, "MDSYNC-up failed: %d\n", ret);
else
dev_dbg(cs35l41->dev, "MDSYNC-up done\n");
dev_dbg(cs35l41->dev, "PUP-done status: %d\n",
!!(status[0] & CS35L41_PUP_DONE_MASK));
}
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
...@@ -500,11 +520,11 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, ...@@ -500,11 +520,11 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
ARRAY_SIZE(cs35l41_pup_patch)); ARRAY_SIZE(cs35l41_pup_patch));
ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type,
1, &cs35l41->pll_lock, cs35l41->dsp.cs_dsp.running); 1, cs35l41->dsp.cs_dsp.running);
break; break;
case SND_SOC_DAPM_POST_PMD: case SND_SOC_DAPM_POST_PMD:
ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type,
0, &cs35l41->pll_lock, cs35l41->dsp.cs_dsp.running); 0, cs35l41->dsp.cs_dsp.running);
regmap_multi_reg_write_bypassed(cs35l41->regmap, regmap_multi_reg_write_bypassed(cs35l41->regmap,
cs35l41_pdn_patch, cs35l41_pdn_patch,
...@@ -802,10 +822,6 @@ static const struct snd_pcm_hw_constraint_list cs35l41_constraints = { ...@@ -802,10 +822,6 @@ static const struct snd_pcm_hw_constraint_list cs35l41_constraints = {
static int cs35l41_pcm_startup(struct snd_pcm_substream *substream, static int cs35l41_pcm_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component);
reinit_completion(&cs35l41->pll_lock);
if (substream->runtime) if (substream->runtime)
return snd_pcm_hw_constraint_list(substream->runtime, 0, return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, SNDRV_PCM_HW_PARAM_RATE,
...@@ -1174,16 +1190,14 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * ...@@ -1174,16 +1190,14 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
ret = devm_regulator_bulk_get(cs35l41->dev, CS35L41_NUM_SUPPLIES, ret = devm_regulator_bulk_get(cs35l41->dev, CS35L41_NUM_SUPPLIES,
cs35l41->supplies); cs35l41->supplies);
if (ret != 0) { if (ret != 0)
dev_err(cs35l41->dev, "Failed to request core supplies: %d\n", ret); return dev_err_probe(cs35l41->dev, ret,
return ret; "Failed to request core supplies\n");
}
ret = regulator_bulk_enable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); ret = regulator_bulk_enable(CS35L41_NUM_SUPPLIES, cs35l41->supplies);
if (ret != 0) { if (ret != 0)
dev_err(cs35l41->dev, "Failed to enable core supplies: %d\n", ret); return dev_err_probe(cs35l41->dev, ret,
return ret; "Failed to enable core supplies\n");
}
/* returning NULL can be an option if in stereo mode */ /* returning NULL can be an option if in stereo mode */
cs35l41->reset_gpio = devm_gpiod_get_optional(cs35l41->dev, "reset", cs35l41->reset_gpio = devm_gpiod_get_optional(cs35l41->dev, "reset",
...@@ -1195,8 +1209,8 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * ...@@ -1195,8 +1209,8 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
dev_info(cs35l41->dev, dev_info(cs35l41->dev,
"Reset line busy, assuming shared reset\n"); "Reset line busy, assuming shared reset\n");
} else { } else {
dev_err(cs35l41->dev, dev_err_probe(cs35l41->dev, ret,
"Failed to get reset GPIO: %d\n", ret); "Failed to get reset GPIO\n");
goto err; goto err;
} }
} }
...@@ -1212,8 +1226,8 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * ...@@ -1212,8 +1226,8 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
int_status, int_status & CS35L41_OTP_BOOT_DONE, int_status, int_status & CS35L41_OTP_BOOT_DONE,
1000, 100000); 1000, 100000);
if (ret) { if (ret) {
dev_err(cs35l41->dev, dev_err_probe(cs35l41->dev, ret,
"Failed waiting for OTP_BOOT_DONE: %d\n", ret); "Failed waiting for OTP_BOOT_DONE\n");
goto err; goto err;
} }
...@@ -1226,13 +1240,13 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * ...@@ -1226,13 +1240,13 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, &regid); ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, &regid);
if (ret < 0) { if (ret < 0) {
dev_err(cs35l41->dev, "Get Device ID failed: %d\n", ret); dev_err_probe(cs35l41->dev, ret, "Get Device ID failed\n");
goto err; goto err;
} }
ret = regmap_read(cs35l41->regmap, CS35L41_REVID, &reg_revid); ret = regmap_read(cs35l41->regmap, CS35L41_REVID, &reg_revid);
if (ret < 0) { if (ret < 0) {
dev_err(cs35l41->dev, "Get Revision ID failed: %d\n", ret); dev_err_probe(cs35l41->dev, ret, "Get Revision ID failed\n");
goto err; goto err;
} }
...@@ -1257,7 +1271,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * ...@@ -1257,7 +1271,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap); ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
if (ret < 0) { if (ret < 0) {
dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret); dev_err_probe(cs35l41->dev, ret, "OTP Unpack failed\n");
goto err; goto err;
} }
...@@ -1277,13 +1291,13 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * ...@@ -1277,13 +1291,13 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
IRQF_ONESHOT | IRQF_SHARED | irq_pol, IRQF_ONESHOT | IRQF_SHARED | irq_pol,
"cs35l41", cs35l41); "cs35l41", cs35l41);
if (ret != 0) { if (ret != 0) {
dev_err(cs35l41->dev, "Failed to request IRQ: %d\n", ret); dev_err_probe(cs35l41->dev, ret, "Failed to request IRQ\n");
goto err; goto err;
} }
ret = cs35l41_set_pdata(cs35l41); ret = cs35l41_set_pdata(cs35l41);
if (ret < 0) { if (ret < 0) {
dev_err(cs35l41->dev, "Set pdata failed: %d\n", ret); dev_err_probe(cs35l41->dev, ret, "Set pdata failed\n");
goto err; goto err;
} }
...@@ -1295,8 +1309,6 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * ...@@ -1295,8 +1309,6 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
if (ret < 0) if (ret < 0)
goto err; goto err;
init_completion(&cs35l41->pll_lock);
pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000); pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000);
pm_runtime_use_autosuspend(cs35l41->dev); pm_runtime_use_autosuspend(cs35l41->dev);
pm_runtime_mark_last_busy(cs35l41->dev); pm_runtime_mark_last_busy(cs35l41->dev);
...@@ -1308,7 +1320,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * ...@@ -1308,7 +1320,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
&soc_component_dev_cs35l41, &soc_component_dev_cs35l41,
cs35l41_dai, ARRAY_SIZE(cs35l41_dai)); cs35l41_dai, ARRAY_SIZE(cs35l41_dai));
if (ret < 0) { if (ret < 0) {
dev_err(cs35l41->dev, "Register codec failed: %d\n", ret); dev_err_probe(cs35l41->dev, ret, "Register codec failed\n");
goto err_pm; goto err_pm;
} }
...@@ -1320,6 +1332,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * ...@@ -1320,6 +1332,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
return 0; return 0;
err_pm: err_pm:
pm_runtime_dont_use_autosuspend(cs35l41->dev);
pm_runtime_disable(cs35l41->dev); pm_runtime_disable(cs35l41->dev);
pm_runtime_put_noidle(cs35l41->dev); pm_runtime_put_noidle(cs35l41->dev);
...@@ -1336,6 +1349,7 @@ EXPORT_SYMBOL_GPL(cs35l41_probe); ...@@ -1336,6 +1349,7 @@ EXPORT_SYMBOL_GPL(cs35l41_probe);
void cs35l41_remove(struct cs35l41_private *cs35l41) void cs35l41_remove(struct cs35l41_private *cs35l41)
{ {
pm_runtime_get_sync(cs35l41->dev); pm_runtime_get_sync(cs35l41->dev);
pm_runtime_dont_use_autosuspend(cs35l41->dev);
pm_runtime_disable(cs35l41->dev); pm_runtime_disable(cs35l41->dev);
regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF); regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF);
...@@ -1354,7 +1368,7 @@ void cs35l41_remove(struct cs35l41_private *cs35l41) ...@@ -1354,7 +1368,7 @@ void cs35l41_remove(struct cs35l41_private *cs35l41)
} }
EXPORT_SYMBOL_GPL(cs35l41_remove); EXPORT_SYMBOL_GPL(cs35l41_remove);
static int __maybe_unused cs35l41_runtime_suspend(struct device *dev) static int cs35l41_runtime_suspend(struct device *dev)
{ {
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
...@@ -1371,7 +1385,7 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev) ...@@ -1371,7 +1385,7 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev)
return 0; return 0;
} }
static int __maybe_unused cs35l41_runtime_resume(struct device *dev) static int cs35l41_runtime_resume(struct device *dev)
{ {
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
int ret; int ret;
...@@ -1400,7 +1414,7 @@ static int __maybe_unused cs35l41_runtime_resume(struct device *dev) ...@@ -1400,7 +1414,7 @@ static int __maybe_unused cs35l41_runtime_resume(struct device *dev)
return 0; return 0;
} }
static int __maybe_unused cs35l41_sys_suspend(struct device *dev) static int cs35l41_sys_suspend(struct device *dev)
{ {
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
...@@ -1410,7 +1424,7 @@ static int __maybe_unused cs35l41_sys_suspend(struct device *dev) ...@@ -1410,7 +1424,7 @@ static int __maybe_unused cs35l41_sys_suspend(struct device *dev)
return 0; return 0;
} }
static int __maybe_unused cs35l41_sys_suspend_noirq(struct device *dev) static int cs35l41_sys_suspend_noirq(struct device *dev)
{ {
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
...@@ -1420,7 +1434,7 @@ static int __maybe_unused cs35l41_sys_suspend_noirq(struct device *dev) ...@@ -1420,7 +1434,7 @@ static int __maybe_unused cs35l41_sys_suspend_noirq(struct device *dev)
return 0; return 0;
} }
static int __maybe_unused cs35l41_sys_resume_noirq(struct device *dev) static int cs35l41_sys_resume_noirq(struct device *dev)
{ {
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
...@@ -1430,7 +1444,7 @@ static int __maybe_unused cs35l41_sys_resume_noirq(struct device *dev) ...@@ -1430,7 +1444,7 @@ static int __maybe_unused cs35l41_sys_resume_noirq(struct device *dev)
return 0; return 0;
} }
static int __maybe_unused cs35l41_sys_resume(struct device *dev) static int cs35l41_sys_resume(struct device *dev)
{ {
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
...@@ -1440,13 +1454,12 @@ static int __maybe_unused cs35l41_sys_resume(struct device *dev) ...@@ -1440,13 +1454,12 @@ static int __maybe_unused cs35l41_sys_resume(struct device *dev)
return 0; return 0;
} }
const struct dev_pm_ops cs35l41_pm_ops = { EXPORT_GPL_DEV_PM_OPS(cs35l41_pm_ops) = {
SET_RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL) RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend, cs35l41_sys_resume) SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend, cs35l41_sys_resume)
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend_noirq, cs35l41_sys_resume_noirq) NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend_noirq, cs35l41_sys_resume_noirq)
}; };
EXPORT_SYMBOL_GPL(cs35l41_pm_ops);
MODULE_DESCRIPTION("ASoC CS35L41 driver"); MODULE_DESCRIPTION("ASoC CS35L41 driver");
MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>"); MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>");
......
...@@ -33,7 +33,6 @@ struct cs35l41_private { ...@@ -33,7 +33,6 @@ struct cs35l41_private {
int irq; int irq;
/* GPIO for /RST */ /* GPIO for /RST */
struct gpio_desc *reset_gpio; struct gpio_desc *reset_gpio;
struct completion pll_lock;
}; };
int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg); int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment