mirror of https://gitee.com/openkylin/linux.git
greybus: audio: add runtime pm support
Add runtime pm support to audio protocol device class driver. Testing Done: - Use white speaker module and check the interface is autosuspended when it's idle and resumed when playback audio Signed-off-by: David Lin <dtwlin@google.com> Signed-off-by: Axel Haslam <ahaslam@baylibre.com> Reviewed-by: Vaibhav Agarwal <vaibhav.agarwal@linaro.org> Signed-off-by: Alex Elder <elder@linaro.org>
This commit is contained in:
parent
61e13db9cc
commit
6ba7fad430
|
@ -33,12 +33,17 @@ int gb_audio_apbridgea_register_cport(struct gb_connection *connection,
|
|||
__u8 direction)
|
||||
{
|
||||
struct audio_apbridgea_register_cport_request req;
|
||||
int ret;
|
||||
|
||||
req.hdr.type = AUDIO_APBRIDGEA_TYPE_REGISTER_CPORT;
|
||||
req.hdr.i2s_port = cpu_to_le16(i2s_port);
|
||||
req.cport = cpu_to_le16(cportid);
|
||||
req.direction = direction;
|
||||
|
||||
ret = gb_pm_runtime_get_sync(connection->bundle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return gb_hd_output(connection->hd, &req, sizeof(req),
|
||||
GB_APB_REQUEST_AUDIO_CONTROL, true);
|
||||
}
|
||||
|
@ -49,14 +54,19 @@ int gb_audio_apbridgea_unregister_cport(struct gb_connection *connection,
|
|||
__u8 direction)
|
||||
{
|
||||
struct audio_apbridgea_unregister_cport_request req;
|
||||
int ret;
|
||||
|
||||
req.hdr.type = AUDIO_APBRIDGEA_TYPE_UNREGISTER_CPORT;
|
||||
req.hdr.i2s_port = cpu_to_le16(i2s_port);
|
||||
req.cport = cpu_to_le16(cportid);
|
||||
req.direction = direction;
|
||||
|
||||
return gb_hd_output(connection->hd, &req, sizeof(req),
|
||||
GB_APB_REQUEST_AUDIO_CONTROL, true);
|
||||
ret = gb_hd_output(connection->hd, &req, sizeof(req),
|
||||
GB_APB_REQUEST_AUDIO_CONTROL, true);
|
||||
|
||||
gb_pm_runtime_put_autosuspend(connection->bundle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gb_audio_apbridgea_unregister_cport);
|
||||
|
||||
|
|
|
@ -332,6 +332,8 @@ static int gb_audio_probe(struct gb_bundle *bundle,
|
|||
|
||||
dev_dbg(dev, "Add GB Audio device:%s\n", gbmodule->name);
|
||||
|
||||
gb_pm_runtime_put_autosuspend(bundle);
|
||||
|
||||
return 0;
|
||||
|
||||
disable_data_connection:
|
||||
|
@ -366,6 +368,8 @@ static void gb_audio_disconnect(struct gb_bundle *bundle)
|
|||
struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
|
||||
struct gbaudio_data_connection *dai, *_dai;
|
||||
|
||||
gb_pm_runtime_get_sync(bundle);
|
||||
|
||||
/* cleanup module related resources first */
|
||||
gbaudio_unregister_module(gbmodule);
|
||||
|
||||
|
@ -394,11 +398,58 @@ static const struct greybus_bundle_id gb_audio_id_table[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(greybus, gb_audio_id_table);
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int gb_audio_suspend(struct device *dev)
|
||||
{
|
||||
struct gb_bundle *bundle = to_gb_bundle(dev);
|
||||
struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
|
||||
struct gbaudio_data_connection *dai;
|
||||
|
||||
list_for_each_entry(dai, &gbmodule->data_list, list)
|
||||
gb_connection_disable(dai->connection);
|
||||
|
||||
gb_connection_disable(gbmodule->mgmt_connection);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gb_audio_resume(struct device *dev)
|
||||
{
|
||||
struct gb_bundle *bundle = to_gb_bundle(dev);
|
||||
struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
|
||||
struct gbaudio_data_connection *dai;
|
||||
int ret;
|
||||
|
||||
ret = gb_connection_enable(gbmodule->mgmt_connection);
|
||||
if (ret) {
|
||||
dev_err(dev, "%d:Error while enabling mgmt connection\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
list_for_each_entry(dai, &gbmodule->data_list, list) {
|
||||
ret = gb_connection_enable(dai->connection);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"%d:Error while enabling %d:data connection\n",
|
||||
ret, dai->data_cport);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops gb_audio_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(gb_audio_suspend, gb_audio_resume, NULL)
|
||||
};
|
||||
|
||||
static struct greybus_driver gb_audio_driver = {
|
||||
.name = "gb-audio",
|
||||
.probe = gb_audio_probe,
|
||||
.disconnect = gb_audio_disconnect,
|
||||
.id_table = gb_audio_id_table,
|
||||
.driver.pm = &gb_audio_pm_ops,
|
||||
};
|
||||
module_greybus_driver(gb_audio_driver);
|
||||
|
||||
|
|
|
@ -213,6 +213,7 @@ static int gbcodec_mixer_ctl_get(struct snd_kcontrol *kcontrol,
|
|||
struct gbaudio_module_info *module;
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
|
||||
struct gb_bundle *bundle;
|
||||
|
||||
dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
|
||||
module = find_gb_module(gb, kcontrol->id.name);
|
||||
|
@ -221,9 +222,17 @@ static int gbcodec_mixer_ctl_get(struct snd_kcontrol *kcontrol,
|
|||
|
||||
data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
|
||||
info = (struct gb_audio_ctl_elem_info *)data->info;
|
||||
bundle = to_gb_bundle(module->dev);
|
||||
|
||||
ret = gb_pm_runtime_get_sync(bundle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = gb_audio_gb_get_control(module->mgmt_connection, data->ctl_id,
|
||||
GB_AUDIO_INVALID_INDEX, &gbvalue);
|
||||
|
||||
gb_pm_runtime_put_autosuspend(bundle);
|
||||
|
||||
if (ret) {
|
||||
dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret,
|
||||
__func__, kcontrol->id.name);
|
||||
|
@ -266,6 +275,7 @@ static int gbcodec_mixer_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
struct gbaudio_module_info *module;
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
|
||||
struct gb_bundle *bundle;
|
||||
|
||||
dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
|
||||
module = find_gb_module(gb, kcontrol->id.name);
|
||||
|
@ -274,6 +284,7 @@ static int gbcodec_mixer_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
|
||||
data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
|
||||
info = (struct gb_audio_ctl_elem_info *)data->info;
|
||||
bundle = to_gb_bundle(module->dev);
|
||||
|
||||
/* update ucontrol */
|
||||
switch (info->type) {
|
||||
|
@ -299,11 +310,18 @@ static int gbcodec_mixer_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = gb_pm_runtime_get_sync(bundle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = gb_audio_gb_set_control(module->mgmt_connection, data->ctl_id,
|
||||
GB_AUDIO_INVALID_INDEX, &gbvalue);
|
||||
|
||||
gb_pm_runtime_put_autosuspend(bundle);
|
||||
|
||||
if (ret) {
|
||||
dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret,
|
||||
__func__, kcontrol->id.name);
|
||||
|
@ -370,6 +388,7 @@ static int gbcodec_mixer_dapm_ctl_get(struct snd_kcontrol *kcontrol,
|
|||
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
||||
struct snd_soc_codec *codec = widget->codec;
|
||||
struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
|
||||
struct gb_bundle *bundle;
|
||||
|
||||
dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
|
||||
module = find_gb_module(gb, kcontrol->id.name);
|
||||
|
@ -378,14 +397,22 @@ static int gbcodec_mixer_dapm_ctl_get(struct snd_kcontrol *kcontrol,
|
|||
|
||||
data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
|
||||
info = (struct gb_audio_ctl_elem_info *)data->info;
|
||||
bundle = to_gb_bundle(module->dev);
|
||||
|
||||
if (data->vcount == 2)
|
||||
dev_warn(widget->dapm->dev,
|
||||
"GB: Control '%s' is stereo, which is not supported\n",
|
||||
kcontrol->id.name);
|
||||
|
||||
ret = gb_pm_runtime_get_sync(bundle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = gb_audio_gb_get_control(module->mgmt_connection, data->ctl_id,
|
||||
GB_AUDIO_INVALID_INDEX, &gbvalue);
|
||||
|
||||
gb_pm_runtime_put_autosuspend(bundle);
|
||||
|
||||
if (ret) {
|
||||
dev_err_ratelimited(codec->dev, "%d:Error in %s for %s\n", ret,
|
||||
__func__, kcontrol->id.name);
|
||||
|
@ -410,6 +437,7 @@ static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
||||
struct snd_soc_codec *codec = widget->codec;
|
||||
struct gbaudio_codec_info *gb = snd_soc_codec_get_drvdata(codec);
|
||||
struct gb_bundle *bundle;
|
||||
|
||||
dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
|
||||
module = find_gb_module(gb, kcontrol->id.name);
|
||||
|
@ -418,6 +446,7 @@ static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
|
||||
data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
|
||||
info = (struct gb_audio_ctl_elem_info *)data->info;
|
||||
bundle = to_gb_bundle(module->dev);
|
||||
|
||||
if (data->vcount == 2)
|
||||
dev_warn(widget->dapm->dev,
|
||||
|
@ -441,9 +470,17 @@ static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
}
|
||||
gbvalue.value.integer_value[0] =
|
||||
ucontrol->value.integer.value[0];
|
||||
|
||||
ret = gb_pm_runtime_get_sync(bundle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = gb_audio_gb_set_control(module->mgmt_connection,
|
||||
data->ctl_id,
|
||||
GB_AUDIO_INVALID_INDEX, &gbvalue);
|
||||
|
||||
gb_pm_runtime_put_autosuspend(bundle);
|
||||
|
||||
if (ret) {
|
||||
dev_err_ratelimited(codec->dev,
|
||||
"%d:Error in %s for %s\n", ret,
|
||||
|
@ -850,6 +887,7 @@ static int gbaudio_widget_event(struct snd_soc_dapm_widget *w,
|
|||
struct snd_soc_codec *codec = w->codec;
|
||||
struct gbaudio_codec_info *gbcodec = snd_soc_codec_get_drvdata(codec);
|
||||
struct gbaudio_module_info *module;
|
||||
struct gb_bundle *bundle;
|
||||
|
||||
dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
|
||||
|
||||
|
@ -865,6 +903,12 @@ static int gbaudio_widget_event(struct snd_soc_dapm_widget *w,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
bundle = to_gb_bundle(module->dev);
|
||||
|
||||
ret = gb_pm_runtime_get_sync(bundle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
ret = gb_audio_gb_enable_widget(module->mgmt_connection, wid);
|
||||
|
@ -883,6 +927,9 @@ static int gbaudio_widget_event(struct snd_soc_dapm_widget *w,
|
|||
dev_err_ratelimited(codec->dev,
|
||||
"%d: widget, event:%d failed:%d\n", wid,
|
||||
event, ret);
|
||||
|
||||
gb_pm_runtime_put_autosuspend(bundle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue