Browse Source

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 <[email protected]>
Signed-off-by: Meng Wang <[email protected]>
Laxminath Kasam 7 years ago
parent
commit
30ad751aac

+ 5 - 1
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)

+ 15 - 2
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;

+ 10 - 5
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;
 }
 

+ 5 - 1
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 {

+ 6 - 1
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");

+ 2 - 1
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);

+ 2 - 1
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);

+ 2 - 2
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 */

+ 63 - 55
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();
 }

+ 6 - 0
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();

+ 4 - 3
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;