Commit 354e592a authored by Mark Brown's avatar Mark Brown

Merge series "ASoC: ti: davinci-mcasp: Handle incomplete DT node gracefully"...

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
parents 1cc3245b 1b4fb70e
......@@ -76,12 +76,16 @@ struct davinci_mcasp_ruledata {
struct davinci_mcasp {
struct snd_dmaengine_dai_dma_data dma_data[2];
struct davinci_mcasp_pdata *pdata;
void __iomem *base;
u32 fifo_base;
struct device *dev;
struct snd_pcm_substream *substreams[2];
unsigned int dai_fmt;
/* Audio can not be enabled due to missing parameter(s) */
bool missing_audio_param;
/* McASP specific data */
int tdm_slots;
u32 tdm_mask[2];
......@@ -94,7 +98,6 @@ struct davinci_mcasp {
u8 bclk_div;
int streams;
u32 irq_request[2];
int dma_request[2];
int sysclk_freq;
bool bclk_master;
......@@ -1748,48 +1751,58 @@ static int mcasp_reparent_fck(struct platform_device *pdev)
return ret;
}
static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
struct platform_device *pdev)
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)
{
const struct of_device_id *match = of_match_device(mcasp_dt_ids, &pdev->dev);
struct device_node *np = pdev->dev.of_node;
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;
u32 val;
int i, ret = 0;
int i;
if (pdev->dev.platform_data) {
pdata = pdev->dev.platform_data;
pdata->dismod = DISMOD_LOW;
return pdata;
goto out;
} else if (match) {
pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
GFP_KERNEL);
if (!pdata)
return NULL;
return -ENOMEM;
} else {
/* control shouldn't reach here. something is wrong */
ret = -EINVAL;
goto nodata;
dev_err(&pdev->dev, "No compatible match found\n");
return -EINVAL;
}
ret = of_property_read_u32(np, "op-mode", &val);
if (ret >= 0)
if (of_property_read_u32(np, "op-mode", &val) == 0) {
pdata->op_mode = val;
} else {
mcasp->missing_audio_param = true;
goto out;
}
ret = of_property_read_u32(np, "tdm-slots", &val);
if (ret >= 0) {
if (of_property_read_u32(np, "tdm-slots", &val) == 0) {
if (val < 2 || val > 32) {
dev_err(&pdev->dev,
"tdm-slots must be in rage [2-32]\n");
ret = -EINVAL;
goto nodata;
dev_err(&pdev->dev, "tdm-slots must be in rage [2-32]\n");
return -EINVAL;
}
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);
......@@ -1798,61 +1811,29 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
(sizeof(*of_serial_dir) * val),
GFP_KERNEL);
if (!of_serial_dir) {
ret = -ENOMEM;
goto nodata;
}
if (!of_serial_dir)
return -ENOMEM;
for (i = 0; i < val; i++)
of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
pdata->num_serializer = val;
pdata->serial_dir = of_serial_dir;
} else {
mcasp->missing_audio_param = true;
goto out;
}
ret = of_property_match_string(np, "dma-names", "tx");
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)
if (of_property_read_u32(np, "tx-num-evt", &val) == 0)
pdata->txnumevt = val;
ret = of_property_read_u32(np, "rx-num-evt", &val);
if (ret >= 0)
if (of_property_read_u32(np, "rx-num-evt", &val) == 0)
pdata->rxnumevt = val;
ret = of_property_read_u32(np, "sram-size-playback", &val);
if (ret >= 0)
pdata->sram_size_playback = val;
ret = of_property_read_u32(np, "sram-size-capture", &val);
if (ret >= 0)
pdata->sram_size_capture = val;
if (of_property_read_u32(np, "auxclk-fs-ratio", &val) == 0)
mcasp->auxclk_fs_ratio = val;
ret = of_property_read_u32(np, "dismod", &val);
if (ret >= 0) {
if (of_property_read_u32(np, "dismod", &val) == 0) {
if (val == 0 || val == 2 || val == 3) {
pdata->dismod = DISMOD_VAL(val);
} else {
......@@ -1863,15 +1844,50 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
pdata->dismod = DISMOD_LOW;
}
return pdata;
out:
mcasp->pdata = pdata;
if (mcasp->missing_audio_param) {
if (davinci_mcasp_have_gpiochip(mcasp)) {
dev_dbg(&pdev->dev, "Missing DT parameter(s) for audio\n");
return 0;
}
dev_err(&pdev->dev, "Insufficient DT parameter(s)\n");
return -ENODEV;
}
nodata:
if (ret < 0) {
dev_err(&pdev->dev, "Error populating platform data, err %d\n",
ret);
pdata = NULL;
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;
}
}
return pdata;
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 {
......@@ -2090,7 +2106,7 @@ static const struct gpio_chip davinci_mcasp_template_chip = {
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;
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 */
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)
{
struct snd_dmaengine_dai_dma_data *dma_data;
struct resource *mem, *res, *dat;
struct davinci_mcasp_pdata *pdata;
struct resource *mem, *dat;
struct davinci_mcasp *mcasp;
char *irq_name;
int *dma;
int irq;
int ret;
......@@ -2145,12 +2145,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (!mcasp)
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");
if (!mem) {
dev_warn(&pdev->dev,
......@@ -2166,44 +2160,25 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (IS_ERR(mcasp->base))
return PTR_ERR(mcasp->base);
dev_set_drvdata(&pdev->dev, mcasp);
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;
mcasp->dev = &pdev->dev;
ret = davinci_mcasp_get_config(mcasp, pdev);
if (ret)
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;
/* All PINS as McASP */
pm_runtime_get_sync(mcasp->dev);
mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
pm_runtime_put(mcasp->dev);
irq = platform_get_irq_byname(pdev, "common");
if (irq >= 0) {
/* 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",
dev_name(&pdev->dev));
if (!irq_name) {
......@@ -2223,8 +2198,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
}
irq = platform_get_irq_byname(pdev, "rx");
if (irq >= 0) {
irq = platform_get_irq_byname_optional(pdev, "rx");
if (irq > 0) {
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx",
dev_name(&pdev->dev));
if (!irq_name) {
......@@ -2242,8 +2217,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
}
irq = platform_get_irq_byname(pdev, "tx");
if (irq >= 0) {
irq = platform_get_irq_byname_optional(pdev, "tx");
if (irq > 0) {
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx",
dev_name(&pdev->dev));
if (!irq_name) {
......@@ -2266,45 +2241,22 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp->dat_port = true;
dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
dma_data->filter_data = "tx";
if (dat)
dma_data->addr = dat->start;
else
dma_data->addr = mem->start + davinci_mcasp_txdma_offset(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;
dma_data->addr = mem->start + davinci_mcasp_txdma_offset(mcasp->pdata);
/* 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 */
if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
dma_data->filter_data = "rx";
if (dat)
dma_data->addr = dat->start;
else
dma_data->addr =
mem->start + davinci_mcasp_rxdma_offset(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;
mem->start + davinci_mcasp_rxdma_offset(mcasp->pdata);
}
if (mcasp->version < MCASP_VERSION_3) {
......@@ -2344,24 +2296,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (ret)
goto err;
dev_set_drvdata(&pdev->dev, mcasp);
mcasp_reparent_fck(pdev);
/* All PINS as McASP */
pm_runtime_get_sync(mcasp->dev);
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);
ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
&davinci_mcasp_dai[mcasp->op_mode], 1);
if (ret != 0)
goto err;
......@@ -2389,8 +2327,14 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
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:
pm_runtime_disable(&pdev->dev);
return ret;
......
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