Merge series "ASoC: ti: davinci-mcasp: Handle incomplete DT node gracefully" from Peter Ujfalusi <peter.ujfalusi@ti.com>:

Hi,

The series is inspired by the effort to standardize TI's arm64 dtsi files to keep
all nodes in 'okay' state and let the board dts files disable not needed
peripherals (and not properly configured):
https://lore.kernel.org/lkml/20201104224356.18040-1-nm@ti.com/

In the unlikely (or likely?) event when the dts misses to disable the McASP node
which is not configured we currenly and luckily just manage to not crash as we
had fixup code in place for legacy pdata boots.
This however prints out a message which does not really help to identify the
issue.

This series will reduce some of the noise during boot (first patch) then
adds the needed changes to handle the variations of 'okay':
A - have all required DT properties for audio
B - gpiochip is enabled

A && !B  -> everything is OK for audio, no gpiochip registered
A && B   -> everything is OK for audio, gpiochip is registered
!A && B  -> audio is not OK, gpiochip is registered. dev_dbg() for audio and do
            not register SOC DAI and PCM
!A && !B ->  audio is not OK, no gpiochip. dev_err() and fail the probe

Regards,
Peter
---
Peter Ujfalusi (4):
  ASoC: ti: davinci-mcasp: Use platform_get_irq_byname_optional
  ASoC: ti: davinci-mcasp: Remove legacy dma_request parsing
  ASoC: ti: davinci-mcasp: Simplify the configuration parameter handling
  ASoC: ti: davinci-mcasp: Handle missing required DT properties

 sound/soc/ti/davinci-mcasp.c | 294 ++++++++++++++---------------------
 1 file changed, 119 insertions(+), 175 deletions(-)

--
Peter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
This commit is contained in:
Mark Brown 2020-11-09 19:43:31 +00:00
Родитель 1cc3245b2c 1b4fb70e5b
Коммит 354e592a50
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 24D68B725D5487D0
1 изменённых файлов: 120 добавлений и 176 удалений

Просмотреть файл

@ -76,12 +76,16 @@ struct davinci_mcasp_ruledata {
struct davinci_mcasp { struct davinci_mcasp {
struct snd_dmaengine_dai_dma_data dma_data[2]; struct snd_dmaengine_dai_dma_data dma_data[2];
struct davinci_mcasp_pdata *pdata;
void __iomem *base; void __iomem *base;
u32 fifo_base; u32 fifo_base;
struct device *dev; struct device *dev;
struct snd_pcm_substream *substreams[2]; struct snd_pcm_substream *substreams[2];
unsigned int dai_fmt; unsigned int dai_fmt;
/* Audio can not be enabled due to missing parameter(s) */
bool missing_audio_param;
/* McASP specific data */ /* McASP specific data */
int tdm_slots; int tdm_slots;
u32 tdm_mask[2]; u32 tdm_mask[2];
@ -94,7 +98,6 @@ struct davinci_mcasp {
u8 bclk_div; u8 bclk_div;
int streams; int streams;
u32 irq_request[2]; u32 irq_request[2];
int dma_request[2];
int sysclk_freq; int sysclk_freq;
bool bclk_master; bool bclk_master;
@ -1748,48 +1751,58 @@ err1:
return ret; return ret;
} }
static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( static bool davinci_mcasp_have_gpiochip(struct davinci_mcasp *mcasp)
{
#ifdef CONFIG_OF_GPIO
if (mcasp->dev->of_node &&
of_property_read_bool(mcasp->dev->of_node, "gpio-controller"))
return true;
#endif
return false;
}
static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp,
struct platform_device *pdev) struct platform_device *pdev)
{ {
const struct of_device_id *match = of_match_device(mcasp_dt_ids, &pdev->dev);
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct davinci_mcasp_pdata *pdata = NULL; struct davinci_mcasp_pdata *pdata = NULL;
const struct of_device_id *match =
of_match_device(mcasp_dt_ids, &pdev->dev);
struct of_phandle_args dma_spec;
const u32 *of_serial_dir32; const u32 *of_serial_dir32;
u32 val; u32 val;
int i, ret = 0; int i;
if (pdev->dev.platform_data) { if (pdev->dev.platform_data) {
pdata = pdev->dev.platform_data; pdata = pdev->dev.platform_data;
pdata->dismod = DISMOD_LOW; pdata->dismod = DISMOD_LOW;
return pdata; goto out;
} else if (match) { } else if (match) {
pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata), pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
GFP_KERNEL); GFP_KERNEL);
if (!pdata) if (!pdata)
return NULL; return -ENOMEM;
} else { } else {
/* control shouldn't reach here. something is wrong */ dev_err(&pdev->dev, "No compatible match found\n");
ret = -EINVAL; return -EINVAL;
goto nodata;
} }
ret = of_property_read_u32(np, "op-mode", &val); if (of_property_read_u32(np, "op-mode", &val) == 0) {
if (ret >= 0)
pdata->op_mode = val; pdata->op_mode = val;
} else {
mcasp->missing_audio_param = true;
goto out;
}
ret = of_property_read_u32(np, "tdm-slots", &val); if (of_property_read_u32(np, "tdm-slots", &val) == 0) {
if (ret >= 0) {
if (val < 2 || val > 32) { if (val < 2 || val > 32) {
dev_err(&pdev->dev, dev_err(&pdev->dev, "tdm-slots must be in rage [2-32]\n");
"tdm-slots must be in rage [2-32]\n"); return -EINVAL;
ret = -EINVAL;
goto nodata;
} }
pdata->tdm_slots = val; pdata->tdm_slots = val;
} else if (pdata->op_mode == DAVINCI_MCASP_IIS_MODE) {
mcasp->missing_audio_param = true;
goto out;
} }
of_serial_dir32 = of_get_property(np, "serial-dir", &val); of_serial_dir32 = of_get_property(np, "serial-dir", &val);
@ -1798,61 +1811,29 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
u8 *of_serial_dir = devm_kzalloc(&pdev->dev, u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
(sizeof(*of_serial_dir) * val), (sizeof(*of_serial_dir) * val),
GFP_KERNEL); GFP_KERNEL);
if (!of_serial_dir) { if (!of_serial_dir)
ret = -ENOMEM; return -ENOMEM;
goto nodata;
}
for (i = 0; i < val; i++) for (i = 0; i < val; i++)
of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]); of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
pdata->num_serializer = val; pdata->num_serializer = val;
pdata->serial_dir = of_serial_dir; pdata->serial_dir = of_serial_dir;
} else {
mcasp->missing_audio_param = true;
goto out;
} }
ret = of_property_match_string(np, "dma-names", "tx"); if (of_property_read_u32(np, "tx-num-evt", &val) == 0)
if (ret < 0)
goto nodata;
ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
&dma_spec);
if (ret < 0)
goto nodata;
pdata->tx_dma_channel = dma_spec.args[0];
/* RX is not valid in DIT mode */
if (pdata->op_mode != DAVINCI_MCASP_DIT_MODE) {
ret = of_property_match_string(np, "dma-names", "rx");
if (ret < 0)
goto nodata;
ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
&dma_spec);
if (ret < 0)
goto nodata;
pdata->rx_dma_channel = dma_spec.args[0];
}
ret = of_property_read_u32(np, "tx-num-evt", &val);
if (ret >= 0)
pdata->txnumevt = val; pdata->txnumevt = val;
ret = of_property_read_u32(np, "rx-num-evt", &val); if (of_property_read_u32(np, "rx-num-evt", &val) == 0)
if (ret >= 0)
pdata->rxnumevt = val; pdata->rxnumevt = val;
ret = of_property_read_u32(np, "sram-size-playback", &val); if (of_property_read_u32(np, "auxclk-fs-ratio", &val) == 0)
if (ret >= 0) mcasp->auxclk_fs_ratio = val;
pdata->sram_size_playback = val;
ret = of_property_read_u32(np, "sram-size-capture", &val); if (of_property_read_u32(np, "dismod", &val) == 0) {
if (ret >= 0)
pdata->sram_size_capture = val;
ret = of_property_read_u32(np, "dismod", &val);
if (ret >= 0) {
if (val == 0 || val == 2 || val == 3) { if (val == 0 || val == 2 || val == 3) {
pdata->dismod = DISMOD_VAL(val); pdata->dismod = DISMOD_VAL(val);
} else { } else {
@ -1863,15 +1844,50 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
pdata->dismod = DISMOD_LOW; pdata->dismod = DISMOD_LOW;
} }
return pdata; out:
mcasp->pdata = pdata;
nodata: if (mcasp->missing_audio_param) {
if (ret < 0) { if (davinci_mcasp_have_gpiochip(mcasp)) {
dev_err(&pdev->dev, "Error populating platform data, err %d\n", dev_dbg(&pdev->dev, "Missing DT parameter(s) for audio\n");
ret); return 0;
pdata = NULL;
} }
return pdata;
dev_err(&pdev->dev, "Insufficient DT parameter(s)\n");
return -ENODEV;
}
mcasp->op_mode = pdata->op_mode;
/* sanity check for tdm slots parameter */
if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
if (pdata->tdm_slots < 2) {
dev_warn(&pdev->dev, "invalid tdm slots: %d\n",
pdata->tdm_slots);
mcasp->tdm_slots = 2;
} else if (pdata->tdm_slots > 32) {
dev_warn(&pdev->dev, "invalid tdm slots: %d\n",
pdata->tdm_slots);
mcasp->tdm_slots = 32;
} else {
mcasp->tdm_slots = pdata->tdm_slots;
}
}
mcasp->num_serializer = pdata->num_serializer;
#ifdef CONFIG_PM
mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
mcasp->num_serializer, sizeof(u32),
GFP_KERNEL);
if (!mcasp->context.xrsr_regs)
return -ENOMEM;
#endif
mcasp->serial_dir = pdata->serial_dir;
mcasp->version = pdata->version;
mcasp->txnumevt = pdata->txnumevt;
mcasp->rxnumevt = pdata->rxnumevt;
mcasp->dismod = pdata->dismod;
return 0;
} }
enum { enum {
@ -2090,7 +2106,7 @@ static const struct gpio_chip davinci_mcasp_template_chip = {
static int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) static int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
{ {
if (!of_property_read_bool(mcasp->dev->of_node, "gpio-controller")) if (!davinci_mcasp_have_gpiochip(mcasp))
return 0; return 0;
mcasp->gpio_chip = davinci_mcasp_template_chip; mcasp->gpio_chip = davinci_mcasp_template_chip;
@ -2110,28 +2126,12 @@ static inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
} }
#endif /* CONFIG_GPIOLIB */ #endif /* CONFIG_GPIOLIB */
static void davinci_mcasp_get_dt_params(struct davinci_mcasp *mcasp)
{
struct device_node *np = mcasp->dev->of_node;
int ret;
u32 val;
if (!np)
return;
ret = of_property_read_u32(np, "auxclk-fs-ratio", &val);
if (ret >= 0)
mcasp->auxclk_fs_ratio = val;
}
static int davinci_mcasp_probe(struct platform_device *pdev) static int davinci_mcasp_probe(struct platform_device *pdev)
{ {
struct snd_dmaengine_dai_dma_data *dma_data; struct snd_dmaengine_dai_dma_data *dma_data;
struct resource *mem, *res, *dat; struct resource *mem, *dat;
struct davinci_mcasp_pdata *pdata;
struct davinci_mcasp *mcasp; struct davinci_mcasp *mcasp;
char *irq_name; char *irq_name;
int *dma;
int irq; int irq;
int ret; int ret;
@ -2145,12 +2145,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (!mcasp) if (!mcasp)
return -ENOMEM; return -ENOMEM;
pdata = davinci_mcasp_set_pdata_from_of(pdev);
if (!pdata) {
dev_err(&pdev->dev, "no platform data\n");
return -EINVAL;
}
mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
if (!mem) { if (!mem) {
dev_warn(&pdev->dev, dev_warn(&pdev->dev,
@ -2166,44 +2160,25 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (IS_ERR(mcasp->base)) if (IS_ERR(mcasp->base))
return PTR_ERR(mcasp->base); return PTR_ERR(mcasp->base);
dev_set_drvdata(&pdev->dev, mcasp);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
mcasp->op_mode = pdata->op_mode;
/* sanity check for tdm slots parameter */
if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
if (pdata->tdm_slots < 2) {
dev_err(&pdev->dev, "invalid tdm slots: %d\n",
pdata->tdm_slots);
mcasp->tdm_slots = 2;
} else if (pdata->tdm_slots > 32) {
dev_err(&pdev->dev, "invalid tdm slots: %d\n",
pdata->tdm_slots);
mcasp->tdm_slots = 32;
} else {
mcasp->tdm_slots = pdata->tdm_slots;
}
}
mcasp->num_serializer = pdata->num_serializer;
#ifdef CONFIG_PM
mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
mcasp->num_serializer, sizeof(u32),
GFP_KERNEL);
if (!mcasp->context.xrsr_regs) {
ret = -ENOMEM;
goto err;
}
#endif
mcasp->serial_dir = pdata->serial_dir;
mcasp->version = pdata->version;
mcasp->txnumevt = pdata->txnumevt;
mcasp->rxnumevt = pdata->rxnumevt;
mcasp->dismod = pdata->dismod;
mcasp->dev = &pdev->dev; mcasp->dev = &pdev->dev;
ret = davinci_mcasp_get_config(mcasp, pdev);
if (ret)
goto err;
irq = platform_get_irq_byname(pdev, "common"); /* All PINS as McASP */
if (irq >= 0) { pm_runtime_get_sync(mcasp->dev);
mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
pm_runtime_put(mcasp->dev);
/* Skip audio related setup code if the configuration is not adequat */
if (mcasp->missing_audio_param)
goto no_audio;
irq = platform_get_irq_byname_optional(pdev, "common");
if (irq > 0) {
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common", irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common",
dev_name(&pdev->dev)); dev_name(&pdev->dev));
if (!irq_name) { if (!irq_name) {
@ -2223,8 +2198,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
} }
irq = platform_get_irq_byname(pdev, "rx"); irq = platform_get_irq_byname_optional(pdev, "rx");
if (irq >= 0) { if (irq > 0) {
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx", irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx",
dev_name(&pdev->dev)); dev_name(&pdev->dev));
if (!irq_name) { if (!irq_name) {
@ -2242,8 +2217,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
} }
irq = platform_get_irq_byname(pdev, "tx"); irq = platform_get_irq_byname_optional(pdev, "tx");
if (irq >= 0) { if (irq > 0) {
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx", irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx",
dev_name(&pdev->dev)); dev_name(&pdev->dev));
if (!irq_name) { if (!irq_name) {
@ -2266,45 +2241,22 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp->dat_port = true; mcasp->dat_port = true;
dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
dma_data->filter_data = "tx";
if (dat) if (dat)
dma_data->addr = dat->start; dma_data->addr = dat->start;
else else
dma_data->addr = mem->start + davinci_mcasp_txdma_offset(pdata); dma_data->addr = mem->start + davinci_mcasp_txdma_offset(mcasp->pdata);
dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (res)
*dma = res->start;
else
*dma = pdata->tx_dma_channel;
/* dmaengine filter data for DT and non-DT boot */
if (pdev->dev.of_node)
dma_data->filter_data = "tx";
else
dma_data->filter_data = dma;
/* RX is not valid in DIT mode */ /* RX is not valid in DIT mode */
if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
dma_data->filter_data = "rx";
if (dat) if (dat)
dma_data->addr = dat->start; dma_data->addr = dat->start;
else else
dma_data->addr = dma_data->addr =
mem->start + davinci_mcasp_rxdma_offset(pdata); mem->start + davinci_mcasp_rxdma_offset(mcasp->pdata);
dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE];
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (res)
*dma = res->start;
else
*dma = pdata->rx_dma_channel;
/* dmaengine filter data for DT and non-DT boot */
if (pdev->dev.of_node)
dma_data->filter_data = "rx";
else
dma_data->filter_data = dma;
} }
if (mcasp->version < MCASP_VERSION_3) { if (mcasp->version < MCASP_VERSION_3) {
@ -2344,24 +2296,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err; goto err;
dev_set_drvdata(&pdev->dev, mcasp);
mcasp_reparent_fck(pdev); mcasp_reparent_fck(pdev);
/* All PINS as McASP */ ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
pm_runtime_get_sync(mcasp->dev); &davinci_mcasp_dai[mcasp->op_mode], 1);
mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
pm_runtime_put(mcasp->dev);
ret = davinci_mcasp_init_gpiochip(mcasp);
if (ret)
goto err;
davinci_mcasp_get_dt_params(mcasp);
ret = devm_snd_soc_register_component(&pdev->dev,
&davinci_mcasp_component,
&davinci_mcasp_dai[pdata->op_mode], 1);
if (ret != 0) if (ret != 0)
goto err; goto err;
@ -2389,8 +2327,14 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
goto err; goto err;
} }
return 0; no_audio:
ret = davinci_mcasp_init_gpiochip(mcasp);
if (ret) {
dev_err(&pdev->dev, "gpiochip registration failed: %d\n", ret);
goto err;
}
return 0;
err: err:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
return ret; return ret;