mirror of
https://github.com/torvalds/linux.git
synced 2024-12-05 02:23:16 +00:00
6c9e9046e1
The lockdep mechanism revealed an unbalanced unlocking on MT8186:
[ 2.993966] WARNING: bad unlock balance detected!
[ 2.993978] -------------------------------------
[ 2.993983] kworker/u16:1/10 is trying to release lock (gpio_request_mutex) at:
[ 2.993994] [<ffffffdcd9adebf8>] mt8186_afe_gpio_request+0xf8/0x210
[ 2.994012] but there are no more locks to release!
The cause is that the mutex will be double unlocked if dai is unknown
during GPIO selection, and this patch fixes it.
Fixes: cfa9a966f1
("ASoC: mediatek: mt8186: support gpio control in platform driver")
Signed-off-by: Fei Shao <fshao@chromium.org>
Link: https://lore.kernel.org/r/20220617111003.2014395-1-fshao@chromium.org
Signed-off-by: Mark Brown <broonie@kernel.org>
244 lines
6.4 KiB
C
244 lines
6.4 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
//
|
|
// mt8186-afe-gpio.c -- Mediatek 8186 afe gpio ctrl
|
|
//
|
|
// Copyright (c) 2022 MediaTek Inc.
|
|
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
|
|
|
|
#include <linux/gpio.h>
|
|
#include <linux/pinctrl/consumer.h>
|
|
|
|
#include "mt8186-afe-common.h"
|
|
#include "mt8186-afe-gpio.h"
|
|
|
|
struct pinctrl *aud_pinctrl;
|
|
|
|
enum mt8186_afe_gpio {
|
|
MT8186_AFE_GPIO_CLK_MOSI_OFF,
|
|
MT8186_AFE_GPIO_CLK_MOSI_ON,
|
|
MT8186_AFE_GPIO_CLK_MISO_OFF,
|
|
MT8186_AFE_GPIO_CLK_MISO_ON,
|
|
MT8186_AFE_GPIO_DAT_MISO_OFF,
|
|
MT8186_AFE_GPIO_DAT_MISO_ON,
|
|
MT8186_AFE_GPIO_DAT_MOSI_OFF,
|
|
MT8186_AFE_GPIO_DAT_MOSI_ON,
|
|
MT8186_AFE_GPIO_I2S0_OFF,
|
|
MT8186_AFE_GPIO_I2S0_ON,
|
|
MT8186_AFE_GPIO_I2S1_OFF,
|
|
MT8186_AFE_GPIO_I2S1_ON,
|
|
MT8186_AFE_GPIO_I2S2_OFF,
|
|
MT8186_AFE_GPIO_I2S2_ON,
|
|
MT8186_AFE_GPIO_I2S3_OFF,
|
|
MT8186_AFE_GPIO_I2S3_ON,
|
|
MT8186_AFE_GPIO_TDM_OFF,
|
|
MT8186_AFE_GPIO_TDM_ON,
|
|
MT8186_AFE_GPIO_PCM_OFF,
|
|
MT8186_AFE_GPIO_PCM_ON,
|
|
MT8186_AFE_GPIO_GPIO_NUM
|
|
};
|
|
|
|
struct audio_gpio_attr {
|
|
const char *name;
|
|
bool gpio_prepare;
|
|
struct pinctrl_state *gpioctrl;
|
|
};
|
|
|
|
static struct audio_gpio_attr aud_gpios[MT8186_AFE_GPIO_GPIO_NUM] = {
|
|
[MT8186_AFE_GPIO_CLK_MOSI_OFF] = {"aud_clk_mosi_off", false, NULL},
|
|
[MT8186_AFE_GPIO_CLK_MOSI_ON] = {"aud_clk_mosi_on", false, NULL},
|
|
[MT8186_AFE_GPIO_CLK_MISO_OFF] = {"aud_clk_miso_off", false, NULL},
|
|
[MT8186_AFE_GPIO_CLK_MISO_ON] = {"aud_clk_miso_on", false, NULL},
|
|
[MT8186_AFE_GPIO_DAT_MISO_OFF] = {"aud_dat_miso_off", false, NULL},
|
|
[MT8186_AFE_GPIO_DAT_MISO_ON] = {"aud_dat_miso_on", false, NULL},
|
|
[MT8186_AFE_GPIO_DAT_MOSI_OFF] = {"aud_dat_mosi_off", false, NULL},
|
|
[MT8186_AFE_GPIO_DAT_MOSI_ON] = {"aud_dat_mosi_on", false, NULL},
|
|
[MT8186_AFE_GPIO_I2S0_OFF] = {"aud_gpio_i2s0_off", false, NULL},
|
|
[MT8186_AFE_GPIO_I2S0_ON] = {"aud_gpio_i2s0_on", false, NULL},
|
|
[MT8186_AFE_GPIO_I2S1_OFF] = {"aud_gpio_i2s1_off", false, NULL},
|
|
[MT8186_AFE_GPIO_I2S1_ON] = {"aud_gpio_i2s1_on", false, NULL},
|
|
[MT8186_AFE_GPIO_I2S2_OFF] = {"aud_gpio_i2s2_off", false, NULL},
|
|
[MT8186_AFE_GPIO_I2S2_ON] = {"aud_gpio_i2s2_on", false, NULL},
|
|
[MT8186_AFE_GPIO_I2S3_OFF] = {"aud_gpio_i2s3_off", false, NULL},
|
|
[MT8186_AFE_GPIO_I2S3_ON] = {"aud_gpio_i2s3_on", false, NULL},
|
|
[MT8186_AFE_GPIO_TDM_OFF] = {"aud_gpio_tdm_off", false, NULL},
|
|
[MT8186_AFE_GPIO_TDM_ON] = {"aud_gpio_tdm_on", false, NULL},
|
|
[MT8186_AFE_GPIO_PCM_OFF] = {"aud_gpio_pcm_off", false, NULL},
|
|
[MT8186_AFE_GPIO_PCM_ON] = {"aud_gpio_pcm_on", false, NULL},
|
|
};
|
|
|
|
static DEFINE_MUTEX(gpio_request_mutex);
|
|
|
|
int mt8186_afe_gpio_init(struct device *dev)
|
|
{
|
|
int i, j, ret;
|
|
|
|
aud_pinctrl = devm_pinctrl_get(dev);
|
|
if (IS_ERR(aud_pinctrl)) {
|
|
ret = PTR_ERR(aud_pinctrl);
|
|
dev_err(dev, "%s(), ret %d, cannot get aud_pinctrl!\n",
|
|
__func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(aud_gpios); i++) {
|
|
aud_gpios[i].gpioctrl = pinctrl_lookup_state(aud_pinctrl,
|
|
aud_gpios[i].name);
|
|
if (IS_ERR(aud_gpios[i].gpioctrl)) {
|
|
ret = PTR_ERR(aud_gpios[i].gpioctrl);
|
|
dev_info(dev, "%s(), pinctrl_lookup_state %s fail, ret %d\n",
|
|
__func__, aud_gpios[i].name, ret);
|
|
} else {
|
|
aud_gpios[i].gpio_prepare = true;
|
|
}
|
|
}
|
|
|
|
/* gpio status init */
|
|
for (i = MT8186_DAI_ADDA; i <= MT8186_DAI_TDM_IN; i++) {
|
|
for (j = 0; j <= 1; j++)
|
|
mt8186_afe_gpio_request(dev, false, i, j);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(mt8186_afe_gpio_init);
|
|
|
|
static int mt8186_afe_gpio_select(struct device *dev,
|
|
enum mt8186_afe_gpio type)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (type < 0 || type >= MT8186_AFE_GPIO_GPIO_NUM) {
|
|
dev_err(dev, "%s(), error, invalid gpio type %d\n",
|
|
__func__, type);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!aud_gpios[type].gpio_prepare) {
|
|
dev_err(dev, "%s(), error, gpio type %d not prepared\n",
|
|
__func__, type);
|
|
return -EIO;
|
|
}
|
|
|
|
ret = pinctrl_select_state(aud_pinctrl,
|
|
aud_gpios[type].gpioctrl);
|
|
if (ret) {
|
|
dev_err(dev, "%s(), error, can not set gpio type %d\n",
|
|
__func__, type);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt8186_afe_gpio_adda_dl(struct device *dev, bool enable)
|
|
{
|
|
int ret;
|
|
|
|
if (enable) {
|
|
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_ON);
|
|
if (ret) {
|
|
dev_err(dev, "%s(), MOSI CLK ON select fail!\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_ON);
|
|
if (ret) {
|
|
dev_err(dev, "%s(), MOSI DAT ON select fail!\n", __func__);
|
|
return ret;
|
|
}
|
|
} else {
|
|
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_OFF);
|
|
if (ret) {
|
|
dev_err(dev, "%s(), MOSI DAT OFF select fail!\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_OFF);
|
|
if (ret) {
|
|
dev_err(dev, "%s(), MOSI CLK ON select fail!\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt8186_afe_gpio_adda_ul(struct device *dev, bool enable)
|
|
{
|
|
int ret;
|
|
|
|
if (enable) {
|
|
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_ON);
|
|
if (ret) {
|
|
dev_err(dev, "%s(), MISO CLK ON slect fail!\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_ON);
|
|
if (ret) {
|
|
dev_err(dev, "%s(), MISO DAT ON slect fail!\n", __func__);
|
|
return ret;
|
|
}
|
|
} else {
|
|
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_OFF);
|
|
if (ret) {
|
|
dev_err(dev, "%s(), MISO DAT OFF slect fail!\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_OFF);
|
|
if (ret) {
|
|
dev_err(dev, "%s(), MISO CLK OFF slect fail!\n", __func__);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mt8186_afe_gpio_request(struct device *dev, bool enable,
|
|
int dai, int uplink)
|
|
{
|
|
enum mt8186_afe_gpio sel;
|
|
int ret = -EINVAL;
|
|
|
|
mutex_lock(&gpio_request_mutex);
|
|
|
|
switch (dai) {
|
|
case MT8186_DAI_ADDA:
|
|
if (uplink)
|
|
ret = mt8186_afe_gpio_adda_ul(dev, enable);
|
|
else
|
|
ret = mt8186_afe_gpio_adda_dl(dev, enable);
|
|
goto unlock;
|
|
case MT8186_DAI_I2S_0:
|
|
sel = enable ? MT8186_AFE_GPIO_I2S0_ON : MT8186_AFE_GPIO_I2S0_OFF;
|
|
break;
|
|
case MT8186_DAI_I2S_1:
|
|
sel = enable ? MT8186_AFE_GPIO_I2S1_ON : MT8186_AFE_GPIO_I2S1_OFF;
|
|
break;
|
|
case MT8186_DAI_I2S_2:
|
|
sel = enable ? MT8186_AFE_GPIO_I2S2_ON : MT8186_AFE_GPIO_I2S2_OFF;
|
|
break;
|
|
case MT8186_DAI_I2S_3:
|
|
sel = enable ? MT8186_AFE_GPIO_I2S3_ON : MT8186_AFE_GPIO_I2S3_OFF;
|
|
break;
|
|
case MT8186_DAI_TDM_IN:
|
|
sel = enable ? MT8186_AFE_GPIO_TDM_ON : MT8186_AFE_GPIO_TDM_OFF;
|
|
break;
|
|
case MT8186_DAI_PCM:
|
|
sel = enable ? MT8186_AFE_GPIO_PCM_ON : MT8186_AFE_GPIO_PCM_OFF;
|
|
break;
|
|
default:
|
|
dev_err(dev, "%s(), invalid dai %d\n", __func__, dai);
|
|
goto unlock;
|
|
}
|
|
|
|
ret = mt8186_afe_gpio_select(dev, sel);
|
|
|
|
unlock:
|
|
mutex_unlock(&gpio_request_mutex);
|
|
|
|
return ret;
|
|
}
|