From 30ad751aacb9f348e895d2fe110660d5bc440d0b Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Tue, 28 Nov 2017 12:40:22 +0530 Subject: ASoC: rmmod fixes for audio drivers For remove module(rmmod), update drivers to cleanup resources and allow insert module again without any issue. Change-Id: Iddc6e5e11d986359afd3100bf3c5eab70cb1c1eb Signed-off-by: Laxminath Kasam Signed-off-by: Meng Wang --- asoc/codecs/msm_sdw/msm_sdw.h | 6 +- asoc/codecs/msm_sdw/msm_sdw_cdc.c | 17 ++++- asoc/codecs/sdm660_cdc/msm-analog-cdc.c | 15 ++-- asoc/codecs/sdm660_cdc/msm-analog-cdc.h | 6 +- asoc/codecs/sdm660_cdc/sdm660-cdc-irq.c | 7 +- asoc/codecs/sdm660_cdc/sdm660-cdc-irq.h | 3 +- asoc/msm-dai-q6-v2.c | 3 +- dsp/audio_slimslave.c | 4 +- dsp/q6adm.c | 118 +++++++++++++++++--------------- dsp/q6afe.c | 6 ++ soc/swr-wcd-ctrl.c | 7 +- 11 files changed, 120 insertions(+), 72 deletions(-) diff --git a/asoc/codecs/msm_sdw/msm_sdw.h b/asoc/codecs/msm_sdw/msm_sdw.h index d4ac4333..3c7a07dc 100644 --- a/asoc/codecs/msm_sdw/msm_sdw.h +++ b/asoc/codecs/msm_sdw/msm_sdw.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,6 +17,7 @@ #include "msm_sdw_registers.h" #define MSM_SDW_MAX_REGISTER 0x400 +#define MSM_SDW_CHILD_DEVICES_MAX 1 extern const struct regmap_config msm_sdw_regmap_config; extern const u8 msm_sdw_page_map[MSM_SDW_MAX_REGISTER]; @@ -154,6 +155,9 @@ struct msm_sdw_priv { /* Entry for version info */ struct snd_info_entry *entry; struct snd_info_entry *version_entry; + struct platform_device *pdev_child_devices + [MSM_SDW_CHILD_DEVICES_MAX]; + int child_count; }; #if IS_ENABLED(CONFIG_SND_SOC_MSM_SDW) diff --git a/asoc/codecs/msm_sdw/msm_sdw_cdc.c b/asoc/codecs/msm_sdw/msm_sdw_cdc.c index 7a5ba8f0..3e4921d1 100644 --- a/asoc/codecs/msm_sdw/msm_sdw_cdc.c +++ b/asoc/codecs/msm_sdw/msm_sdw_cdc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1251,7 +1251,13 @@ static int msm_sdw_swrm_write(void *handle, int reg, int val) static int msm_sdw_swrm_clock(void *handle, bool enable) { - struct msm_sdw_priv *msm_sdw = (struct msm_sdw_priv *) handle; + struct msm_sdw_priv *msm_sdw; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + msm_sdw = (struct msm_sdw_priv *)handle; mutex_lock(&msm_sdw->sdw_clk_lock); @@ -1934,6 +1940,7 @@ static void msm_sdw_add_child_devices(struct work_struct *work) msm_sdw->nr = ctrl_num; msm_sdw->sdw_ctrl_data = sdw_ctrl_data; } + msm_sdw->pdev_child_devices[msm_sdw->child_count++] = pdev; } return; @@ -2050,15 +2057,21 @@ err_sdw_cdc: static int msm_sdw_remove(struct platform_device *pdev) { struct msm_sdw_priv *msm_sdw; + int count; msm_sdw = dev_get_drvdata(&pdev->dev); + for (count = 0; count < msm_sdw->child_count && + count < MSM_SDW_CHILD_DEVICES_MAX; count++) + platform_device_unregister(msm_sdw->pdev_child_devices[count]); + mutex_destroy(&msm_sdw->io_lock); mutex_destroy(&msm_sdw->sdw_read_lock); mutex_destroy(&msm_sdw->sdw_write_lock); mutex_destroy(&msm_sdw->sdw_clk_lock); mutex_destroy(&msm_sdw->codec_mutex); mutex_destroy(&msm_sdw->cdc_int_mclk1_mutex); + devm_kfree(&pdev->dev, msm_sdw); snd_soc_unregister_codec(&pdev->dev); return 0; diff --git a/asoc/codecs/sdm660_cdc/msm-analog-cdc.c b/asoc/codecs/sdm660_cdc/msm-analog-cdc.c index 9121baf0..64b99561 100644 --- a/asoc/codecs/sdm660_cdc/msm-analog-cdc.c +++ b/asoc/codecs/sdm660_cdc/msm-analog-cdc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -4396,7 +4396,7 @@ static int msm_anlg_cdc_init_supplies(struct sdm660_cdc_priv *sdm660_cdc, return ret; err_supplies: - kfree(sdm660_cdc->supplies); + devm_kfree(sdm660_cdc->dev, sdm660_cdc->supplies); err: return ret; } @@ -4442,9 +4442,6 @@ static void msm_anlg_cdc_disable_supplies(struct sdm660_cdc_priv *sdm660_cdc, pdata->regulator[i].max_uv); regulator_set_load(sdm660_cdc->supplies[i].consumer, 0); } - regulator_bulk_free(sdm660_cdc->num_of_supplies, - sdm660_cdc->supplies); - kfree(sdm660_cdc->supplies); } static const struct of_device_id sdm660_codec_of_match[] = { @@ -4531,6 +4528,7 @@ static void msm_anlg_add_child_devices(struct work_struct *work) __func__); pdata->dig_ctrl_data = dig_ctrl_data; } + pdata->pdev_child_devices[pdata->child_count++] = pdev; } return; @@ -4639,9 +4637,16 @@ static int msm_anlg_cdc_remove(struct platform_device *pdev) { struct sdm660_cdc_priv *sdm660_cdc = dev_get_drvdata(&pdev->dev); struct sdm660_cdc_pdata *pdata = sdm660_cdc->dev->platform_data; + int count; + for (count = 0; count < sdm660_cdc->child_count && + count < ANLG_CDC_CHILD_DEVICES_MAX; count++) + platform_device_unregister( + sdm660_cdc->pdev_child_devices[count]); snd_soc_unregister_codec(&pdev->dev); msm_anlg_cdc_disable_supplies(sdm660_cdc, pdata); + wcd9xxx_spmi_irq_exit(); + devm_kfree(&pdev->dev, sdm660_cdc); return 0; } diff --git a/asoc/codecs/sdm660_cdc/msm-analog-cdc.h b/asoc/codecs/sdm660_cdc/msm-analog-cdc.h index 3ee3dee7..71d555f3 100644 --- a/asoc/codecs/sdm660_cdc/msm-analog-cdc.h +++ b/asoc/codecs/sdm660_cdc/msm-analog-cdc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,6 +21,7 @@ #define MICBIAS_EXT_BYP_CAP 0x00 #define MICBIAS_NO_EXT_BYP_CAP 0x01 +#define ANLG_CDC_CHILD_DEVICES_MAX 1 #define MSM89XX_NUM_IRQ_REGS 2 #define MAX_REGULATOR 7 @@ -215,6 +216,9 @@ struct sdm660_cdc_priv { /* Entry for version info */ struct snd_info_entry *entry; struct snd_info_entry *version_entry; + struct platform_device *pdev_child_devices + [ANLG_CDC_CHILD_DEVICES_MAX]; + int child_count; }; struct sdm660_cdc_pdata { diff --git a/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.c b/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.c index ee4ec34f..673b738b 100644 --- a/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.c +++ b/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -409,5 +409,10 @@ int wcd9xxx_spmi_irq_init(void) return 0; } +void wcd9xxx_spmi_irq_exit(void) +{ + pm_qos_remove_request(&map.pm_qos_req); + mutex_destroy(&map.pm_lock); +} MODULE_DESCRIPTION("MSM8x16 SPMI IRQ driver"); MODULE_LICENSE("GPL v2"); diff --git a/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.h b/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.h index d0f48d0c..0b9b56e1 100644 --- a/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.h +++ b/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,6 +26,7 @@ extern int wcd9xxx_spmi_free_irq(int irq, void *priv); extern void wcd9xxx_spmi_set_codec(struct snd_soc_codec *codec); extern void wcd9xxx_spmi_set_dev(struct platform_device *spmi, int i); extern int wcd9xxx_spmi_irq_init(void); +extern void wcd9xxx_spmi_irq_exit(void); extern int wcd9xxx_spmi_suspend(pm_message_t pmesg); extern int wcd9xxx_spmi_resume(void); bool wcd9xxx_spmi_lock_sleep(void); diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c index bec7fcfb..d0df70c5 100644 --- a/asoc/msm-dai-q6-v2.c +++ b/asoc/msm-dai-q6-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -8978,6 +8978,7 @@ fail: void msm_dai_q6_exit(void) { + platform_driver_unregister(&msm_dai_tdm_q6); platform_driver_unregister(&msm_dai_q6_tdm_driver); platform_driver_unregister(&msm_dai_q6_spdif_driver); platform_driver_unregister(&msm_dai_mi2s_q6); diff --git a/dsp/audio_slimslave.c b/dsp/audio_slimslave.c index 25866d12..55982f33 100644 --- a/dsp/audio_slimslave.c +++ b/dsp/audio_slimslave.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -167,7 +167,7 @@ int __init audio_slimslave_init(void) void audio_slimslave_exit(void) { - + slim_driver_unregister(&audio_slimslave_driver); } /* Module information */ diff --git a/dsp/q6adm.c b/dsp/q6adm.c index dc900edb..f8aef943 100644 --- a/dsp/q6adm.c +++ b/dsp/q6adm.c @@ -1440,10 +1440,68 @@ int adm_get_multi_ch_map(char *channel_map, int path) } EXPORT_SYMBOL(adm_get_multi_ch_map); +static void adm_reset_data(void) +{ + int i, j; + + apr_reset(this_adm.apr); + for (i = 0; i < AFE_MAX_PORTS; i++) { + for (j = 0; j < MAX_COPPS_PER_PORT; j++) { + atomic_set(&this_adm.copp.id[i][j], + RESET_COPP_ID); + atomic_set(&this_adm.copp.cnt[i][j], 0); + atomic_set( + &this_adm.copp.topology[i][j], 0); + atomic_set(&this_adm.copp.mode[i][j], + 0); + atomic_set(&this_adm.copp.stat[i][j], + 0); + atomic_set(&this_adm.copp.rate[i][j], + 0); + atomic_set( + &this_adm.copp.channels[i][j], + 0); + atomic_set( + &this_adm.copp.bit_width[i][j], 0); + atomic_set( + &this_adm.copp.app_type[i][j], 0); + atomic_set( + &this_adm.copp.acdb_id[i][j], 0); + this_adm.copp.adm_status[i][j] = + ADM_STATUS_CALIBRATION_REQUIRED; + } + } + this_adm.apr = NULL; + cal_utils_clear_cal_block_q6maps(ADM_MAX_CAL_TYPES, + this_adm.cal_data); + mutex_lock(&this_adm.cal_data + [ADM_CUSTOM_TOP_CAL]->lock); + this_adm.set_custom_topology = 1; + mutex_unlock(&this_adm.cal_data[ + ADM_CUSTOM_TOP_CAL]->lock); + rtac_clear_mapping(ADM_RTAC_CAL); + /* + * Free the ION memory and clear the map handles + * for Source Tracking + */ + if (this_adm.sourceTrackingData.memmap.paddr != 0) { + msm_audio_ion_free( + this_adm.sourceTrackingData.dma_buf); + this_adm.sourceTrackingData.dma_buf = NULL; + this_adm.sourceTrackingData.memmap.size = 0; + this_adm.sourceTrackingData.memmap.kvaddr = + NULL; + this_adm.sourceTrackingData.memmap.paddr = 0; + this_adm.sourceTrackingData.apr_cmd_status = -1; + atomic_set(&this_adm.mem_map_handles[ + ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0); + } +} + static int32_t adm_callback(struct apr_client_data *data, void *priv) { uint32_t *payload; - int i, j, port_idx, copp_idx, idx, client_id; + int i, port_idx, copp_idx, idx, client_id; if (data == NULL) { pr_err("%s: data parameter is null\n", __func__); @@ -1456,60 +1514,8 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv) pr_debug("%s: Reset event is received: %d %d apr[%pK]\n", __func__, data->reset_event, data->reset_proc, this_adm.apr); - if (this_adm.apr) { - apr_reset(this_adm.apr); - for (i = 0; i < AFE_MAX_PORTS; i++) { - for (j = 0; j < MAX_COPPS_PER_PORT; j++) { - atomic_set(&this_adm.copp.id[i][j], - RESET_COPP_ID); - atomic_set(&this_adm.copp.cnt[i][j], 0); - atomic_set( - &this_adm.copp.topology[i][j], 0); - atomic_set(&this_adm.copp.mode[i][j], - 0); - atomic_set(&this_adm.copp.stat[i][j], - 0); - atomic_set(&this_adm.copp.rate[i][j], - 0); - atomic_set( - &this_adm.copp.channels[i][j], - 0); - atomic_set( - &this_adm.copp.bit_width[i][j], 0); - atomic_set( - &this_adm.copp.app_type[i][j], 0); - atomic_set( - &this_adm.copp.acdb_id[i][j], 0); - this_adm.copp.adm_status[i][j] = - ADM_STATUS_CALIBRATION_REQUIRED; - } - } - this_adm.apr = NULL; - cal_utils_clear_cal_block_q6maps(ADM_MAX_CAL_TYPES, - this_adm.cal_data); - mutex_lock(&this_adm.cal_data - [ADM_CUSTOM_TOP_CAL]->lock); - this_adm.set_custom_topology = 1; - mutex_unlock(&this_adm.cal_data[ - ADM_CUSTOM_TOP_CAL]->lock); - rtac_clear_mapping(ADM_RTAC_CAL); - /* - * Free the ION memory and clear the map handles - * for Source Tracking - */ - if (this_adm.sourceTrackingData.memmap.paddr != 0) { - msm_audio_ion_free( - this_adm.sourceTrackingData.dma_buf); - this_adm.sourceTrackingData.dma_buf = NULL; - this_adm.sourceTrackingData.memmap.size = 0; - this_adm.sourceTrackingData.memmap.kvaddr = - NULL; - this_adm.sourceTrackingData.memmap.paddr = 0; - this_adm.sourceTrackingData.apr_cmd_status = -1; - atomic_set(&this_adm.mem_map_handles[ - ADM_MEM_MAP_INDEX_SOURCE_TRACKING], 0); - } - } + if (this_adm.apr) + adm_reset_data(); return 0; } @@ -5256,6 +5262,8 @@ int __init adm_init(void) void adm_exit(void) { + if (this_adm.apr) + adm_reset_data(); mutex_destroy(&dts_srs_lock); adm_delete_cal_data(); } diff --git a/dsp/q6afe.c b/dsp/q6afe.c index f926efbd..60e8e27b 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -7636,6 +7636,12 @@ int __init afe_init(void) void afe_exit(void) { + if (this_afe.apr) { + apr_reset(this_afe.apr); + atomic_set(&this_afe.state, 0); + this_afe.apr = NULL; + rtac_set_afe_handle(this_afe.apr); + } afe_delete_cal_data(); config_debug_fs_exit(); diff --git a/soc/swr-wcd-ctrl.c b/soc/swr-wcd-ctrl.c index dc1f7866..c2edb7a6 100644 --- a/soc/swr-wcd-ctrl.c +++ b/soc/swr-wcd-ctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1538,8 +1538,9 @@ static int swrm_remove(struct platform_device *pdev) { struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev); - swrm->reg_irq(swrm->handle, swr_mstr_interrupt, - swrm, SWR_IRQ_FREE); + if (swrm->reg_irq) + swrm->reg_irq(swrm->handle, swr_mstr_interrupt, + swrm, SWR_IRQ_FREE); if (swrm->mstr_port) { kfree(swrm->mstr_port->port); swrm->mstr_port->port = NULL; -- cgit v1.2.3