summaryrefslogtreecommitdiff
path: root/drivers/mfd/cs42l43.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/cs42l43.c')
-rw-r--r--drivers/mfd/cs42l43.c83
1 files changed, 56 insertions, 27 deletions
diff --git a/drivers/mfd/cs42l43.c b/drivers/mfd/cs42l43.c
index ae8fd37afb75..107cfb983fec 100644
--- a/drivers/mfd/cs42l43.c
+++ b/drivers/mfd/cs42l43.c
@@ -29,7 +29,7 @@
#define CS42L43_RESET_DELAY_MS 20
-#define CS42L43_SDW_ATTACH_TIMEOUT_MS 500
+#define CS42L43_SDW_ATTACH_TIMEOUT_MS 5000
#define CS42L43_SDW_DETACH_TIMEOUT_MS 100
#define CS42L43_MCU_BOOT_STAGE1 1
@@ -48,6 +48,7 @@
#define CS42L43_MCU_SUPPORTED_REV 0x2105
#define CS42L43_MCU_SHADOW_REGS_REQUIRED_REV 0x2200
+#define CS42L43_BIOS_SHADOW_REGS_REQUIRED_REV 0x1002
#define CS42L43_MCU_SUPPORTED_BIOS_REV 0x0001
#define CS42L43_VDDP_DELAY_US 50
@@ -264,7 +265,7 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = {
{ CS42L43_ASRC_MASK, 0x0000000F },
{ CS42L43_HPOUT_MASK, 0x00000003 },
};
-EXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, MFD_CS42L43);
+EXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, "MFD_CS42L43");
bool cs42l43_readable_register(struct device *dev, unsigned int reg)
{
@@ -392,7 +393,7 @@ bool cs42l43_readable_register(struct device *dev, unsigned int reg)
return false;
}
}
-EXPORT_SYMBOL_NS_GPL(cs42l43_readable_register, MFD_CS42L43);
+EXPORT_SYMBOL_NS_GPL(cs42l43_readable_register, "MFD_CS42L43");
bool cs42l43_precious_register(struct device *dev, unsigned int reg)
{
@@ -407,7 +408,7 @@ bool cs42l43_precious_register(struct device *dev, unsigned int reg)
return false;
}
}
-EXPORT_SYMBOL_NS_GPL(cs42l43_precious_register, MFD_CS42L43);
+EXPORT_SYMBOL_NS_GPL(cs42l43_precious_register, "MFD_CS42L43");
bool cs42l43_volatile_register(struct device *dev, unsigned int reg)
{
@@ -435,7 +436,7 @@ bool cs42l43_volatile_register(struct device *dev, unsigned int reg)
return cs42l43_precious_register(dev, reg);
}
}
-EXPORT_SYMBOL_NS_GPL(cs42l43_volatile_register, MFD_CS42L43);
+EXPORT_SYMBOL_NS_GPL(cs42l43_volatile_register, "MFD_CS42L43");
#define CS42L43_IRQ_OFFSET(reg) ((CS42L43_##reg##_INT) - CS42L43_DECIM_INT)
@@ -773,7 +774,8 @@ static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43)
* Later versions of the firmwware require the driver to access some
* features through a set of shadow registers.
*/
- shadow = mcu_rev >= CS42L43_MCU_SHADOW_REGS_REQUIRED_REV;
+ shadow = (mcu_rev >= CS42L43_MCU_SHADOW_REGS_REQUIRED_REV) ||
+ (bios_rev >= CS42L43_BIOS_SHADOW_REGS_REQUIRED_REV);
ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_CONTROL, &secure_cfg);
if (ret) {
@@ -960,14 +962,12 @@ static void cs42l43_boot_work(struct work_struct *work)
goto err;
}
- pm_runtime_mark_last_busy(cs42l43->dev);
pm_runtime_put_autosuspend(cs42l43->dev);
return;
err:
pm_runtime_put_sync(cs42l43->dev);
- cs42l43_dev_remove(cs42l43);
}
static int cs42l43_power_up(struct cs42l43 *cs42l43)
@@ -983,7 +983,7 @@ static int cs42l43_power_up(struct cs42l43 *cs42l43)
/* vdd-p must be on for 50uS before any other supply */
usleep_range(CS42L43_VDDP_DELAY_US, 2 * CS42L43_VDDP_DELAY_US);
- gpiod_set_value_cansleep(cs42l43->reset, 1);
+ gpiod_set_raw_value_cansleep(cs42l43->reset, 1);
ret = regulator_bulk_enable(CS42L43_N_SUPPLIES, cs42l43->core_supplies);
if (ret) {
@@ -1004,7 +1004,7 @@ static int cs42l43_power_up(struct cs42l43 *cs42l43)
err_core_supplies:
regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies);
err_reset:
- gpiod_set_value_cansleep(cs42l43->reset, 0);
+ gpiod_set_raw_value_cansleep(cs42l43->reset, 0);
regulator_disable(cs42l43->vdd_p);
return ret;
@@ -1026,7 +1026,7 @@ static int cs42l43_power_down(struct cs42l43 *cs42l43)
return ret;
}
- gpiod_set_value_cansleep(cs42l43->reset, 0);
+ gpiod_set_raw_value_cansleep(cs42l43->reset, 0);
ret = regulator_disable(cs42l43->vdd_p);
if (ret) {
@@ -1037,6 +1037,15 @@ static int cs42l43_power_down(struct cs42l43 *cs42l43)
return 0;
}
+static void cs42l43_dev_remove(void *data)
+{
+ struct cs42l43 *cs42l43 = data;
+
+ cancel_work_sync(&cs42l43->boot_work);
+
+ cs42l43_power_down(cs42l43);
+}
+
int cs42l43_dev_probe(struct cs42l43 *cs42l43)
{
int i, ret;
@@ -1051,11 +1060,13 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43)
regcache_cache_only(cs42l43->regmap, true);
- cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_LOW);
+ cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(cs42l43->reset))
return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->reset),
"Failed to get reset\n");
+ gpiod_set_raw_value_cansleep(cs42l43->reset, 0);
+
cs42l43->vdd_p = devm_regulator_get(cs42l43->dev, "vdd-p");
if (IS_ERR(cs42l43->vdd_p))
return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_p),
@@ -1081,6 +1092,10 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43)
if (ret)
return ret;
+ ret = devm_add_action_or_reset(cs42l43->dev, cs42l43_dev_remove, cs42l43);
+ if (ret)
+ return ret;
+
pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME_MS);
pm_runtime_use_autosuspend(cs42l43->dev);
pm_runtime_set_active(cs42l43->dev);
@@ -1097,27 +1112,20 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, MFD_CS42L43);
-
-void cs42l43_dev_remove(struct cs42l43 *cs42l43)
-{
- cs42l43_power_down(cs42l43);
-}
-EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, MFD_CS42L43);
+EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, "MFD_CS42L43");
static int cs42l43_suspend(struct device *dev)
{
struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
int ret;
- /*
- * Don't care about being resumed here, but the driver does want
- * force_resume to always trigger an actual resume, so that register
- * state for the MCU/GPIOs is returned as soon as possible after system
- * resume. force_resume will resume if the reference count is resumed on
- * suspend hence the get_noresume.
- */
- pm_runtime_get_noresume(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to resume for suspend: %d\n", ret);
+ return ret;
+ }
+
+ disable_irq(cs42l43->irq);
ret = pm_runtime_force_suspend(dev);
if (ret) {
@@ -1135,6 +1143,24 @@ static int cs42l43_suspend(struct device *dev)
return 0;
}
+static int cs42l43_suspend_noirq(struct device *dev)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+
+ enable_irq(cs42l43->irq);
+
+ return 0;
+}
+
+static int cs42l43_resume_noirq(struct device *dev)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+
+ disable_irq(cs42l43->irq);
+
+ return 0;
+}
+
static int cs42l43_resume(struct device *dev)
{
struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
@@ -1150,6 +1176,8 @@ static int cs42l43_resume(struct device *dev)
return ret;
}
+ enable_irq(cs42l43->irq);
+
return 0;
}
@@ -1211,6 +1239,7 @@ err:
EXPORT_NS_GPL_DEV_PM_OPS(cs42l43_pm_ops, MFD_CS42L43) = {
SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_suspend_noirq, cs42l43_resume_noirq)
RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL)
};