summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/cs42l43.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/cs42l43.c')
-rw-r--r--sound/soc/codecs/cs42l43.c414
1 files changed, 306 insertions, 108 deletions
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c
index 24e718e51174..fd02d8a57e0f 100644
--- a/sound/soc/codecs/cs42l43.c
+++ b/sound/soc/codecs/cs42l43.c
@@ -6,17 +6,28 @@
// Cirrus Logic International Semiconductor Ltd.
#include <linux/bitops.h>
+#include <linux/bits.h>
+#include <linux/build_bug.h>
+#include <linux/clk.h>
+#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/bitmap.h>
#include <linux/gcd.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/jiffies.h>
#include <linux/mfd/cs42l43.h>
#include <linux/mfd/cs42l43-regs.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <linux/string.h>
+#include <linux/workqueue.h>
#include <sound/control.h>
+#include <sound/cs42l43.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc-component.h>
@@ -138,7 +149,79 @@ CS42L43_IRQ_ERROR(spkr_therm_warm)
CS42L43_IRQ_ERROR(spkl_therm_warm)
CS42L43_IRQ_ERROR(spkr_sc_detect)
CS42L43_IRQ_ERROR(spkl_sc_detect)
-CS42L43_IRQ_ERROR(hp_ilimit)
+
+static void cs42l43_hp_ilimit_clear_work(struct work_struct *work)
+{
+ struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,
+ hp_ilimit_clear_work.work);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(priv->component);
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ priv->hp_ilimit_count--;
+
+ if (priv->hp_ilimit_count)
+ queue_delayed_work(system_dfl_wq, &priv->hp_ilimit_clear_work,
+ msecs_to_jiffies(CS42L43_HP_ILIMIT_DECAY_MS));
+
+ snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static irqreturn_t cs42l43_hp_ilimit(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(priv->component);
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "headphone ilimit IRQ\n");
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ if (priv->hp_ilimit_count < CS42L43_HP_ILIMIT_MAX_COUNT) {
+ if (!priv->hp_ilimit_count)
+ queue_delayed_work(system_dfl_wq, &priv->hp_ilimit_clear_work,
+ msecs_to_jiffies(CS42L43_HP_ILIMIT_DECAY_MS));
+
+ priv->hp_ilimit_count++;
+ snd_soc_dapm_mutex_unlock(dapm);
+ return IRQ_HANDLED;
+ }
+
+ dev_err(priv->dev, "Disabling headphone for %dmS, due to frequent current limit\n",
+ CS42L43_HP_ILIMIT_BACKOFF_MS);
+
+ priv->hp_ilimited = true;
+
+ // No need to wait for disable, as just disabling for a period of time
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
+ CS42L43_HP_EN_MASK, 0);
+
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ msleep(CS42L43_HP_ILIMIT_BACKOFF_MS);
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ if (priv->hp_ena && !priv->load_detect_running) {
+ unsigned long time_left;
+
+ reinit_completion(&priv->hp_startup);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
+ CS42L43_HP_EN_MASK, priv->hp_ena);
+
+ time_left = wait_for_completion_timeout(&priv->hp_startup,
+ msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS));
+ if (!time_left)
+ dev_err(priv->dev, "ilimit HP restore timed out\n");
+ }
+
+ priv->hp_ilimited = false;
+
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return IRQ_HANDLED;
+}
#define CS42L43_IRQ_COMPLETE(name) \
static irqreturn_t cs42l43_##name(int irq, void *data) \
@@ -162,24 +245,20 @@ CS42L43_IRQ_COMPLETE(load_detect)
static irqreturn_t cs42l43_mic_shutter(int irq, void *data)
{
struct cs42l43_codec *priv = data;
- const char * const controls[] = {
- "Decimator 1 Switch",
- "Decimator 2 Switch",
- "Decimator 3 Switch",
- "Decimator 4 Switch",
- };
- int i, ret;
+ struct snd_soc_component *component = priv->component;
+ int i;
dev_dbg(priv->dev, "Microphone shutter changed\n");
- if (!priv->component)
+ if (!component)
return IRQ_NONE;
- for (i = 0; i < ARRAY_SIZE(controls); i++) {
- ret = snd_soc_component_notify_control(priv->component,
- controls[i]);
- if (ret)
+ for (i = 1; i < ARRAY_SIZE(priv->kctl); i++) {
+ if (!priv->kctl[i])
return IRQ_NONE;
+
+ snd_ctl_notify(component->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, &priv->kctl[i]->id);
}
return IRQ_HANDLED;
@@ -188,18 +267,19 @@ static irqreturn_t cs42l43_mic_shutter(int irq, void *data)
static irqreturn_t cs42l43_spk_shutter(int irq, void *data)
{
struct cs42l43_codec *priv = data;
- int ret;
+ struct snd_soc_component *component = priv->component;
dev_dbg(priv->dev, "Speaker shutter changed\n");
- if (!priv->component)
+ if (!component)
return IRQ_NONE;
- ret = snd_soc_component_notify_control(priv->component,
- "Speaker Digital Switch");
- if (ret)
+ if (!priv->kctl[0])
return IRQ_NONE;
+ snd_ctl_notify(component->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, &priv->kctl[0]->id);
+
return IRQ_HANDLED;
}
@@ -220,8 +300,9 @@ static int cs42l43_startup(struct snd_pcm_substream *substream, struct snd_soc_d
struct snd_soc_component *component = dai->component;
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
- int provider = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
- CS42L43_ASP_MASTER_MODE_MASK);
+ int provider = !dai->id || !!regmap_test_bits(cs42l43->regmap,
+ CS42L43_ASP_CLK_CONFIG2,
+ CS42L43_ASP_MASTER_MODE_MASK);
if (provider)
priv->constraint.mask = CS42L43_PROVIDER_RATE_MASK;
@@ -370,7 +451,7 @@ static int cs42l43_asp_hw_params(struct snd_pcm_substream *substream,
static int cs42l43_asp_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
int provider = regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
@@ -459,23 +540,22 @@ static int cs42l43_asp_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static void cs42l43_mask_to_slots(struct cs42l43_codec *priv, unsigned int mask, int *slots)
+static void cs42l43_mask_to_slots(struct cs42l43_codec *priv, unsigned long mask,
+ int *slots, unsigned int nslots)
{
- int i;
+ int i = 0;
+ int slot;
- for (i = 0; i < CS42L43_ASP_MAX_CHANNELS; ++i) {
- int slot = ffs(mask) - 1;
-
- if (slot < 0)
+ for_each_set_bit(slot, &mask, BITS_PER_TYPE(mask)) {
+ if (i == nslots) {
+ dev_warn(priv->dev, "Too many channels in TDM mask: %lx\n",
+ mask);
return;
+ }
- slots[i] = slot;
-
- mask &= ~(1 << slot);
+ slots[i++] = slot;
}
- if (mask)
- dev_warn(priv->dev, "Too many channels in TDM mask\n");
}
static int cs42l43_asp_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
@@ -492,13 +572,54 @@ static int cs42l43_asp_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mas
rx_mask = CS42L43_DEFAULT_SLOTS;
}
- cs42l43_mask_to_slots(priv, tx_mask, priv->tx_slots);
- cs42l43_mask_to_slots(priv, rx_mask, priv->rx_slots);
+ cs42l43_mask_to_slots(priv, tx_mask, priv->tx_slots,
+ ARRAY_SIZE(priv->tx_slots));
+ cs42l43_mask_to_slots(priv, rx_mask, priv->rx_slots,
+ ARRAY_SIZE(priv->rx_slots));
+
+ return 0;
+}
+
+static int cs42l43_dai_probe(struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ static const char * const controls[] = {
+ "Speaker Digital Switch",
+ "Decimator 1 Switch",
+ "Decimator 2 Switch",
+ "Decimator 3 Switch",
+ "Decimator 4 Switch",
+ };
+ int i;
+
+ static_assert(ARRAY_SIZE(controls) == ARRAY_SIZE(priv->kctl));
+
+ for (i = 0; i < ARRAY_SIZE(controls); i++) {
+ if (priv->kctl[i])
+ continue;
+
+ priv->kctl[i] = snd_soc_component_get_kcontrol(component, controls[i]);
+ }
+
+ return 0;
+}
+
+static int cs42l43_dai_remove(struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(priv->kctl); i++)
+ priv->kctl[i] = NULL;
return 0;
}
static const struct snd_soc_dai_ops cs42l43_asp_ops = {
+ .probe = cs42l43_dai_probe,
+ .remove = cs42l43_dai_remove,
.startup = cs42l43_startup,
.hw_params = cs42l43_asp_hw_params,
.set_fmt = cs42l43_asp_set_fmt,
@@ -516,9 +637,11 @@ static int cs42l43_sdw_hw_params(struct snd_pcm_substream *substream,
return ret;
return cs42l43_set_sample_rate(substream, params, dai);
-};
+}
static const struct snd_soc_dai_ops cs42l43_sdw_ops = {
+ .probe = cs42l43_dai_probe,
+ .remove = cs42l43_dai_remove,
.startup = cs42l43_startup,
.set_stream = cs42l43_sdw_set_stream,
.hw_params = cs42l43_sdw_hw_params,
@@ -826,8 +949,8 @@ CS42L43_DECL_MIXER(amp4, CS42L43_AMP4MIX_INPUT1);
static int cs42l43_dapm_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
snd_soc_dapm_mutex_lock(dapm);
@@ -840,8 +963,8 @@ static int cs42l43_dapm_get_volsw(struct snd_kcontrol *kcontrol,
static int cs42l43_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
snd_soc_dapm_mutex_lock(dapm);
@@ -854,8 +977,8 @@ static int cs42l43_dapm_put_volsw(struct snd_kcontrol *kcontrol,
static int cs42l43_dapm_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
snd_soc_dapm_mutex_lock(dapm);
@@ -868,8 +991,8 @@ static int cs42l43_dapm_get_enum(struct snd_kcontrol *kcontrol,
static int cs42l43_dapm_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
snd_soc_dapm_mutex_lock(dapm);
@@ -882,7 +1005,7 @@ static int cs42l43_dapm_put_enum(struct snd_kcontrol *kcontrol,
static int cs42l43_eq_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
memcpy(ucontrol->value.integer.value, priv->eq_coeffs, sizeof(priv->eq_coeffs));
@@ -893,8 +1016,8 @@ static int cs42l43_eq_get(struct snd_kcontrol *kcontrol,
static int cs42l43_eq_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
snd_soc_dapm_mutex_lock(dapm);
@@ -957,7 +1080,6 @@ static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift)
ret ? "open" : "closed");
error:
- pm_runtime_mark_last_busy(priv->dev);
pm_runtime_put_autosuspend(priv->dev);
return ret;
@@ -966,17 +1088,15 @@ error:
static int cs42l43_decim_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
int ret;
ret = cs42l43_shutter_get(priv, CS42L43_STATUS_MIC_SHUTTER_MUTE_SHIFT);
- if (ret < 0)
- return ret;
+ if (ret > 0)
+ ret = cs42l43_dapm_get_volsw(kcontrol, ucontrol);
else if (!ret)
ucontrol->value.integer.value[0] = ret;
- else
- ret = cs42l43_dapm_get_volsw(kcontrol, ucontrol);
return ret;
}
@@ -984,17 +1104,15 @@ static int cs42l43_decim_get(struct snd_kcontrol *kcontrol,
static int cs42l43_spk_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
int ret;
ret = cs42l43_shutter_get(priv, CS42L43_STATUS_SPK_SHUTTER_MUTE_SHIFT);
- if (ret < 0)
- return ret;
+ if (ret > 0)
+ ret = snd_soc_get_volsw(kcontrol, ucontrol);
else if (!ret)
ucontrol->value.integer.value[0] = ret;
- else
- ret = snd_soc_get_volsw(kcontrol, ucontrol);
return ret;
}
@@ -1002,7 +1120,7 @@ static int cs42l43_spk_get(struct snd_kcontrol *kcontrol,
static int cs42l43_spk_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
int ret;
@@ -1019,7 +1137,7 @@ static const struct snd_kcontrol_new cs42l43_controls[] = {
SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L43_ADC_B_CTRL1, CS42L43_ADC_B_CTRL2,
CS42L43_ADC_PGA_GAIN_SHIFT,
- 0xF, 5, cs42l43_adc_tlv),
+ 0xF, 4, cs42l43_adc_tlv),
SOC_DOUBLE("PDM1 Invert Switch", CS42L43_DMIC_PDM_CTRL,
CS42L43_PDM1L_INV_SHIFT, CS42L43_PDM1R_INV_SHIFT, 1, 0),
@@ -1251,10 +1369,9 @@ static int cs42l43_enable_pll(struct cs42l43_codec *priv)
dev_dbg(priv->dev, "Enabling PLL at %uHz\n", freq);
- while (freq > cs42l43_pll_configs[ARRAY_SIZE(cs42l43_pll_configs) - 1].freq) {
- div++;
- freq /= 2;
- }
+ div = fls(freq) -
+ fls(cs42l43_pll_configs[ARRAY_SIZE(cs42l43_pll_configs) - 1].freq);
+ freq >>= div;
if (div <= CS42L43_PLL_REFCLK_DIV_MASK) {
int i;
@@ -1452,13 +1569,13 @@ static int cs42l43_hp_ev(struct snd_soc_dapm_widget *w,
if (ret)
return ret;
- if (!priv->load_detect_running)
+ if (!priv->load_detect_running && !priv->hp_ilimited)
regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
mask, val);
break;
case SND_SOC_DAPM_POST_PMU:
case SND_SOC_DAPM_POST_PMD:
- if (priv->load_detect_running)
+ if (priv->load_detect_running || priv->hp_ilimited)
break;
ret = cs42l43_dapm_wait_completion(&priv->hp_startup,
@@ -2014,8 +2131,10 @@ static int cs42l43_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, cs42l43->regmap);
- cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->tx_slots);
- cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->rx_slots);
+ cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->tx_slots,
+ ARRAY_SIZE(priv->tx_slots));
+ cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->rx_slots,
+ ARRAY_SIZE(priv->rx_slots));
priv->component = component;
priv->constraint = cs42l43_constraint;
@@ -2023,10 +2142,25 @@ static int cs42l43_component_probe(struct snd_soc_component *component)
return 0;
}
+static void cs42l43_component_remove(struct snd_soc_component *component)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ cs42l43_set_jack(priv->component, NULL, NULL);
+
+ cancel_delayed_work_sync(&priv->bias_sense_timeout);
+ cancel_delayed_work_sync(&priv->tip_sense_work);
+
+ cancel_delayed_work_sync(&priv->hp_ilimit_clear_work);
+
+ priv->component = NULL;
+}
+
static const struct snd_soc_component_driver cs42l43_component_drv = {
.name = "cs42l43-codec",
.probe = cs42l43_component_probe,
+ .remove = cs42l43_component_remove,
.set_sysclk = cs42l43_set_sysclk,
.set_jack = cs42l43_set_jack,
@@ -2076,32 +2210,48 @@ static const struct cs42l43_irq cs42l43_irqs[] = {
};
static int cs42l43_request_irq(struct cs42l43_codec *priv,
- struct irq_domain *dom, const char * const name,
- unsigned int irq, irq_handler_t handler)
+ const char * const name, unsigned int irq,
+ irq_handler_t handler, unsigned long flags)
{
int ret;
- ret = irq_create_mapping(dom, irq);
+ ret = irq_create_mapping(priv->dom, irq);
if (ret < 0)
return dev_err_probe(priv->dev, ret, "Failed to map IRQ %s\n", name);
dev_dbg(priv->dev, "Request IRQ %d for %s\n", ret, name);
- ret = devm_request_threaded_irq(priv->dev, ret, NULL, handler, IRQF_ONESHOT,
- name, priv);
+ ret = devm_request_threaded_irq(priv->dev, ret, NULL, handler,
+ IRQF_ONESHOT | flags, name, priv);
if (ret)
return dev_err_probe(priv->dev, ret, "Failed to request IRQ %s\n", name);
return 0;
}
-static int cs42l43_shutter_irq(struct cs42l43_codec *priv,
- struct irq_domain *dom, unsigned int shutter,
- const char * const open_name,
- const char * const close_name,
+static void cs42l43_disable_irq(struct cs42l43_codec *priv, unsigned int irq)
+{
+ int ret;
+
+ ret = irq_find_mapping(priv->dom, irq);
+ if (ret > 0)
+ disable_irq(ret);
+}
+
+static void cs42l43_enable_irq(struct cs42l43_codec *priv, unsigned int irq)
+{
+ int ret;
+
+ ret = irq_find_mapping(priv->dom, irq);
+ if (ret > 0)
+ enable_irq(ret);
+}
+
+static int cs42l43_shutter_irq(struct cs42l43_codec *priv, unsigned int shutter,
+ const char * const open_name, unsigned int *open_irq,
+ const char * const close_name, unsigned int *close_irq,
irq_handler_t handler)
{
- unsigned int open_irq, close_irq;
int ret;
switch (shutter) {
@@ -2109,40 +2259,35 @@ static int cs42l43_shutter_irq(struct cs42l43_codec *priv,
dev_warn(priv->dev, "Manual shutters, notifications not available\n");
return 0;
case 0x2:
- open_irq = CS42L43_GPIO1_RISE;
- close_irq = CS42L43_GPIO1_FALL;
+ *open_irq = CS42L43_GPIO1_RISE;
+ *close_irq = CS42L43_GPIO1_FALL;
break;
case 0x4:
- open_irq = CS42L43_GPIO2_RISE;
- close_irq = CS42L43_GPIO2_FALL;
+ *open_irq = CS42L43_GPIO2_RISE;
+ *close_irq = CS42L43_GPIO2_FALL;
break;
case 0x8:
- open_irq = CS42L43_GPIO3_RISE;
- close_irq = CS42L43_GPIO3_FALL;
+ *open_irq = CS42L43_GPIO3_RISE;
+ *close_irq = CS42L43_GPIO3_FALL;
break;
default:
return 0;
}
- ret = cs42l43_request_irq(priv, dom, close_name, close_irq, handler);
+ ret = cs42l43_request_irq(priv, close_name, *close_irq, handler, IRQF_SHARED);
if (ret)
return ret;
- return cs42l43_request_irq(priv, dom, open_name, open_irq, handler);
+ return cs42l43_request_irq(priv, open_name, *open_irq, handler, IRQF_SHARED);
}
static int cs42l43_codec_probe(struct platform_device *pdev)
{
struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
struct cs42l43_codec *priv;
- struct irq_domain *dom;
unsigned int val;
int i, ret;
- dom = irq_find_matching_fwnode(dev_fwnode(cs42l43->dev), DOMAIN_BUS_ANY);
- if (!dom)
- return -EPROBE_DEFER;
-
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -2150,6 +2295,10 @@ static int cs42l43_codec_probe(struct platform_device *pdev)
priv->dev = &pdev->dev;
priv->core = cs42l43;
+ priv->dom = irq_find_matching_fwnode(dev_fwnode(cs42l43->dev), DOMAIN_BUS_ANY);
+ if (!priv->dom)
+ return -EPROBE_DEFER;
+
platform_set_drvdata(pdev, priv);
mutex_init(&priv->jack_lock);
@@ -2167,18 +2316,21 @@ static int cs42l43_codec_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&priv->tip_sense_work, cs42l43_tip_sense_work);
INIT_DELAYED_WORK(&priv->bias_sense_timeout, cs42l43_bias_sense_timeout);
- INIT_DELAYED_WORK(&priv->button_press_work, cs42l43_button_press_work);
- INIT_WORK(&priv->button_release_work, cs42l43_button_release_work);
+ INIT_DELAYED_WORK(&priv->hp_ilimit_clear_work, cs42l43_hp_ilimit_clear_work);
pm_runtime_set_autosuspend_delay(priv->dev, 100);
pm_runtime_use_autosuspend(priv->dev);
pm_runtime_set_active(priv->dev);
pm_runtime_get_noresume(priv->dev);
- devm_pm_runtime_enable(priv->dev);
+
+ ret = devm_pm_runtime_enable(priv->dev);
+ if (ret)
+ goto err_pm;
for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) {
- ret = cs42l43_request_irq(priv, dom, cs42l43_irqs[i].name,
- cs42l43_irqs[i].irq, cs42l43_irqs[i].handler);
+ ret = cs42l43_request_irq(priv, cs42l43_irqs[i].name,
+ cs42l43_irqs[i].irq,
+ cs42l43_irqs[i].handler, 0);
if (ret)
goto err_pm;
}
@@ -2189,15 +2341,17 @@ static int cs42l43_codec_probe(struct platform_device *pdev)
goto err_pm;
}
- ret = cs42l43_shutter_irq(priv, dom, val & CS42L43_MIC_SHUTTER_CFG_MASK,
- "mic shutter open", "mic shutter close",
+ ret = cs42l43_shutter_irq(priv, val & CS42L43_MIC_SHUTTER_CFG_MASK,
+ "mic shutter open", &priv->shutter_irqs[0],
+ "mic shutter close", &priv->shutter_irqs[1],
cs42l43_mic_shutter);
if (ret)
goto err_pm;
- ret = cs42l43_shutter_irq(priv, dom, (val & CS42L43_SPK_SHUTTER_CFG_MASK) >>
+ ret = cs42l43_shutter_irq(priv, (val & CS42L43_SPK_SHUTTER_CFG_MASK) >>
CS42L43_SPK_SHUTTER_CFG_SHIFT,
- "spk shutter open", "spk shutter close",
+ "spk shutter open", &priv->shutter_irqs[2],
+ "spk shutter close", &priv->shutter_irqs[3],
cs42l43_spk_shutter);
if (ret)
goto err_pm;
@@ -2205,7 +2359,8 @@ static int cs42l43_codec_probe(struct platform_device *pdev)
// Don't use devm as we need to get against the MFD device
priv->mclk = clk_get_optional(cs42l43->dev, "mclk");
if (IS_ERR(priv->mclk)) {
- dev_err_probe(priv->dev, PTR_ERR(priv->mclk), "Failed to get mclk\n");
+ ret = PTR_ERR(priv->mclk);
+ dev_err_probe(priv->dev, ret, "Failed to get mclk\n");
goto err_pm;
}
@@ -2216,7 +2371,6 @@ static int cs42l43_codec_probe(struct platform_device *pdev)
goto err_clk;
}
- pm_runtime_mark_last_busy(priv->dev);
pm_runtime_put_autosuspend(priv->dev);
return 0;
@@ -2229,13 +2383,11 @@ err_pm:
return ret;
}
-static int cs42l43_codec_remove(struct platform_device *pdev)
+static void cs42l43_codec_remove(struct platform_device *pdev)
{
struct cs42l43_codec *priv = platform_get_drvdata(pdev);
clk_put(priv->mclk);
-
- return 0;
}
static int cs42l43_codec_runtime_resume(struct device *dev)
@@ -2250,8 +2402,54 @@ static int cs42l43_codec_runtime_resume(struct device *dev)
return 0;
}
-DEFINE_RUNTIME_DEV_PM_OPS(cs42l43_codec_pm_ops, NULL,
- cs42l43_codec_runtime_resume, NULL);
+static int cs42l43_codec_suspend(struct device *dev)
+{
+ struct cs42l43_codec *priv = dev_get_drvdata(dev);
+ int i;
+
+ dev_dbg(priv->dev, "System suspend\n");
+
+ priv->suspend_jack_debounce = true;
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++)
+ cs42l43_disable_irq(priv, cs42l43_irqs[i].irq);
+
+ for (i = 0; i < ARRAY_SIZE(priv->shutter_irqs); i++)
+ if (priv->shutter_irqs[i])
+ cs42l43_disable_irq(priv, priv->shutter_irqs[i]);
+
+ cancel_delayed_work_sync(&priv->bias_sense_timeout);
+ cancel_delayed_work_sync(&priv->tip_sense_work);
+ cancel_delayed_work_sync(&priv->hp_ilimit_clear_work);
+
+ cs42l43_clear_jack(priv);
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static int cs42l43_codec_resume(struct device *dev)
+{
+ struct cs42l43_codec *priv = dev_get_drvdata(dev);
+ int ret, i;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++)
+ cs42l43_enable_irq(priv, cs42l43_irqs[i].irq);
+
+ for (i = 0; i < ARRAY_SIZE(priv->shutter_irqs); i++)
+ if (priv->shutter_irqs[i])
+ cs42l43_enable_irq(priv, priv->shutter_irqs[i]);
+
+ return 0;
+}
+
+static const struct dev_pm_ops cs42l43_codec_pm_ops = {
+ RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, cs42l43_codec_resume)
+};
static const struct platform_device_id cs42l43_codec_id_table[] = {
{ "cs42l43-codec", },
@@ -2262,7 +2460,7 @@ MODULE_DEVICE_TABLE(platform, cs42l43_codec_id_table);
static struct platform_driver cs42l43_codec_driver = {
.driver = {
.name = "cs42l43-codec",
- .pm = &cs42l43_codec_pm_ops,
+ .pm = pm_ptr(&cs42l43_codec_pm_ops),
},
.probe = cs42l43_codec_probe,
@@ -2271,7 +2469,7 @@ static struct platform_driver cs42l43_codec_driver = {
};
module_platform_driver(cs42l43_codec_driver);
-MODULE_IMPORT_NS(SND_SOC_CS42L43);
+MODULE_IMPORT_NS("SND_SOC_CS42L43");
MODULE_DESCRIPTION("CS42L43 CODEC Driver");
MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");