diff options
Diffstat (limited to 'sound/soc/soc-core.c')
| -rw-r--r-- | sound/soc/soc-core.c | 1833 | 
1 files changed, 1024 insertions, 809 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4d0561312f3..b87d7d882e6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -56,7 +56,6 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);  #endif  static DEFINE_MUTEX(client_mutex); -static LIST_HEAD(dai_list);  static LIST_HEAD(platform_list);  static LIST_HEAD(codec_list);  static LIST_HEAD(component_list); @@ -155,22 +154,15 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf,  		step = codec->driver->reg_cache_step;  	for (i = 0; i < codec->driver->reg_cache_size; i += step) { -		if (!snd_soc_codec_readable_register(codec, i)) -			continue; -		if (codec->driver->display_register) { -			count += codec->driver->display_register(codec, buf + count, -							 PAGE_SIZE - count, i); -		} else { -			/* only support larger than PAGE_SIZE bytes debugfs -			 * entries for the default case */ -			if (p >= pos) { -				if (total + len >= count - 1) -					break; -				format_register_str(codec, i, buf + total, len); -				total += len; -			} -			p += len; +		/* only support larger than PAGE_SIZE bytes debugfs +		 * entries for the default case */ +		if (p >= pos) { +			if (total + len >= count - 1) +				break; +			format_register_str(codec, i, buf + total, len); +			total += len;  		} +		p += len;  	}  	total = min(total, count - 1); @@ -370,18 +362,22 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,  {  	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);  	ssize_t len, ret = 0; +	struct snd_soc_component *component;  	struct snd_soc_dai *dai;  	if (!buf)  		return -ENOMEM; -	list_for_each_entry(dai, &dai_list, list) { -		len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name); -		if (len >= 0) -			ret += len; -		if (ret > PAGE_SIZE) { -			ret = PAGE_SIZE; -			break; +	list_for_each_entry(component, &component_list, list) { +		list_for_each_entry(dai, &component->dai_list, list) { +			len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", +				dai->name); +			if (len >= 0) +				ret += len; +			if (ret > PAGE_SIZE) { +				ret = PAGE_SIZE; +				break; +			}  		}  	} @@ -660,8 +656,10 @@ int snd_soc_suspend(struct device *dev)  				codec->driver->suspend(codec);  				codec->suspended = 1;  				codec->cache_sync = 1; -				if (codec->using_regmap) -					regcache_mark_dirty(codec->control_data); +				if (codec->component.regmap) +					regcache_mark_dirty(codec->component.regmap); +				/* deactivate pins to sleep state */ +				pinctrl_pm_select_sleep_state(codec->dev);  				break;  			default:  				dev_dbg(codec->dev, @@ -679,6 +677,9 @@ int snd_soc_suspend(struct device *dev)  		if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control)  			cpu_dai->driver->suspend(cpu_dai); + +		/* deactivate pins to sleep state */ +		pinctrl_pm_select_sleep_state(cpu_dai->dev);  	}  	if (card->suspend_post) @@ -807,6 +808,16 @@ int snd_soc_resume(struct device *dev)  	if (list_empty(&card->codec_dev_list))  		return 0; +	/* activate pins from sleep state */ +	for (i = 0; i < card->num_rtd; i++) { +		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; +		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai; +		if (cpu_dai->active) +			pinctrl_pm_select_default_state(cpu_dai->dev); +		if (codec_dai->active) +			pinctrl_pm_select_default_state(codec_dai->dev); +	} +  	/* AC97 devices might have other drivers hanging off them so  	 * need to resume immediately.  Other drivers don't have that  	 * problem and may take a substantial amount of time to resume @@ -836,30 +847,66 @@ EXPORT_SYMBOL_GPL(snd_soc_resume);  static const struct snd_soc_dai_ops null_dai_ops = {  }; +static struct snd_soc_codec *soc_find_codec(const struct device_node *codec_of_node, +					    const char *codec_name) +{ +	struct snd_soc_codec *codec; + +	list_for_each_entry(codec, &codec_list, list) { +		if (codec_of_node) { +			if (codec->dev->of_node != codec_of_node) +				continue; +		} else { +			if (strcmp(codec->name, codec_name)) +				continue; +		} + +		return codec; +	} + +	return NULL; +} + +static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec, +					      const char *codec_dai_name) +{ +	struct snd_soc_dai *codec_dai; + +	list_for_each_entry(codec_dai, &codec->component.dai_list, list) { +		if (!strcmp(codec_dai->name, codec_dai_name)) { +			return codec_dai; +		} +	} + +	return NULL; +} +  static int soc_bind_dai_link(struct snd_soc_card *card, int num)  {  	struct snd_soc_dai_link *dai_link = &card->dai_link[num];  	struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; -	struct snd_soc_codec *codec; +	struct snd_soc_component *component;  	struct snd_soc_platform *platform; -	struct snd_soc_dai *codec_dai, *cpu_dai; +	struct snd_soc_dai *cpu_dai;  	const char *platform_name;  	dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);  	/* Find CPU DAI from registered DAIs*/ -	list_for_each_entry(cpu_dai, &dai_list, list) { +	list_for_each_entry(component, &component_list, list) {  		if (dai_link->cpu_of_node && -		    (cpu_dai->dev->of_node != dai_link->cpu_of_node)) +			component->dev->of_node != dai_link->cpu_of_node)  			continue;  		if (dai_link->cpu_name && -		    strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name)) -			continue; -		if (dai_link->cpu_dai_name && -		    strcmp(cpu_dai->name, dai_link->cpu_dai_name)) +			strcmp(dev_name(component->dev), dai_link->cpu_name))  			continue; +		list_for_each_entry(cpu_dai, &component->dai_list, list) { +			if (dai_link->cpu_dai_name && +				strcmp(cpu_dai->name, dai_link->cpu_dai_name)) +				continue; -		rtd->cpu_dai = cpu_dai; +			rtd->cpu_dai = cpu_dai; +		}  	}  	if (!rtd->cpu_dai) { @@ -868,44 +915,24 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)  		return -EPROBE_DEFER;  	} -	/* Find CODEC from registered CODECs */ -	list_for_each_entry(codec, &codec_list, list) { -		if (dai_link->codec_of_node) { -			if (codec->dev->of_node != dai_link->codec_of_node) -				continue; -		} else { -			if (strcmp(codec->name, dai_link->codec_name)) -				continue; -		} - -		rtd->codec = codec; - -		/* -		 * CODEC found, so find CODEC DAI from registered DAIs from -		 * this CODEC -		 */ -		list_for_each_entry(codec_dai, &dai_list, list) { -			if (codec->dev == codec_dai->dev && -				!strcmp(codec_dai->name, -					dai_link->codec_dai_name)) { - -				rtd->codec_dai = codec_dai; -			} -		} - -		if (!rtd->codec_dai) { -			dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", -				dai_link->codec_dai_name); -			return -EPROBE_DEFER; -		} -	} - +	/* Find CODEC from registered list */ +	rtd->codec = soc_find_codec(dai_link->codec_of_node, +				    dai_link->codec_name);  	if (!rtd->codec) {  		dev_err(card->dev, "ASoC: CODEC %s not registered\n",  			dai_link->codec_name);  		return -EPROBE_DEFER;  	} +	/* Find CODEC DAI from registered list */ +	rtd->codec_dai = soc_find_codec_dai(rtd->codec, +					    dai_link->codec_dai_name); +	if (!rtd->codec_dai) { +		dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", +			dai_link->codec_dai_name); +		return -EPROBE_DEFER; +	} +  	/* if there's no platform we match on the empty platform */  	platform_name = dai_link->platform_name;  	if (!platform_name && !dai_link->platform_of_node) @@ -976,6 +1003,23 @@ static void soc_remove_codec(struct snd_soc_codec *codec)  	module_put(codec->dev->driver->owner);  } +static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order) +{ +	int err; + +	if (codec_dai && codec_dai->probed && +			codec_dai->driver->remove_order == order) { +		if (codec_dai->driver->remove) { +			err = codec_dai->driver->remove(codec_dai); +			if (err < 0) +				dev_err(codec_dai->dev, +					"ASoC: failed to remove %s: %d\n", +					codec_dai->name, err); +		} +		codec_dai->probed = 0; +	} +} +  static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)  {  	struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; @@ -991,18 +1035,7 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)  	}  	/* remove the CODEC DAI */ -	if (codec_dai && codec_dai->probed && -			codec_dai->driver->remove_order == order) { -		if (codec_dai->driver->remove) { -			err = codec_dai->driver->remove(codec_dai); -			if (err < 0) -				dev_err(codec_dai->dev, -					"ASoC: failed to remove %s: %d\n", -					codec_dai->name, err); -		} -		codec_dai->probed = 0; -		list_del(&codec_dai->card_list); -	} +	soc_remove_codec_dai(codec_dai, order);  	/* remove the cpu_dai */  	if (cpu_dai && cpu_dai->probed && @@ -1015,7 +1048,6 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)  					cpu_dai->name, err);  		}  		cpu_dai->probed = 0; -		list_del(&cpu_dai->card_list);  		if (!cpu_dai->codec) {  			snd_soc_dapm_free(&cpu_dai->dapm); @@ -1085,10 +1117,12 @@ static void soc_set_name_prefix(struct snd_soc_card *card,  	for (i = 0; i < card->num_configs; i++) {  		struct snd_soc_codec_conf *map = &card->codec_conf[i]; -		if (map->dev_name && !strcmp(codec->name, map->dev_name)) { -			codec->name_prefix = map->name_prefix; -			break; -		} +		if (map->of_node && codec->dev->of_node != map->of_node) +			continue; +		if (map->dev_name && strcmp(codec->name, map->dev_name)) +			continue; +		codec->name_prefix = map->name_prefix; +		break;  	}  } @@ -1108,16 +1142,27 @@ static int soc_probe_codec(struct snd_soc_card *card,  	soc_init_codec_debugfs(codec); -	if (driver->dapm_widgets) -		snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets, -					  driver->num_dapm_widgets); +	if (driver->dapm_widgets) { +		ret = snd_soc_dapm_new_controls(&codec->dapm, +						driver->dapm_widgets, +					 	driver->num_dapm_widgets); + +		if (ret != 0) { +			dev_err(codec->dev, +				"Failed to create new controls %d\n", ret); +			goto err_probe; +		} +	}  	/* Create DAPM widgets for each DAI stream */ -	list_for_each_entry(dai, &dai_list, list) { -		if (dai->dev != codec->dev) -			continue; +	list_for_each_entry(dai, &codec->component.dai_list, list) { +		ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); -		snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); +		if (ret != 0) { +			dev_err(codec->dev, +				"Failed to create DAI widgets %d\n", ret); +			goto err_probe; +		}  	}  	codec->dapm.idle_bias_off = driver->idle_bias_off; @@ -1135,10 +1180,6 @@ static int soc_probe_codec(struct snd_soc_card *card,  			codec->name);  	} -	/* If the driver didn't set I/O up try regmap */ -	if (!codec->write && dev_get_regmap(codec->dev, NULL)) -		snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); -  	if (driver->controls)  		snd_soc_add_codec_controls(codec, driver->controls,  				     driver->num_controls); @@ -1165,6 +1206,7 @@ static int soc_probe_platform(struct snd_soc_card *card,  {  	int ret = 0;  	const struct snd_soc_platform_driver *driver = platform->driver; +	struct snd_soc_component *component;  	struct snd_soc_dai *dai;  	platform->card = card; @@ -1180,11 +1222,11 @@ static int soc_probe_platform(struct snd_soc_card *card,  			driver->dapm_widgets, driver->num_dapm_widgets);  	/* Create DAPM widgets for each DAI stream */ -	list_for_each_entry(dai, &dai_list, list) { -		if (dai->dev != platform->dev) +	list_for_each_entry(component, &component_list, list) { +		if (component->dev != platform->dev)  			continue; - -		snd_soc_dapm_new_dai_widgets(&platform->dapm, dai); +		list_for_each_entry(dai, &component->dai_list, list) +			snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);  	}  	platform->dapm.idle_bias_off = 1; @@ -1224,6 +1266,50 @@ static void rtd_release(struct device *dev)  	kfree(dev);  } +static int soc_aux_dev_init(struct snd_soc_card *card, +			    struct snd_soc_codec *codec, +			    int num) +{ +	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; +	struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; +	int ret; + +	rtd->card = card; + +	/* do machine specific initialization */ +	if (aux_dev->init) { +		ret = aux_dev->init(&codec->dapm); +		if (ret < 0) +			return ret; +	} + +	rtd->codec = codec; + +	return 0; +} + +static int soc_dai_link_init(struct snd_soc_card *card, +			     struct snd_soc_codec *codec, +			     int num) +{ +	struct snd_soc_dai_link *dai_link =  &card->dai_link[num]; +	struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; +	int ret; + +	rtd->card = card; + +	/* do machine specific initialization */ +	if (dai_link->init) { +		ret = dai_link->init(rtd); +		if (ret < 0) +			return ret; +	} + +	rtd->codec = codec; + +	return 0; +} +  static int soc_post_component_init(struct snd_soc_card *card,  				   struct snd_soc_codec *codec,  				   int num, int dailess) @@ -1231,38 +1317,27 @@ static int soc_post_component_init(struct snd_soc_card *card,  	struct snd_soc_dai_link *dai_link = NULL;  	struct snd_soc_aux_dev *aux_dev = NULL;  	struct snd_soc_pcm_runtime *rtd; -	const char *temp, *name; +	const char *name;  	int ret = 0;  	if (!dailess) {  		dai_link = &card->dai_link[num];  		rtd = &card->rtd[num];  		name = dai_link->name; +		ret = soc_dai_link_init(card, codec, num);  	} else {  		aux_dev = &card->aux_dev[num];  		rtd = &card->rtd_aux[num];  		name = aux_dev->name; +		ret = soc_aux_dev_init(card, codec, num);  	} -	rtd->card = card; - -	/* machine controls, routes and widgets are not prefixed */ -	temp = codec->name_prefix; -	codec->name_prefix = NULL; -	/* do machine specific initialization */ -	if (!dailess && dai_link->init) -		ret = dai_link->init(rtd); -	else if (dailess && aux_dev->init) -		ret = aux_dev->init(&codec->dapm);  	if (ret < 0) {  		dev_err(card->dev, "ASoC: failed to init %s: %d\n", name, ret);  		return ret;  	} -	codec->name_prefix = temp;  	/* register the rtd device */ -	rtd->codec = codec; -  	rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL);  	if (!rtd->dev)  		return -ENOMEM; @@ -1349,6 +1424,66 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num,  	return 0;  } +static int soc_probe_codec_dai(struct snd_soc_card *card, +			       struct snd_soc_dai *codec_dai, +			       int order) +{ +	int ret; + +	if (!codec_dai->probed && codec_dai->driver->probe_order == order) { +		if (codec_dai->driver->probe) { +			ret = codec_dai->driver->probe(codec_dai); +			if (ret < 0) { +				dev_err(codec_dai->dev, +					"ASoC: failed to probe CODEC DAI %s: %d\n", +					codec_dai->name, ret); +				return ret; +			} +		} + +		/* mark codec_dai as probed and add to card dai list */ +		codec_dai->probed = 1; +	} + +	return 0; +} + +static int soc_link_dai_widgets(struct snd_soc_card *card, +				struct snd_soc_dai_link *dai_link, +				struct snd_soc_dai *cpu_dai, +				struct snd_soc_dai *codec_dai) +{ +	struct snd_soc_dapm_widget *play_w, *capture_w; +	int ret; + +	/* link the DAI widgets */ +	play_w = codec_dai->playback_widget; +	capture_w = cpu_dai->capture_widget; +	if (play_w && capture_w) { +		ret = snd_soc_dapm_new_pcm(card, dai_link->params, +					   capture_w, play_w); +		if (ret != 0) { +			dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", +				play_w->name, capture_w->name, ret); +			return ret; +		} +	} + +	play_w = cpu_dai->playback_widget; +	capture_w = codec_dai->capture_widget; +	if (play_w && capture_w) { +		ret = snd_soc_dapm_new_pcm(card, dai_link->params, +					   capture_w, play_w); +		if (ret != 0) { +			dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", +				play_w->name, capture_w->name, ret); +			return ret; +		} +	} + +	return 0; +} +  static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)  {  	struct snd_soc_dai_link *dai_link = &card->dai_link[num]; @@ -1357,7 +1492,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)  	struct snd_soc_platform *platform = rtd->platform;  	struct snd_soc_dai *codec_dai = rtd->codec_dai;  	struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -	struct snd_soc_dapm_widget *play_w, *capture_w;  	int ret;  	dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", @@ -1380,7 +1514,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)  				return -ENODEV;  			list_add(&cpu_dai->dapm.list, &card->dapm_list); -			snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai);  		}  		if (cpu_dai->driver->probe) { @@ -1394,26 +1527,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)  			}  		}  		cpu_dai->probed = 1; -		/* mark cpu_dai as probed and add to card dai list */ -		list_add(&cpu_dai->card_list, &card->dai_dev_list);  	}  	/* probe the CODEC DAI */ -	if (!codec_dai->probed && codec_dai->driver->probe_order == order) { -		if (codec_dai->driver->probe) { -			ret = codec_dai->driver->probe(codec_dai); -			if (ret < 0) { -				dev_err(codec_dai->dev, -					"ASoC: failed to probe CODEC DAI %s: %d\n", -					codec_dai->name, ret); -				return ret; -			} -		} - -		/* mark codec_dai as probed and add to card dai list */ -		codec_dai->probed = 1; -		list_add(&codec_dai->card_list, &card->dai_dev_list); -	} +	ret = soc_probe_codec_dai(card, codec_dai, order); +	if (ret) +		return ret;  	/* complete DAI probe during last probe */  	if (order != SND_SOC_COMP_ORDER_LAST) @@ -1451,29 +1570,10 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)  						codec2codec_close_delayed_work);  			/* link the DAI widgets */ -			play_w = codec_dai->playback_widget; -			capture_w = cpu_dai->capture_widget; -			if (play_w && capture_w) { -				ret = snd_soc_dapm_new_pcm(card, dai_link->params, -						   capture_w, play_w); -				if (ret != 0) { -					dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", -						play_w->name, capture_w->name, ret); -					return ret; -				} -			} - -			play_w = cpu_dai->playback_widget; -			capture_w = codec_dai->capture_widget; -			if (play_w && capture_w) { -				ret = snd_soc_dapm_new_pcm(card, dai_link->params, -						   capture_w, play_w); -				if (ret != 0) { -					dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", -						play_w->name, capture_w->name, ret); -					return ret; -				} -			} +			ret = soc_link_dai_widgets(card, dai_link, +					cpu_dai, codec_dai); +			if (ret) +				return ret;  		}  	} @@ -1485,14 +1585,15 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)  }  #ifdef CONFIG_SND_SOC_AC97_BUS -static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) +static int soc_register_ac97_codec(struct snd_soc_codec *codec, +				   struct snd_soc_dai *codec_dai)  {  	int ret;  	/* Only instantiate AC97 if not already done by the adaptor  	 * for the generic AC97 subsystem.  	 */ -	if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) { +	if (codec_dai->driver->ac97_control && !codec->ac97_registered) {  		/*  		 * It is possible that the AC97 device is already registered to  		 * the device subsystem. This happens when the device is created @@ -1501,76 +1602,101 @@ static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)  		 *  		 * In those cases we don't try to register the device again.  		 */ -		if (!rtd->codec->ac97_created) +		if (!codec->ac97_created)  			return 0; -		ret = soc_ac97_dev_register(rtd->codec); +		ret = soc_ac97_dev_register(codec);  		if (ret < 0) { -			dev_err(rtd->codec->dev, +			dev_err(codec->dev,  				"ASoC: AC97 device register failed: %d\n", ret);  			return ret;  		} -		rtd->codec->ac97_registered = 1; +		codec->ac97_registered = 1;  	}  	return 0;  } -static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec) +static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) +{ +	return soc_register_ac97_codec(rtd->codec, rtd->codec_dai); +} + +static void soc_unregister_ac97_codec(struct snd_soc_codec *codec)  {  	if (codec->ac97_registered) {  		soc_ac97_dev_unregister(codec);  		codec->ac97_registered = 0;  	}  } + +static void soc_unregister_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) +{ +	soc_unregister_ac97_codec(rtd->codec); +}  #endif -static int soc_check_aux_dev(struct snd_soc_card *card, int num) +static struct snd_soc_codec *soc_find_matching_codec(struct snd_soc_card *card, +	int num)  {  	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];  	struct snd_soc_codec *codec; -	/* find CODEC from registered CODECs*/ +	/* find CODEC from registered CODECs */  	list_for_each_entry(codec, &codec_list, list) { -		if (!strcmp(codec->name, aux_dev->codec_name)) -			return 0; +		if (aux_dev->codec_of_node && +		   (codec->dev->of_node != aux_dev->codec_of_node)) +			continue; +		if (aux_dev->codec_name && strcmp(codec->name, aux_dev->codec_name)) +			continue; +		return codec;  	} -	dev_err(card->dev, "ASoC: %s not registered\n", aux_dev->codec_name); +	return NULL; +} + +static int soc_check_aux_dev(struct snd_soc_card *card, int num) +{ +	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; +	const char *codecname = aux_dev->codec_name; +	struct snd_soc_codec *codec = soc_find_matching_codec(card, num); + +	if (codec) +		return 0; +	if (aux_dev->codec_of_node) +		codecname = of_node_full_name(aux_dev->codec_of_node); +	dev_err(card->dev, "ASoC: %s not registered\n", codecname);  	return -EPROBE_DEFER;  }  static int soc_probe_aux_dev(struct snd_soc_card *card, int num)  {  	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; -	struct snd_soc_codec *codec; +	const char *codecname = aux_dev->codec_name;  	int ret = -ENODEV; +	struct snd_soc_codec *codec = soc_find_matching_codec(card, num); -	/* find CODEC from registered CODECs*/ -	list_for_each_entry(codec, &codec_list, list) { -		if (!strcmp(codec->name, aux_dev->codec_name)) { -			if (codec->probed) { -				dev_err(codec->dev, -					"ASoC: codec already probed"); -				ret = -EBUSY; -				goto out; -			} -			goto found; -		} +	if (!codec) { +		if (aux_dev->codec_of_node) +			codecname = of_node_full_name(aux_dev->codec_of_node); + +		/* codec not found */ +		dev_err(card->dev, "ASoC: codec %s not found", codecname); +		return -EPROBE_DEFER; +	} + +	if (codec->probed) { +		dev_err(codec->dev, "ASoC: codec already probed"); +		return -EBUSY;  	} -	/* codec not found */ -	dev_err(card->dev, "ASoC: codec %s not found", aux_dev->codec_name); -	return -EPROBE_DEFER; -found:  	ret = soc_probe_codec(card, codec);  	if (ret < 0)  		return ret;  	ret = soc_post_component_init(card, codec, num, 1); -out:  	return ret;  } @@ -1590,17 +1716,13 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)  		soc_remove_codec(codec);  } -static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, -				    enum snd_soc_compress_type compress_type) +static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)  {  	int ret;  	if (codec->cache_init)  		return 0; -	/* override the compress_type if necessary */ -	if (compress_type && codec->compress_type != compress_type) -		codec->compress_type = compress_type;  	ret = snd_soc_cache_init(codec);  	if (ret < 0) {  		dev_err(codec->dev, @@ -1615,8 +1737,6 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,  static int snd_soc_instantiate_card(struct snd_soc_card *card)  {  	struct snd_soc_codec *codec; -	struct snd_soc_codec_conf *codec_conf; -	enum snd_soc_compress_type compress_type;  	struct snd_soc_dai_link *dai_link;  	int ret, i, order, dai_fmt; @@ -1640,25 +1760,13 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)  	list_for_each_entry(codec, &codec_list, list) {  		if (codec->cache_init)  			continue; -		/* by default we don't override the compress_type */ -		compress_type = 0; -		/* check to see if we need to override the compress_type */ -		for (i = 0; i < card->num_configs; ++i) { -			codec_conf = &card->codec_conf[i]; -			if (!strcmp(codec->name, codec_conf->dev_name)) { -				compress_type = codec_conf->compress_type; -				if (compress_type && compress_type -				    != codec->compress_type) -					break; -			} -		} -		ret = snd_soc_init_codec_cache(codec, compress_type); +		ret = snd_soc_init_codec_cache(codec);  		if (ret < 0)  			goto base_error;  	}  	/* card bind complete so register a sound card */ -	ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, +	ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,  			card->owner, 0, &card->snd_card);  	if (ret < 0) {  		dev_err(card->dev, @@ -1666,7 +1774,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)  			card->name, ret);  		goto base_error;  	} -	card->snd_card->dev = card->dev;  	card->dapm.bias_level = SND_SOC_BIAS_OFF;  	card->dapm.dev = card->dev; @@ -1732,6 +1839,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)  	}  	snd_soc_dapm_link_dai_widgets(card); +	snd_soc_dapm_connect_dai_link_widgets(card);  	if (card->controls)  		snd_soc_add_card_controls(card, card->controls, card->num_controls); @@ -1839,7 +1947,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)  			dev_err(card->dev,  				"ASoC: failed to register AC97: %d\n", ret);  			while (--i >= 0) -				soc_unregister_ac97_dai_link(card->rtd[i].codec); +				soc_unregister_ac97_dai_link(&card->rtd[i]);  			goto probe_aux_dev_err;  		}  	} @@ -1948,6 +2056,14 @@ int snd_soc_poweroff(struct device *dev)  	snd_soc_dapm_shutdown(card); +	/* deactivate pins to sleep state */ +	for (i = 0; i < card->num_rtd; i++) { +		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; +		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai; +		pinctrl_pm_select_sleep_state(codec_dai->dev); +		pinctrl_pm_select_sleep_state(cpu_dai->dev); +	} +  	return 0;  }  EXPORT_SYMBOL_GPL(snd_soc_poweroff); @@ -1974,92 +2090,6 @@ static struct platform_driver soc_driver = {  };  /** - * snd_soc_codec_volatile_register: Report if a register is volatile. - * - * @codec: CODEC to query. - * @reg: Register to query. - * - * Boolean function indiciating if a CODEC register is volatile. - */ -int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, -				    unsigned int reg) -{ -	if (codec->volatile_register) -		return codec->volatile_register(codec, reg); -	else -		return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register); - -/** - * snd_soc_codec_readable_register: Report if a register is readable. - * - * @codec: CODEC to query. - * @reg: Register to query. - * - * Boolean function indicating if a CODEC register is readable. - */ -int snd_soc_codec_readable_register(struct snd_soc_codec *codec, -				    unsigned int reg) -{ -	if (codec->readable_register) -		return codec->readable_register(codec, reg); -	else -		return 1; -} -EXPORT_SYMBOL_GPL(snd_soc_codec_readable_register); - -/** - * snd_soc_codec_writable_register: Report if a register is writable. - * - * @codec: CODEC to query. - * @reg: Register to query. - * - * Boolean function indicating if a CODEC register is writable. - */ -int snd_soc_codec_writable_register(struct snd_soc_codec *codec, -				    unsigned int reg) -{ -	if (codec->writable_register) -		return codec->writable_register(codec, reg); -	else -		return 1; -} -EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register); - -int snd_soc_platform_read(struct snd_soc_platform *platform, -					unsigned int reg) -{ -	unsigned int ret; - -	if (!platform->driver->read) { -		dev_err(platform->dev, "ASoC: platform has no read back\n"); -		return -1; -	} - -	ret = platform->driver->read(platform, reg); -	dev_dbg(platform->dev, "read %x => %x\n", reg, ret); -	trace_snd_soc_preg_read(platform, reg, ret); - -	return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_platform_read); - -int snd_soc_platform_write(struct snd_soc_platform *platform, -					 unsigned int reg, unsigned int val) -{ -	if (!platform->driver->write) { -		dev_err(platform->dev, "ASoC: platform has no write back\n"); -		return -1; -	} - -	dev_dbg(platform->dev, "write %x = %x\n", reg, val); -	trace_snd_soc_preg_write(platform, reg, val); -	return platform->driver->write(platform, reg, val); -} -EXPORT_SYMBOL_GPL(snd_soc_platform_write); - -/**   * snd_soc_new_ac97_codec - initailise AC97 device   * @codec: audio codec   * @ops: AC97 bus operations @@ -2147,28 +2177,28 @@ static int snd_soc_ac97_parse_pinctl(struct device *dev,  	p = devm_pinctrl_get(dev);  	if (IS_ERR(p)) {  		dev_err(dev, "Failed to get pinctrl\n"); -		return PTR_RET(p); +		return PTR_ERR(p);  	}  	cfg->pctl = p;  	state = pinctrl_lookup_state(p, "ac97-reset");  	if (IS_ERR(state)) {  		dev_err(dev, "Can't find pinctrl state ac97-reset\n"); -		return PTR_RET(state); +		return PTR_ERR(state);  	}  	cfg->pstate_reset = state;  	state = pinctrl_lookup_state(p, "ac97-warm-reset");  	if (IS_ERR(state)) {  		dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n"); -		return PTR_RET(state); +		return PTR_ERR(state);  	}  	cfg->pstate_warm_reset = state;  	state = pinctrl_lookup_state(p, "ac97-running");  	if (IS_ERR(state)) {  		dev_err(dev, "Can't find pinctrl state ac97-running\n"); -		return PTR_RET(state); +		return PTR_ERR(state);  	}  	cfg->pstate_run = state; @@ -2267,7 +2297,7 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)  {  	mutex_lock(&codec->mutex);  #ifdef CONFIG_SND_SOC_AC97_BUS -	soc_unregister_ac97_dai_link(codec); +	soc_unregister_ac97_codec(codec);  #endif  	kfree(codec->ac97->bus);  	kfree(codec->ac97); @@ -2277,125 +2307,6 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)  }  EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); -unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg) -{ -	unsigned int ret; - -	ret = codec->read(codec, reg); -	dev_dbg(codec->dev, "read %x => %x\n", reg, ret); -	trace_snd_soc_reg_read(codec, reg, ret); - -	return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_read); - -unsigned int snd_soc_write(struct snd_soc_codec *codec, -			   unsigned int reg, unsigned int val) -{ -	dev_dbg(codec->dev, "write %x = %x\n", reg, val); -	trace_snd_soc_reg_write(codec, reg, val); -	return codec->write(codec, reg, val); -} -EXPORT_SYMBOL_GPL(snd_soc_write); - -unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec, -				    unsigned int reg, const void *data, size_t len) -{ -	return codec->bulk_write_raw(codec, reg, data, len); -} -EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw); - -/** - * snd_soc_update_bits - update codec register bits - * @codec: audio codec - * @reg: codec register - * @mask: register mask - * @value: new value - * - * Writes new register value. - * - * Returns 1 for change, 0 for no change, or negative error code. - */ -int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, -				unsigned int mask, unsigned int value) -{ -	bool change; -	unsigned int old, new; -	int ret; - -	if (codec->using_regmap) { -		ret = regmap_update_bits_check(codec->control_data, reg, -					       mask, value, &change); -	} else { -		ret = snd_soc_read(codec, reg); -		if (ret < 0) -			return ret; - -		old = ret; -		new = (old & ~mask) | (value & mask); -		change = old != new; -		if (change) -			ret = snd_soc_write(codec, reg, new); -	} - -	if (ret < 0) -		return ret; - -	return change; -} -EXPORT_SYMBOL_GPL(snd_soc_update_bits); - -/** - * snd_soc_update_bits_locked - update codec register bits - * @codec: audio codec - * @reg: codec register - * @mask: register mask - * @value: new value - * - * Writes new register value, and takes the codec mutex. - * - * Returns 1 for change else 0. - */ -int snd_soc_update_bits_locked(struct snd_soc_codec *codec, -			       unsigned short reg, unsigned int mask, -			       unsigned int value) -{ -	int change; - -	mutex_lock(&codec->mutex); -	change = snd_soc_update_bits(codec, reg, mask, value); -	mutex_unlock(&codec->mutex); - -	return change; -} -EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked); - -/** - * snd_soc_test_bits - test register for change - * @codec: audio codec - * @reg: codec register - * @mask: register mask - * @value: new value - * - * Tests a register with a new value and checks if the new value is - * different from the old value. - * - * Returns 1 for change else 0. - */ -int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, -				unsigned int mask, unsigned int value) -{ -	int change; -	unsigned int old, new; - -	old = snd_soc_read(codec, reg); -	new = (old & ~mask) | value; -	change = old != new; - -	return change; -} -EXPORT_SYMBOL_GPL(snd_soc_test_bits); -  /**   * snd_soc_cnew - create new control   * @_template: control template @@ -2492,7 +2403,7 @@ int snd_soc_add_codec_controls(struct snd_soc_codec *codec,  	struct snd_card *card = codec->card->snd_card;  	return snd_soc_add_controls(card, codec->dev, controls, num_controls, -			codec->name_prefix, codec); +			codec->name_prefix, &codec->component);  }  EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls); @@ -2512,7 +2423,7 @@ int snd_soc_add_platform_controls(struct snd_soc_platform *platform,  	struct snd_card *card = platform->card->snd_card;  	return snd_soc_add_controls(card, platform->dev, controls, num_controls, -			NULL, platform); +			NULL, &platform->component);  }  EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls); @@ -2573,12 +2484,13 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,  	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;  	uinfo->count = e->shift_l == e->shift_r ? 1 : 2; -	uinfo->value.enumerated.items = e->max; +	uinfo->value.enumerated.items = e->items; -	if (uinfo->value.enumerated.item > e->max - 1) -		uinfo->value.enumerated.item = e->max - 1; -	strcpy(uinfo->value.enumerated.name, -		e->texts[uinfo->value.enumerated.item]); +	if (uinfo->value.enumerated.item >= e->items) +		uinfo->value.enumerated.item = e->items - 1; +	strlcpy(uinfo->value.enumerated.name, +		e->texts[uinfo->value.enumerated.item], +		sizeof(uinfo->value.enumerated.name));  	return 0;  }  EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); @@ -2595,16 +2507,23 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);  int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -	unsigned int val; +	unsigned int val, item; +	unsigned int reg_val; +	int ret; -	val = snd_soc_read(codec, e->reg); -	ucontrol->value.enumerated.item[0] -		= (val >> e->shift_l) & e->mask; -	if (e->shift_l != e->shift_r) -		ucontrol->value.enumerated.item[1] = -			(val >> e->shift_r) & e->mask; +	ret = snd_soc_component_read(component, e->reg, ®_val); +	if (ret) +		return ret; +	val = (reg_val >> e->shift_l) & e->mask; +	item = snd_soc_enum_val_to_item(e, val); +	ucontrol->value.enumerated.item[0] = item; +	if (e->shift_l != e->shift_r) { +		val = (reg_val >> e->shift_l) & e->mask; +		item = snd_soc_enum_val_to_item(e, val); +		ucontrol->value.enumerated.item[1] = item; +	}  	return 0;  } @@ -2622,99 +2541,80 @@ EXPORT_SYMBOL_GPL(snd_soc_get_enum_double);  int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; +	unsigned int *item = ucontrol->value.enumerated.item;  	unsigned int val;  	unsigned int mask; -	if (ucontrol->value.enumerated.item[0] > e->max - 1) +	if (item[0] >= e->items)  		return -EINVAL; -	val = ucontrol->value.enumerated.item[0] << e->shift_l; +	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;  	mask = e->mask << e->shift_l;  	if (e->shift_l != e->shift_r) { -		if (ucontrol->value.enumerated.item[1] > e->max - 1) +		if (item[1] >= e->items)  			return -EINVAL; -		val |= ucontrol->value.enumerated.item[1] << e->shift_r; +		val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;  		mask |= e->mask << e->shift_r;  	} -	return snd_soc_update_bits_locked(codec, e->reg, mask, val); +	return snd_soc_component_update_bits(component, e->reg, mask, val);  }  EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);  /** - * snd_soc_get_value_enum_double - semi enumerated double mixer get callback - * @kcontrol: mixer control - * @ucontrol: control element information + * snd_soc_read_signed - Read a codec register and interprete as signed value + * @component: component + * @reg: Register to read + * @mask: Mask to use after shifting the register value + * @shift: Right shift of register value + * @sign_bit: Bit that describes if a number is negative or not. + * @signed_val: Pointer to where the read value should be stored   * - * Callback to get the value of a double semi enumerated mixer. + * This functions reads a codec register. The register value is shifted right + * by 'shift' bits and masked with the given 'mask'. Afterwards it translates + * the given registervalue into a signed integer if sign_bit is non-zero.   * - * Semi enumerated mixer: the enumerated items are referred as values. Can be - * used for handling bitfield coded enumeration for example. - * - * Returns 0 for success. + * Returns 0 on sucess, otherwise an error value   */ -int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, -	struct snd_ctl_elem_value *ucontrol) +static int snd_soc_read_signed(struct snd_soc_component *component, +	unsigned int reg, unsigned int mask, unsigned int shift, +	unsigned int sign_bit, int *signed_val)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); -	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -	unsigned int reg_val, val, mux; +	int ret; +	unsigned int val; -	reg_val = snd_soc_read(codec, e->reg); -	val = (reg_val >> e->shift_l) & e->mask; -	for (mux = 0; mux < e->max; mux++) { -		if (val == e->values[mux]) -			break; +	ret = snd_soc_component_read(component, reg, &val); +	if (ret < 0) +		return ret; + +	val = (val >> shift) & mask; + +	if (!sign_bit) { +		*signed_val = val; +		return 0;  	} -	ucontrol->value.enumerated.item[0] = mux; -	if (e->shift_l != e->shift_r) { -		val = (reg_val >> e->shift_r) & e->mask; -		for (mux = 0; mux < e->max; mux++) { -			if (val == e->values[mux]) -				break; -		} -		ucontrol->value.enumerated.item[1] = mux; + +	/* non-negative number */ +	if (!(val & BIT(sign_bit))) { +		*signed_val = val; +		return 0;  	} -	return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double); +	ret = val; -/** - * snd_soc_put_value_enum_double - semi enumerated double mixer put callback - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Callback to set the value of a double semi enumerated mixer. - * - * Semi enumerated mixer: the enumerated items are referred as values. Can be - * used for handling bitfield coded enumeration for example. - * - * Returns 0 for success. - */ -int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, -	struct snd_ctl_elem_value *ucontrol) -{ -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); -	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -	unsigned int val; -	unsigned int mask; +	/* +	 * The register most probably does not contain a full-sized int. +	 * Instead we have an arbitrary number of bits in a signed +	 * representation which has to be translated into a full-sized int. +	 * This is done by filling up all bits above the sign-bit. +	 */ +	ret |= ~((int)(BIT(sign_bit) - 1)); -	if (ucontrol->value.enumerated.item[0] > e->max - 1) -		return -EINVAL; -	val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; -	mask = e->mask << e->shift_l; -	if (e->shift_l != e->shift_r) { -		if (ucontrol->value.enumerated.item[1] > e->max - 1) -			return -EINVAL; -		val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; -		mask |= e->mask << e->shift_r; -	} +	*signed_val = ret; -	return snd_soc_update_bits_locked(codec, e->reg, mask, val); +	return 0;  } -EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);  /**   * snd_soc_info_volsw - single mixer info callback @@ -2744,7 +2644,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,  	uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;  	uinfo->value.integer.min = 0; -	uinfo->value.integer.max = platform_max; +	uinfo->value.integer.max = platform_max - mc->min;  	return 0;  }  EXPORT_SYMBOL_GPL(snd_soc_info_volsw); @@ -2762,30 +2662,44 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw);  int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int reg2 = mc->rreg;  	unsigned int shift = mc->shift;  	unsigned int rshift = mc->rshift;  	int max = mc->max; +	int min = mc->min; +	int sign_bit = mc->sign_bit;  	unsigned int mask = (1 << fls(max)) - 1;  	unsigned int invert = mc->invert; +	int val; +	int ret; -	ucontrol->value.integer.value[0] = -		(snd_soc_read(codec, reg) >> shift) & mask; +	if (sign_bit) +		mask = BIT(sign_bit + 1) - 1; + +	ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val); +	if (ret) +		return ret; + +	ucontrol->value.integer.value[0] = val - min;  	if (invert)  		ucontrol->value.integer.value[0] =  			max - ucontrol->value.integer.value[0];  	if (snd_soc_volsw_is_stereo(mc)) {  		if (reg == reg2) -			ucontrol->value.integer.value[1] = -				(snd_soc_read(codec, reg) >> rshift) & mask; +			ret = snd_soc_read_signed(component, reg, mask, rshift, +				sign_bit, &val);  		else -			ucontrol->value.integer.value[1] = -				(snd_soc_read(codec, reg2) >> shift) & mask; +			ret = snd_soc_read_signed(component, reg2, mask, shift, +				sign_bit, &val); +		if (ret) +			return ret; + +		ucontrol->value.integer.value[1] = val - min;  		if (invert)  			ucontrol->value.integer.value[1] =  				max - ucontrol->value.integer.value[1]; @@ -2808,28 +2722,33 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw);  int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int reg2 = mc->rreg;  	unsigned int shift = mc->shift;  	unsigned int rshift = mc->rshift;  	int max = mc->max; +	int min = mc->min; +	unsigned int sign_bit = mc->sign_bit;  	unsigned int mask = (1 << fls(max)) - 1;  	unsigned int invert = mc->invert;  	int err; -	bool type_2r = 0; +	bool type_2r = false;  	unsigned int val2 = 0;  	unsigned int val, val_mask; -	val = (ucontrol->value.integer.value[0] & mask); +	if (sign_bit) +		mask = BIT(sign_bit + 1) - 1; + +	val = ((ucontrol->value.integer.value[0] + min) & mask);  	if (invert)  		val = max - val;  	val_mask = mask << shift;  	val = val << shift;  	if (snd_soc_volsw_is_stereo(mc)) { -		val2 = (ucontrol->value.integer.value[1] & mask); +		val2 = ((ucontrol->value.integer.value[1] + min) & mask);  		if (invert)  			val2 = max - val2;  		if (reg == reg2) { @@ -2837,15 +2756,16 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,  			val |= val2 << rshift;  		} else {  			val2 = val2 << shift; -			type_2r = 1; +			type_2r = true;  		}  	} -	err = snd_soc_update_bits_locked(codec, reg, val_mask, val); +	err = snd_soc_component_update_bits(component, reg, val_mask, val);  	if (err < 0)  		return err;  	if (type_2r) -		err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2); +		err = snd_soc_component_update_bits(component, reg2, val_mask, +			val2);  	return err;  } @@ -2864,10 +2784,9 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw);  int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,  		      struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_mixer_control *mc =  	    (struct soc_mixer_control *)kcontrol->private_value; -  	unsigned int reg = mc->reg;  	unsigned int reg2 = mc->rreg;  	unsigned int shift = mc->shift; @@ -2875,13 +2794,23 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,  	int max = mc->max;  	int min = mc->min;  	int mask = (1 << (fls(min + max) - 1)) - 1; +	unsigned int val; +	int ret; -	ucontrol->value.integer.value[0] = -	    ((snd_soc_read(codec, reg) >> shift) - min) & mask; +	ret = snd_soc_component_read(component, reg, &val); +	if (ret < 0) +		return ret; -	if (snd_soc_volsw_is_stereo(mc)) -		ucontrol->value.integer.value[1] = -			((snd_soc_read(codec, reg2) >> rshift) - min) & mask; +	ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask; + +	if (snd_soc_volsw_is_stereo(mc)) { +		ret = snd_soc_component_read(component, reg2, &val); +		if (ret < 0) +			return ret; + +		val = ((val >> rshift) - min) & mask; +		ucontrol->value.integer.value[1] = val; +	}  	return 0;  } @@ -2899,7 +2828,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);  int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,  			 struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_mixer_control *mc =  	    (struct soc_mixer_control *)kcontrol->private_value; @@ -2911,13 +2840,13 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,  	int min = mc->min;  	int mask = (1 << (fls(min + max) - 1)) - 1;  	int err = 0; -	unsigned short val, val_mask, val2 = 0; +	unsigned int val, val_mask, val2 = 0;  	val_mask = mask << shift;  	val = (ucontrol->value.integer.value[0] + min) & mask;  	val = val << shift; -	err = snd_soc_update_bits_locked(codec, reg, val_mask, val); +	err = snd_soc_component_update_bits(component, reg, val_mask, val);  	if (err < 0)  		return err; @@ -2926,10 +2855,10 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,  		val2 = (ucontrol->value.integer.value[1] + min) & mask;  		val2 = val2 << rshift; -		if (snd_soc_update_bits_locked(codec, reg2, val_mask, val2)) -			return err; +		err = snd_soc_component_update_bits(component, reg2, val_mask, +			val2);  	} -	return 0; +	return err;  }  EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx); @@ -2976,10 +2905,15 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	unsigned int reg = mc->reg; +	unsigned int val;  	int min = mc->min; -	int val = snd_soc_read(codec, reg); +	int ret; + +	ret = snd_soc_component_read(component, reg, &val); +	if (ret) +		return ret;  	ucontrol->value.integer.value[0] =  		((signed char)(val & 0xff))-min; @@ -3003,7 +2937,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	unsigned int reg = mc->reg;  	int min = mc->min;  	unsigned int val; @@ -3011,7 +2945,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,  	val = (ucontrol->value.integer.value[0]+min) & 0xff;  	val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; -	return snd_soc_update_bits_locked(codec, reg, 0xffff, val); +	return snd_soc_component_update_bits(component, reg, 0xffff, val);  }  EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); @@ -3060,7 +2994,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,  {  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int rreg = mc->rreg;  	unsigned int shift = mc->shift; @@ -3077,7 +3011,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,  	val_mask = mask << shift;  	val = val << shift; -	ret = snd_soc_update_bits_locked(codec, reg, val_mask, val); +	ret = snd_soc_component_update_bits(component, reg, val_mask, val);  	if (ret < 0)  		return ret; @@ -3088,7 +3022,8 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,  		val_mask = mask << shift;  		val = val << shift; -		ret = snd_soc_update_bits_locked(codec, rreg, val_mask, val); +		ret = snd_soc_component_update_bits(component, rreg, val_mask, +			val);  	}  	return ret; @@ -3107,9 +3042,9 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);  int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int rreg = mc->rreg;  	unsigned int shift = mc->shift; @@ -3117,9 +3052,14 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,  	int max = mc->max;  	unsigned int mask = (1 << fls(max)) - 1;  	unsigned int invert = mc->invert; +	unsigned int val; +	int ret; -	ucontrol->value.integer.value[0] = -		(snd_soc_read(codec, reg) >> shift) & mask; +	ret = snd_soc_component_read(component, reg, &val); +	if (ret) +		return ret; + +	ucontrol->value.integer.value[0] = (val >> shift) & mask;  	if (invert)  		ucontrol->value.integer.value[0] =  			max - ucontrol->value.integer.value[0]; @@ -3127,8 +3067,11 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,  		ucontrol->value.integer.value[0] - min;  	if (snd_soc_volsw_is_stereo(mc)) { -		ucontrol->value.integer.value[1] = -			(snd_soc_read(codec, rreg) >> shift) & mask; +		ret = snd_soc_component_read(component, rreg, &val); +		if (ret) +			return ret; + +		ucontrol->value.integer.value[1] = (val >> shift) & mask;  		if (invert)  			ucontrol->value.integer.value[1] =  				max - ucontrol->value.integer.value[1]; @@ -3182,11 +3125,11 @@ EXPORT_SYMBOL_GPL(snd_soc_limit_volume);  int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,  		       struct snd_ctl_elem_info *uinfo)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_bytes *params = (void *)kcontrol->private_value;  	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; -	uinfo->count = params->num_regs * codec->val_bytes; +	uinfo->count = params->num_regs * component->val_bytes;  	return 0;  } @@ -3195,30 +3138,30 @@ EXPORT_SYMBOL_GPL(snd_soc_bytes_info);  int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,  		      struct snd_ctl_elem_value *ucontrol)  { +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_bytes *params = (void *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);  	int ret; -	if (codec->using_regmap) -		ret = regmap_raw_read(codec->control_data, params->base, +	if (component->regmap) +		ret = regmap_raw_read(component->regmap, params->base,  				      ucontrol->value.bytes.data, -				      params->num_regs * codec->val_bytes); +				      params->num_regs * component->val_bytes);  	else  		ret = -EINVAL;  	/* Hide any masked bytes to ensure consistent data reporting */  	if (ret == 0 && params->mask) { -		switch (codec->val_bytes) { +		switch (component->val_bytes) {  		case 1:  			ucontrol->value.bytes.data[0] &= ~params->mask;  			break;  		case 2:  			((u16 *)(&ucontrol->value.bytes.data))[0] -				&= ~params->mask; +				&= cpu_to_be16(~params->mask);  			break;  		case 4:  			((u32 *)(&ucontrol->value.bytes.data))[0] -				&= ~params->mask; +				&= cpu_to_be32(~params->mask);  			break;  		default:  			return -EINVAL; @@ -3232,16 +3175,16 @@ EXPORT_SYMBOL_GPL(snd_soc_bytes_get);  int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,  		      struct snd_ctl_elem_value *ucontrol)  { +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_bytes *params = (void *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);  	int ret, len; -	unsigned int val; +	unsigned int val, mask;  	void *data; -	if (!codec->using_regmap) +	if (!component->regmap)  		return -EINVAL; -	len = params->num_regs * codec->val_bytes; +	len = params->num_regs * component->val_bytes;  	data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);  	if (!data) @@ -3253,24 +3196,48 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,  	 * copy.  	 */  	if (params->mask) { -		ret = regmap_read(codec->control_data, params->base, &val); +		ret = regmap_read(component->regmap, params->base, &val);  		if (ret != 0)  			goto out;  		val &= params->mask; -		switch (codec->val_bytes) { +		switch (component->val_bytes) {  		case 1:  			((u8 *)data)[0] &= ~params->mask;  			((u8 *)data)[0] |= val;  			break;  		case 2: -			((u16 *)data)[0] &= cpu_to_be16(~params->mask); -			((u16 *)data)[0] |= cpu_to_be16(val); +			mask = ~params->mask; +			ret = regmap_parse_val(component->regmap, +							&mask, &mask); +			if (ret != 0) +				goto out; + +			((u16 *)data)[0] &= mask; + +			ret = regmap_parse_val(component->regmap, +							&val, &val); +			if (ret != 0) +				goto out; + +			((u16 *)data)[0] |= val;  			break;  		case 4: -			((u32 *)data)[0] &= cpu_to_be32(~params->mask); -			((u32 *)data)[0] |= cpu_to_be32(val); +			mask = ~params->mask; +			ret = regmap_parse_val(component->regmap, +							&mask, &mask); +			if (ret != 0) +				goto out; + +			((u32 *)data)[0] &= mask; + +			ret = regmap_parse_val(component->regmap, +							&val, &val); +			if (ret != 0) +				goto out; + +			((u32 *)data)[0] |= val;  			break;  		default:  			ret = -EINVAL; @@ -3278,7 +3245,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,  		}  	} -	ret = regmap_raw_write(codec->control_data, params->base, +	ret = regmap_raw_write(component->regmap, params->base,  			       data, len);  out: @@ -3288,6 +3255,18 @@ out:  }  EXPORT_SYMBOL_GPL(snd_soc_bytes_put); +int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol, +			struct snd_ctl_elem_info *ucontrol) +{ +	struct soc_bytes_ext *params = (void *)kcontrol->private_value; + +	ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; +	ucontrol->count = params->max; + +	return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext); +  /**   * snd_soc_info_xr_sx - signed multi register info callback   * @kcontrol: mreg control @@ -3329,24 +3308,27 @@ EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx);  int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_mreg_control *mc =  		(struct soc_mreg_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);  	unsigned int regbase = mc->regbase;  	unsigned int regcount = mc->regcount; -	unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE; +	unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;  	unsigned int regwmask = (1<<regwshift)-1;  	unsigned int invert = mc->invert;  	unsigned long mask = (1UL<<mc->nbits)-1;  	long min = mc->min;  	long max = mc->max;  	long val = 0; -	unsigned long regval; +	unsigned int regval;  	unsigned int i; +	int ret;  	for (i = 0; i < regcount; i++) { -		regval = snd_soc_read(codec, regbase+i) & regwmask; -		val |= regval << (regwshift*(regcount-i-1)); +		ret = snd_soc_component_read(component, regbase+i, ®val); +		if (ret) +			return ret; +		val |= (regval & regwmask) << (regwshift*(regcount-i-1));  	}  	val &= mask;  	if (min < 0 && val > max) @@ -3375,12 +3357,12 @@ EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx);  int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_mreg_control *mc =  		(struct soc_mreg_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);  	unsigned int regbase = mc->regbase;  	unsigned int regcount = mc->regcount; -	unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE; +	unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;  	unsigned int regwmask = (1<<regwshift)-1;  	unsigned int invert = mc->invert;  	unsigned long mask = (1UL<<mc->nbits)-1; @@ -3395,7 +3377,7 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,  	for (i = 0; i < regcount; i++) {  		regval = (val >> (regwshift*(regcount-i-1))) & regwmask;  		regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask; -		err = snd_soc_update_bits_locked(codec, regbase+i, +		err = snd_soc_component_update_bits(component, regbase+i,  				regmask, regval);  		if (err < 0)  			return err; @@ -3417,14 +3399,21 @@ EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx);  int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int shift = mc->shift;  	unsigned int mask = 1 << shift;  	unsigned int invert = mc->invert != 0; -	unsigned int val = snd_soc_read(codec, reg) & mask; +	unsigned int val; +	int ret; + +	ret = snd_soc_component_read(component, reg, &val); +	if (ret) +		return ret; + +	val &= mask;  	if (shift != 0 && val != 0)  		val = val >> shift; @@ -3447,9 +3436,9 @@ EXPORT_SYMBOL_GPL(snd_soc_get_strobe);  int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,  	struct snd_ctl_elem_value *ucontrol)  { +	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value; -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);  	unsigned int reg = mc->reg;  	unsigned int shift = mc->shift;  	unsigned int mask = 1 << shift; @@ -3459,12 +3448,11 @@ int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,  	unsigned int val2 = (strobe ^ invert) ? 0 : mask;  	int err; -	err = snd_soc_update_bits_locked(codec, reg, mask, val1); +	err = snd_soc_component_update_bits(component, reg, mask, val1);  	if (err < 0)  		return err; -	err = snd_soc_update_bits_locked(codec, reg, mask, val2); -	return err; +	return snd_soc_component_update_bits(component, reg, mask, val2);  }  EXPORT_SYMBOL_GPL(snd_soc_put_strobe); @@ -3486,7 +3474,7 @@ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,  		return dai->codec->driver->set_sysclk(dai->codec, clk_id, 0,  						      freq, dir);  	else -		return -EINVAL; +		return -ENOTSUPP;  }  EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); @@ -3507,7 +3495,7 @@ int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,  		return codec->driver->set_sysclk(codec, clk_id, source,  						 freq, dir);  	else -		return -EINVAL; +		return -ENOTSUPP;  }  EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk); @@ -3577,6 +3565,22 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,  EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll);  /** + * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. + * @dai: DAI + * @ratio Ratio of BCLK to Sample rate. + * + * Configures the DAI for a preset BCLK to sample rate ratio. + */ +int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ +	if (dai->driver && dai->driver->ops->set_bclk_ratio) +		return dai->driver->ops->set_bclk_ratio(dai, ratio); +	else +		return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); + +/**   * snd_soc_dai_set_fmt - configure DAI hardware audio format.   * @dai: DAI   * @fmt: SND_SOC_DAIFMT_ format value. @@ -3594,6 +3598,30 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)  EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);  /** + * snd_soc_xlate_tdm_slot - generate tx/rx slot mask. + * @slots: Number of slots in use. + * @tx_mask: bitmask representing active TX slots. + * @rx_mask: bitmask representing active RX slots. + * + * Generates the TDM tx and rx slot default masks for DAI. + */ +static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, +					  unsigned int *tx_mask, +					  unsigned int *rx_mask) +{ +	if (*tx_mask || *rx_mask) +		return 0; + +	if (!slots) +		return -EINVAL; + +	*tx_mask = (1 << slots) - 1; +	*rx_mask = (1 << slots) - 1; + +	return 0; +} + +/**   * snd_soc_dai_set_tdm_slot - configure DAI TDM.   * @dai: DAI   * @tx_mask: bitmask representing active TX slots. @@ -3607,11 +3635,17 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);  int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,  	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)  { +	if (dai->driver && dai->driver->ops->xlate_tdm_slot_mask) +		dai->driver->ops->xlate_tdm_slot_mask(slots, +						&tx_mask, &rx_mask); +	else +		snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); +  	if (dai->driver && dai->driver->ops->set_tdm_slot)  		return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,  				slots, slot_width);  	else -		return -EINVAL; +		return -ENOTSUPP;  }  EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); @@ -3766,7 +3800,6 @@ int snd_soc_register_card(struct snd_soc_card *card)  	for (i = 0; i < card->num_links; i++)  		card->rtd[i].dai_link = &card->dai_link[i]; -	INIT_LIST_HEAD(&card->list);  	INIT_LIST_HEAD(&card->dapm_dirty);  	card->instantiated = 0;  	mutex_init(&card->mutex); @@ -3776,6 +3809,16 @@ int snd_soc_register_card(struct snd_soc_card *card)  	if (ret != 0)  		soc_cleanup_card_debugfs(card); +	/* deactivate pins to sleep state */ +	for (i = 0; i < card->num_rtd; i++) { +		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; +		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai; +		if (!codec_dai->active) +			pinctrl_pm_select_sleep_state(codec_dai->dev); +		if (!cpu_dai->active) +			pinctrl_pm_select_sleep_state(cpu_dai->dev); +	} +  	return ret;  }  EXPORT_SYMBOL_GPL(snd_soc_register_card); @@ -3857,95 +3900,42 @@ static inline char *fmt_multiple_name(struct device *dev,  }  /** - * snd_soc_register_dai - Register a DAI with the ASoC core + * snd_soc_unregister_dai - Unregister DAIs from the ASoC core   * - * @dai: DAI to register + * @component: The component for which the DAIs should be unregistered   */ -static int snd_soc_register_dai(struct device *dev, -		struct snd_soc_dai_driver *dai_drv) +static void snd_soc_unregister_dais(struct snd_soc_component *component)  { -	struct snd_soc_codec *codec; -	struct snd_soc_dai *dai; - -	dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev)); - -	dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); -	if (dai == NULL) -		return -ENOMEM; +	struct snd_soc_dai *dai, *_dai; -	/* create DAI component name */ -	dai->name = fmt_single_name(dev, &dai->id); -	if (dai->name == NULL) { +	list_for_each_entry_safe(dai, _dai, &component->dai_list, list) { +		dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", +			dai->name); +		list_del(&dai->list); +		kfree(dai->name);  		kfree(dai); -		return -ENOMEM;  	} - -	dai->dev = dev; -	dai->driver = dai_drv; -	dai->dapm.dev = dev; -	if (!dai->driver->ops) -		dai->driver->ops = &null_dai_ops; - -	mutex_lock(&client_mutex); - -	list_for_each_entry(codec, &codec_list, list) { -		if (codec->dev == dev) { -			dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n", -				dai->name, codec->name); -			dai->codec = codec; -			break; -		} -	} - -	if (!dai->codec) -		dai->dapm.idle_bias_off = 1; - -	list_add(&dai->list, &dai_list); - -	mutex_unlock(&client_mutex); - -	dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); - -	return 0; -} - -/** - * snd_soc_unregister_dai - Unregister a DAI from the ASoC core - * - * @dai: DAI to unregister - */ -static void snd_soc_unregister_dai(struct device *dev) -{ -	struct snd_soc_dai *dai; - -	list_for_each_entry(dai, &dai_list, list) { -		if (dev == dai->dev) -			goto found; -	} -	return; - -found: -	mutex_lock(&client_mutex); -	list_del(&dai->list); -	mutex_unlock(&client_mutex); - -	dev_dbg(dev, "ASoC: Unregistered DAI '%s'\n", dai->name); -	kfree(dai->name); -	kfree(dai);  }  /** - * snd_soc_register_dais - Register multiple DAIs with the ASoC core + * snd_soc_register_dais - Register a DAI with the ASoC core   * - * @dai: Array of DAIs to register + * @component: The component the DAIs are registered for + * @codec: The CODEC that the DAIs are registered for, NULL if the component is + *         not a CODEC. + * @dai_drv: DAI driver to use for the DAIs   * @count: Number of DAIs + * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the + *                     parent's name.   */ -static int snd_soc_register_dais(struct device *dev, -		struct snd_soc_dai_driver *dai_drv, size_t count) +static int snd_soc_register_dais(struct snd_soc_component *component, +	struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv, +	size_t count, bool legacy_dai_naming)  { -	struct snd_soc_codec *codec; +	struct device *dev = component->dev;  	struct snd_soc_dai *dai; -	int i, ret = 0; +	unsigned int i; +	int ret;  	dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); @@ -3957,67 +3947,177 @@ static int snd_soc_register_dais(struct device *dev,  			goto err;  		} -		/* create DAI component name */ -		dai->name = fmt_multiple_name(dev, &dai_drv[i]); +		/* +		 * Back in the old days when we still had component-less DAIs, +		 * instead of having a static name, component-less DAIs would +		 * inherit the name of the parent device so it is possible to +		 * register multiple instances of the DAI. We still need to keep +		 * the same naming style even though those DAIs are not +		 * component-less anymore. +		 */ +		if (count == 1 && legacy_dai_naming) { +			dai->name = fmt_single_name(dev, &dai->id); +		} else { +			dai->name = fmt_multiple_name(dev, &dai_drv[i]); +			if (dai_drv[i].id) +				dai->id = dai_drv[i].id; +			else +				dai->id = i; +		}  		if (dai->name == NULL) {  			kfree(dai); -			ret = -EINVAL; +			ret = -ENOMEM;  			goto err;  		} +		dai->component = component; +		dai->codec = codec;  		dai->dev = dev;  		dai->driver = &dai_drv[i]; -		if (dai->driver->id) -			dai->id = dai->driver->id; -		else -			dai->id = i;  		dai->dapm.dev = dev;  		if (!dai->driver->ops)  			dai->driver->ops = &null_dai_ops; -		mutex_lock(&client_mutex); - -		list_for_each_entry(codec, &codec_list, list) { -			if (codec->dev == dev) { -				dev_dbg(dev, -					"ASoC: Mapped DAI %s to CODEC %s\n", -					dai->name, codec->name); -				dai->codec = codec; -				break; -			} -		} -  		if (!dai->codec)  			dai->dapm.idle_bias_off = 1; -		list_add(&dai->list, &dai_list); - -		mutex_unlock(&client_mutex); +		list_add(&dai->list, &component->dai_list); -		dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name); +		dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);  	}  	return 0;  err: -	for (i--; i >= 0; i--) -		snd_soc_unregister_dai(dev); +	snd_soc_unregister_dais(component);  	return ret;  }  /** - * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core + * snd_soc_register_component - Register a component with the ASoC core   * - * @dai: Array of DAIs to unregister - * @count: Number of DAIs   */ -static void snd_soc_unregister_dais(struct device *dev, size_t count) +static int +__snd_soc_register_component(struct device *dev, +			     struct snd_soc_component *cmpnt, +			     const struct snd_soc_component_driver *cmpnt_drv, +			     struct snd_soc_codec *codec, +			     struct snd_soc_dai_driver *dai_drv, +			     int num_dai, bool allow_single_dai)  { -	int i; +	int ret; + +	dev_dbg(dev, "component register %s\n", dev_name(dev)); + +	if (!cmpnt) { +		dev_err(dev, "ASoC: Failed to connecting component\n"); +		return -ENOMEM; +	} + +	mutex_init(&cmpnt->io_mutex); + +	cmpnt->name = fmt_single_name(dev, &cmpnt->id); +	if (!cmpnt->name) { +		dev_err(dev, "ASoC: Failed to simplifying name\n"); +		return -ENOMEM; +	} + +	cmpnt->dev	= dev; +	cmpnt->driver	= cmpnt_drv; +	cmpnt->dai_drv	= dai_drv; +	cmpnt->num_dai	= num_dai; +	INIT_LIST_HEAD(&cmpnt->dai_list); + +	ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai, +		allow_single_dai); +	if (ret < 0) { +		dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); +		goto error_component_name; +	} + +	mutex_lock(&client_mutex); +	list_add(&cmpnt->list, &component_list); +	mutex_unlock(&client_mutex); + +	dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); + +	return ret; + +error_component_name: +	kfree(cmpnt->name); + +	return ret; +} + +int snd_soc_register_component(struct device *dev, +			       const struct snd_soc_component_driver *cmpnt_drv, +			       struct snd_soc_dai_driver *dai_drv, +			       int num_dai) +{ +	struct snd_soc_component *cmpnt; + +	cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); +	if (!cmpnt) { +		dev_err(dev, "ASoC: Failed to allocate memory\n"); +		return -ENOMEM; +	} + +	cmpnt->ignore_pmdown_time = true; +	cmpnt->registered_as_component = true; + +	return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL, +					    dai_drv, num_dai, true); +} +EXPORT_SYMBOL_GPL(snd_soc_register_component); + +static void __snd_soc_unregister_component(struct snd_soc_component *cmpnt) +{ +	snd_soc_unregister_dais(cmpnt); + +	mutex_lock(&client_mutex); +	list_del(&cmpnt->list); +	mutex_unlock(&client_mutex); + +	dev_dbg(cmpnt->dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); +	kfree(cmpnt->name); +} + +/** + * snd_soc_unregister_component - Unregister a component from the ASoC core + * + */ +void snd_soc_unregister_component(struct device *dev) +{ +	struct snd_soc_component *cmpnt; + +	list_for_each_entry(cmpnt, &component_list, list) { +		if (dev == cmpnt->dev && cmpnt->registered_as_component) +			goto found; +	} +	return; + +found: +	__snd_soc_unregister_component(cmpnt); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_component); + +static int snd_soc_platform_drv_write(struct snd_soc_component *component, +	unsigned int reg, unsigned int val) +{ +	struct snd_soc_platform *platform = snd_soc_component_to_platform(component); -	for (i = 0; i < count; i++) -		snd_soc_unregister_dai(dev); +	return platform->driver->write(platform, reg, val); +} + +static int snd_soc_platform_drv_read(struct snd_soc_component *component, +	unsigned int reg, unsigned int *val) +{ +	struct snd_soc_platform *platform = snd_soc_component_to_platform(component); + +	*val = platform->driver->read(platform, reg); + +	return 0;  }  /** @@ -4029,6 +4129,8 @@ static void snd_soc_unregister_dais(struct device *dev, size_t count)  int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,  		const struct snd_soc_platform_driver *platform_drv)  { +	int ret; +  	/* create platform component name */  	platform->name = fmt_single_name(dev, &platform->id);  	if (platform->name == NULL) @@ -4038,8 +4140,22 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,  	platform->driver = platform_drv;  	platform->dapm.dev = dev;  	platform->dapm.platform = platform; +	platform->dapm.component = &platform->component;  	platform->dapm.stream_event = platform_drv->stream_event; -	mutex_init(&platform->mutex); +	if (platform_drv->write) +		platform->component.write = snd_soc_platform_drv_write; +	if (platform_drv->read) +		platform->component.read = snd_soc_platform_drv_read; + +	/* register component */ +	ret = __snd_soc_register_component(dev, &platform->component, +					   &platform_drv->component_driver, +					   NULL, NULL, 0, false); +	if (ret < 0) { +		dev_err(platform->component.dev, +			"ASoC: Failed to register component: %d\n", ret); +		return ret; +	}  	mutex_lock(&client_mutex);  	list_add(&platform->list, &platform_list); @@ -4082,6 +4198,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_platform);   */  void snd_soc_remove_platform(struct snd_soc_platform *platform)  { +	__snd_soc_unregister_component(&platform->component); +  	mutex_lock(&client_mutex);  	list_del(&platform->list);  	mutex_unlock(&client_mutex); @@ -4156,6 +4274,24 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)  			stream->formats |= codec_format_map[i];  } +static int snd_soc_codec_drv_write(struct snd_soc_component *component, +	unsigned int reg, unsigned int val) +{ +	struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + +	return codec->driver->write(codec, reg, val); +} + +static int snd_soc_codec_drv_read(struct snd_soc_component *component, +	unsigned int reg, unsigned int *val) +{ +	struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + +	*val = codec->driver->read(codec, reg); + +	return 0; +} +  /**   * snd_soc_register_codec - Register a codec with the ASoC core   * @@ -4166,8 +4302,8 @@ int snd_soc_register_codec(struct device *dev,  			   struct snd_soc_dai_driver *dai_drv,  			   int num_dai)  { -	size_t reg_size;  	struct snd_soc_codec *codec; +	struct regmap *regmap;  	int ret, i;  	dev_dbg(dev, "codec register %s\n", dev_name(dev)); @@ -4183,56 +4319,40 @@ int snd_soc_register_codec(struct device *dev,  		goto fail_codec;  	} -	if (codec_drv->compress_type) -		codec->compress_type = codec_drv->compress_type; -	else -		codec->compress_type = SND_SOC_FLAT_COMPRESSION; - -	codec->write = codec_drv->write; -	codec->read = codec_drv->read; -	codec->volatile_register = codec_drv->volatile_register; -	codec->readable_register = codec_drv->readable_register; -	codec->writable_register = codec_drv->writable_register; -	codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time; +	if (codec_drv->write) +		codec->component.write = snd_soc_codec_drv_write; +	if (codec_drv->read) +		codec->component.read = snd_soc_codec_drv_read; +	codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;  	codec->dapm.bias_level = SND_SOC_BIAS_OFF;  	codec->dapm.dev = dev;  	codec->dapm.codec = codec; +	codec->dapm.component = &codec->component;  	codec->dapm.seq_notifier = codec_drv->seq_notifier;  	codec->dapm.stream_event = codec_drv->stream_event;  	codec->dev = dev;  	codec->driver = codec_drv; -	codec->num_dai = num_dai; +	codec->component.val_bytes = codec_drv->reg_word_size;  	mutex_init(&codec->mutex); -	/* allocate CODEC register cache */ -	if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { -		reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; -		codec->reg_size = reg_size; -		/* it is necessary to make a copy of the default register cache -		 * because in the case of using a compression type that requires -		 * the default register cache to be marked as the -		 * kernel might have freed the array by the time we initialize -		 * the cache. -		 */ -		if (codec_drv->reg_cache_default) { -			codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default, -						      reg_size, GFP_KERNEL); -			if (!codec->reg_def_copy) { -				ret = -ENOMEM; -				goto fail_codec_name; +	if (!codec->component.write) { +		if (codec_drv->get_regmap) +			regmap = codec_drv->get_regmap(dev); +		else +			regmap = dev_get_regmap(dev, NULL); + +		if (regmap) { +			ret = snd_soc_component_init_io(&codec->component, +				regmap); +			if (ret) { +				dev_err(codec->dev, +						"Failed to set cache I/O:%d\n", +						ret); +				return ret;  			}  		}  	} -	if (codec_drv->reg_access_size && codec_drv->reg_access_default) { -		if (!codec->volatile_register) -			codec->volatile_register = snd_soc_default_volatile_register; -		if (!codec->readable_register) -			codec->readable_register = snd_soc_default_readable_register; -		if (!codec->writable_register) -			codec->writable_register = snd_soc_default_writable_register; -	} -  	for (i = 0; i < num_dai; i++) {  		fixup_codec_formats(&dai_drv[i].playback);  		fixup_codec_formats(&dai_drv[i].capture); @@ -4242,10 +4362,12 @@ int snd_soc_register_codec(struct device *dev,  	list_add(&codec->list, &codec_list);  	mutex_unlock(&client_mutex); -	/* register any DAIs */ -	ret = snd_soc_register_dais(dev, dai_drv, num_dai); +	/* register component */ +	ret = __snd_soc_register_component(dev, &codec->component, +					   &codec_drv->component_driver, +					   codec, dai_drv, num_dai, false);  	if (ret < 0) { -		dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret); +		dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret);  		goto fail_codec_name;  	} @@ -4280,7 +4402,7 @@ void snd_soc_unregister_codec(struct device *dev)  	return;  found: -	snd_soc_unregister_dais(dev, codec->num_dai); +	__snd_soc_unregister_component(&codec->component);  	mutex_lock(&client_mutex);  	list_del(&codec->list); @@ -4289,121 +4411,150 @@ found:  	dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", codec->name);  	snd_soc_cache_exit(codec); -	kfree(codec->reg_def_copy);  	kfree(codec->name);  	kfree(codec);  }  EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); - -/** - * snd_soc_register_component - Register a component with the ASoC core - * - */ -int snd_soc_register_component(struct device *dev, -			 const struct snd_soc_component_driver *cmpnt_drv, -			 struct snd_soc_dai_driver *dai_drv, -			 int num_dai) +/* Retrieve a card's name from device tree */ +int snd_soc_of_parse_card_name(struct snd_soc_card *card, +			       const char *propname)  { -	struct snd_soc_component *cmpnt; +	struct device_node *np = card->dev->of_node;  	int ret; -	dev_dbg(dev, "component register %s\n", dev_name(dev)); - -	cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); -	if (!cmpnt) { -		dev_err(dev, "ASoC: Failed to allocate memory\n"); -		return -ENOMEM; +	ret = of_property_read_string_index(np, propname, 0, &card->name); +	/* +	 * EINVAL means the property does not exist. This is fine providing +	 * card->name was previously set, which is checked later in +	 * snd_soc_register_card. +	 */ +	if (ret < 0 && ret != -EINVAL) { +		dev_err(card->dev, +			"ASoC: Property '%s' could not be read: %d\n", +			propname, ret); +		return ret;  	} -	cmpnt->name = fmt_single_name(dev, &cmpnt->id); -	if (!cmpnt->name) { -		dev_err(dev, "ASoC: Failed to simplifying name\n"); -		return -ENOMEM; -	} +	return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); -	cmpnt->dev	= dev; -	cmpnt->driver	= cmpnt_drv; -	cmpnt->num_dai	= num_dai; +static const struct snd_soc_dapm_widget simple_widgets[] = { +	SND_SOC_DAPM_MIC("Microphone", NULL), +	SND_SOC_DAPM_LINE("Line", NULL), +	SND_SOC_DAPM_HP("Headphone", NULL), +	SND_SOC_DAPM_SPK("Speaker", NULL), +}; -	/* -	 * snd_soc_register_dai()  uses fmt_single_name(), and -	 * snd_soc_register_dais() uses fmt_multiple_name() -	 * for dai->name which is used for name based matching -	 */ -	if (1 == num_dai) -		ret = snd_soc_register_dai(dev, dai_drv); -	else -		ret = snd_soc_register_dais(dev, dai_drv, num_dai); -	if (ret < 0) { -		dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); -		goto error_component_name; +int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, +					  const char *propname) +{ +	struct device_node *np = card->dev->of_node; +	struct snd_soc_dapm_widget *widgets; +	const char *template, *wname; +	int i, j, num_widgets, ret; + +	num_widgets = of_property_count_strings(np, propname); +	if (num_widgets < 0) { +		dev_err(card->dev, +			"ASoC: Property '%s' does not exist\n",	propname); +		return -EINVAL; +	} +	if (num_widgets & 1) { +		dev_err(card->dev, +			"ASoC: Property '%s' length is not even\n", propname); +		return -EINVAL;  	} -	mutex_lock(&client_mutex); -	list_add(&cmpnt->list, &component_list); -	mutex_unlock(&client_mutex); +	num_widgets /= 2; +	if (!num_widgets) { +		dev_err(card->dev, "ASoC: Property '%s's length is zero\n", +			propname); +		return -EINVAL; +	} -	dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); +	widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets), +			       GFP_KERNEL); +	if (!widgets) { +		dev_err(card->dev, +			"ASoC: Could not allocate memory for widgets\n"); +		return -ENOMEM; +	} -	return ret; +	for (i = 0; i < num_widgets; i++) { +		ret = of_property_read_string_index(np, propname, +			2 * i, &template); +		if (ret) { +			dev_err(card->dev, +				"ASoC: Property '%s' index %d read error:%d\n", +				propname, 2 * i, ret); +			return -EINVAL; +		} -error_component_name: -	kfree(cmpnt->name); +		for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) { +			if (!strncmp(template, simple_widgets[j].name, +				     strlen(simple_widgets[j].name))) { +				widgets[i] = simple_widgets[j]; +				break; +			} +		} -	return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_register_component); +		if (j >= ARRAY_SIZE(simple_widgets)) { +			dev_err(card->dev, +				"ASoC: DAPM widget '%s' is not supported\n", +				template); +			return -EINVAL; +		} -/** - * snd_soc_unregister_component - Unregister a component from the ASoC core - * - */ -void snd_soc_unregister_component(struct device *dev) -{ -	struct snd_soc_component *cmpnt; +		ret = of_property_read_string_index(np, propname, +						    (2 * i) + 1, +						    &wname); +		if (ret) { +			dev_err(card->dev, +				"ASoC: Property '%s' index %d read error:%d\n", +				propname, (2 * i) + 1, ret); +			return -EINVAL; +		} -	list_for_each_entry(cmpnt, &component_list, list) { -		if (dev == cmpnt->dev) -			goto found; +		widgets[i].name = wname;  	} -	return; -found: -	snd_soc_unregister_dais(dev, cmpnt->num_dai); +	card->dapm_widgets = widgets; +	card->num_dapm_widgets = num_widgets; -	mutex_lock(&client_mutex); -	list_del(&cmpnt->list); -	mutex_unlock(&client_mutex); - -	dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); -	kfree(cmpnt->name); +	return 0;  } -EXPORT_SYMBOL_GPL(snd_soc_unregister_component); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); -/* Retrieve a card's name from device tree */ -int snd_soc_of_parse_card_name(struct snd_soc_card *card, -			       const char *propname) +int snd_soc_of_parse_tdm_slot(struct device_node *np, +			      unsigned int *slots, +			      unsigned int *slot_width)  { -	struct device_node *np = card->dev->of_node; +	u32 val;  	int ret; -	ret = of_property_read_string_index(np, propname, 0, &card->name); -	/* -	 * EINVAL means the property does not exist. This is fine providing -	 * card->name was previously set, which is checked later in -	 * snd_soc_register_card. -	 */ -	if (ret < 0 && ret != -EINVAL) { -		dev_err(card->dev, -			"ASoC: Property '%s' could not be read: %d\n", -			propname, ret); -		return ret; +	if (of_property_read_bool(np, "dai-tdm-slot-num")) { +		ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); +		if (ret) +			return ret; + +		if (slots) +			*slots = val; +	} + +	if (of_property_read_bool(np, "dai-tdm-slot-width")) { +		ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); +		if (ret) +			return ret; + +		if (slot_width) +			*slot_width = val;  	}  	return 0;  } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);  int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,  				   const char *propname) @@ -4462,7 +4613,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,  EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);  unsigned int snd_soc_of_parse_daifmt(struct device_node *np, -				     const char *prefix) +				     const char *prefix, +				     struct device_node **bitclkmaster, +				     struct device_node **framemaster)  {  	int ret, i;  	char prop[128]; @@ -4545,9 +4698,13 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,  	 */  	snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);  	bit = !!of_get_property(np, prop, NULL); +	if (bit && bitclkmaster) +		*bitclkmaster = of_parse_phandle(np, prop, 0);  	snprintf(prop, sizeof(prop), "%sframe-master", prefix);  	frame = !!of_get_property(np, prop, NULL); +	if (frame && framemaster) +		*framemaster = of_parse_phandle(np, prop, 0);  	switch ((bit << 4) + frame) {  	case 0x11: @@ -4568,6 +4725,64 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,  }  EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); +int snd_soc_of_get_dai_name(struct device_node *of_node, +			    const char **dai_name) +{ +	struct snd_soc_component *pos; +	struct of_phandle_args args; +	int ret; + +	ret = of_parse_phandle_with_args(of_node, "sound-dai", +					 "#sound-dai-cells", 0, &args); +	if (ret) +		return ret; + +	ret = -EPROBE_DEFER; + +	mutex_lock(&client_mutex); +	list_for_each_entry(pos, &component_list, list) { +		if (pos->dev->of_node != args.np) +			continue; + +		if (pos->driver->of_xlate_dai_name) { +			ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); +		} else { +			int id = -1; + +			switch (args.args_count) { +			case 0: +				id = 0; /* same as dai_drv[0] */ +				break; +			case 1: +				id = args.args[0]; +				break; +			default: +				/* not supported */ +				break; +			} + +			if (id < 0 || id >= pos->num_dai) { +				ret = -EINVAL; +				continue; +			} + +			ret = 0; + +			*dai_name = pos->dai_drv[id].name; +			if (!*dai_name) +				*dai_name = pos->name; +		} + +		break; +	} +	mutex_unlock(&client_mutex); + +	of_node_put(args.np); + +	return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); +  static int __init snd_soc_init(void)  {  #ifdef CONFIG_DEBUG_FS  | 
