From 8d346df0620eaeddfa1333d413596898fa7e576a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 21 May 2015 11:47:24 +0200 Subject: [PATCH 01/25] greybus: gpbridge: fix section mismatches Fix section mismatches introduced by b27227ce93c0 ("greybus: Use gb_gpbridge_protocol_init()"), which added __exit annotation to gpbridge-protocol exit functions that are called in the error path of gpbridge_init, which lives in the init section. This triggered the following modpost warning: WARNING: modpost: Found 8 section mismatch(es). Fixes: 16b33d100bff ("protocol: Add gb_gpbridge_protocol_driver()") Fixes: b27227ce93c0 ("greybus: Use gb_gpbridge_protocol_init()") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/protocol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/greybus/protocol.h b/drivers/staging/greybus/protocol.h index 8bc3f769c398..f6739f3332cd 100644 --- a/drivers/staging/greybus/protocol.h +++ b/drivers/staging/greybus/protocol.h @@ -108,7 +108,7 @@ int __init gb_##__protocol##_init(void) \ { \ return gb_protocol_register(&__protocol); \ } \ -void __exit gb_##__protocol##_exit(void) \ +void gb_##__protocol##_exit(void) \ { \ gb_protocol_deregister(&__protocol); \ } \ From 0e995aab21dc4a74a4e2daca5df027937cb0b975 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 21 May 2015 15:54:27 -0700 Subject: [PATCH 02/25] greybus: gb-audio: Set clock edges to match rt5647 codec requirements The rt5647 codec on speaker and mediabar modules require that the following clock edge settings: ll_wclk_change_edge GB_I2S_MGMT_EDGE_FALLING ll_wclk_tx_edge GB_I2S_MGMT_EDGE_RISING ll_wclk_rx_edge GB_I2S_MGMT_EDGE_FALLING (Those are the setting that work, at least). So make the Greybus audio driver configure the GPBridge with those settings. Signed-off-by: Mark A. Greer Tested-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio-gb-cmds.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/greybus/audio-gb-cmds.c b/drivers/staging/greybus/audio-gb-cmds.c index daa3181c9422..ffecf3abee5e 100644 --- a/drivers/staging/greybus/audio-gb-cmds.c +++ b/drivers/staging/greybus/audio-gb-cmds.c @@ -134,8 +134,8 @@ int gb_i2s_mgmt_setup(struct gb_connection *connection) (cfg->ll_wclk_role & GB_I2S_MGMT_ROLE_MASTER) && (cfg->ll_wclk_polarity & GB_I2S_MGMT_POLARITY_NORMAL) && (cfg->ll_wclk_change_edge & GB_I2S_MGMT_EDGE_FALLING) && - (cfg->ll_wclk_tx_edge & GB_I2S_MGMT_EDGE_FALLING) && - (cfg->ll_wclk_rx_edge & GB_I2S_MGMT_EDGE_RISING) && + (cfg->ll_wclk_tx_edge & GB_I2S_MGMT_EDGE_RISING) && + (cfg->ll_wclk_rx_edge & GB_I2S_MGMT_EDGE_FALLING) && (cfg->ll_data_offset == 1)) break; } @@ -153,9 +153,9 @@ int gb_i2s_mgmt_setup(struct gb_connection *connection) set_cfg.config.ll_bclk_role = GB_I2S_MGMT_ROLE_MASTER; set_cfg.config.ll_wclk_role = GB_I2S_MGMT_ROLE_MASTER; set_cfg.config.ll_wclk_polarity = GB_I2S_MGMT_POLARITY_NORMAL; - set_cfg.config.ll_wclk_change_edge = GB_I2S_MGMT_EDGE_RISING; - set_cfg.config.ll_wclk_tx_edge = GB_I2S_MGMT_EDGE_FALLING; - set_cfg.config.ll_wclk_rx_edge = GB_I2S_MGMT_EDGE_RISING; + set_cfg.config.ll_wclk_change_edge = GB_I2S_MGMT_EDGE_FALLING; + set_cfg.config.ll_wclk_tx_edge = GB_I2S_MGMT_EDGE_RISING; + set_cfg.config.ll_wclk_rx_edge = GB_I2S_MGMT_EDGE_FALLING; ret = gb_i2s_mgmt_set_configuration(connection, &set_cfg); if (ret) { From 555a0645b17114c559a2079ed64a8edb079b2339 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 21 May 2015 15:54:48 -0700 Subject: [PATCH 03/25] greybus: gb-audio: Allocate space for 20 configurations The greybus code requires that an operation's response buffer be the exact size of the response; however, the size of the response to the GB_I2S_MGMT_TYPE_GET_SUPPORTED_CONFIGURATIONS operation is unknown. To fix this, an extension to the I2S specification is required. In the meantime, set the number of configurations returned to 20 because that is how many configurations will be returned (using "insider knowledge" of the firmware). Signed-off-by: Mark A. Greer Tested-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/greybus/audio.h b/drivers/staging/greybus/audio.h index 6a337d112976..fb88a48d1c0b 100644 --- a/drivers/staging/greybus/audio.h +++ b/drivers/staging/greybus/audio.h @@ -20,7 +20,7 @@ #define CONFIG_SAMPLES_PER_MSG 48L #define CONFIG_PERIOD_NS 1000000 /* send msg every 1ms */ -#define CONFIG_COUNT_MAX 32 +#define CONFIG_COUNT_MAX 20 #define CONFIG_I2S_REMOTE_DATA_CPORT 7 /* XXX shouldn't be hardcoded...*/ #define RT5647_SLAVE_ADDR 0x1b /* from toshiba/quanta code */ From 34aa7e1cadef05f9494ff1f0c4977e762d9f32fa Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 21 May 2015 15:56:56 -0700 Subject: [PATCH 04/25] greybus: gb-audio: Clean up codec name generation Instead of using the fixed suffix, '6-001b', in the codec name, generate it from the I2S adapter number and I2C address of the codec. Signed-off-by: Mark A. Greer Acked-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio.c | 6 +++++- drivers/staging/greybus/audio.h | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/staging/greybus/audio.c b/drivers/staging/greybus/audio.c index 232ba94b5b88..3e8c24275cc3 100644 --- a/drivers/staging/greybus/audio.c +++ b/drivers/staging/greybus/audio.c @@ -19,6 +19,9 @@ #define GB_AUDIO_DATA_DRIVER_NAME "gb_audio_data" #define GB_AUDIO_MGMT_DRIVER_NAME "gb_audio_mgmt" +#define RT5647_I2C_ADAPTER_NR 6 +#define RT5647_I2C_ADDR 0x1b + /* * gb_snd management functions */ @@ -111,7 +114,8 @@ static struct asoc_simple_card_info *setup_card_info(int device_count) #endif #if USE_RT5645 obj->card_info.daifmt = GB_FMTS; - sprintf(obj->codec_name, "rt5645.%s", "6-001b"); /* XXX do i2c bus addr dynamically */ + sprintf(obj->codec_name, "rt5645.%d-%04x", RT5647_I2C_ADAPTER_NR, + RT5647_I2C_ADDR); obj->card_info.codec_dai.name = "rt5645-aif1"; obj->card_info.codec_dai.fmt = SND_SOC_DAIFMT_CBM_CFM; obj->card_info.codec_dai.sysclk = 12288000; diff --git a/drivers/staging/greybus/audio.h b/drivers/staging/greybus/audio.h index fb88a48d1c0b..5095df9096f6 100644 --- a/drivers/staging/greybus/audio.h +++ b/drivers/staging/greybus/audio.h @@ -22,7 +22,6 @@ #define CONFIG_COUNT_MAX 20 #define CONFIG_I2S_REMOTE_DATA_CPORT 7 /* XXX shouldn't be hardcoded...*/ -#define RT5647_SLAVE_ADDR 0x1b /* from toshiba/quanta code */ /* Switch between dummy spdif and jetson rt5645 codec */ #define USE_RT5645 0 From 4c739e3adad46aded0428144681fdaa6437b9e84 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 21 May 2015 15:56:57 -0700 Subject: [PATCH 05/25] greybus: gb-audio: Fix DAI formats and master/slave settings Set the various DAI formats so the bridge on the module is the master of all clocks and the codec is the slave. The only DAI protocol currently supported is I2S. Signed-off-by: Mark A. Greer Acked-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/staging/greybus/audio.c b/drivers/staging/greybus/audio.c index 3e8c24275cc3..03196a044694 100644 --- a/drivers/staging/greybus/audio.c +++ b/drivers/staging/greybus/audio.c @@ -110,14 +110,15 @@ static struct asoc_simple_card_info *setup_card_info(int device_count) obj->card_info.platform = obj->platform_name; obj->card_info.cpu_dai.name = obj->dai_name; #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) - obj->card_info.cpu_dai.fmt = GB_FMTS; + obj->card_info.cpu_dai.fmt = SND_SOC_DAIFMT_CBM_CFM; #endif #if USE_RT5645 - obj->card_info.daifmt = GB_FMTS; + obj->card_info.daifmt = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S; sprintf(obj->codec_name, "rt5645.%d-%04x", RT5647_I2C_ADAPTER_NR, RT5647_I2C_ADDR); obj->card_info.codec_dai.name = "rt5645-aif1"; - obj->card_info.codec_dai.fmt = SND_SOC_DAIFMT_CBM_CFM; + obj->card_info.codec_dai.fmt = SND_SOC_DAIFMT_CBS_CFS; obj->card_info.codec_dai.sysclk = 12288000; #else sprintf(obj->codec_name, "spdif-dit"); From 827e27e8fe3cf1ce29343ed87e042075194ac6ca Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 21 May 2015 15:56:58 -0700 Subject: [PATCH 06/25] greybus: gb-audio: cpu_dai.fmt does not exist in v4.1 The asoc_simple_dai structure does not contain the 'fmt' member in Linux kernel version v4.1 and later so only build code that uses it when the kernel version is earlier than v4.1. Signed-off-by: Mark A. Greer Acked-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/greybus/audio.c b/drivers/staging/greybus/audio.c index 03196a044694..d4d1eff2d099 100644 --- a/drivers/staging/greybus/audio.c +++ b/drivers/staging/greybus/audio.c @@ -118,7 +118,9 @@ static struct asoc_simple_card_info *setup_card_info(int device_count) sprintf(obj->codec_name, "rt5645.%d-%04x", RT5647_I2C_ADAPTER_NR, RT5647_I2C_ADDR); obj->card_info.codec_dai.name = "rt5645-aif1"; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) obj->card_info.codec_dai.fmt = SND_SOC_DAIFMT_CBS_CFS; +#endif obj->card_info.codec_dai.sysclk = 12288000; #else sprintf(obj->codec_name, "spdif-dit"); From 415b83111caac7cd1b90e0df104f81bae8e6e4dd Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 21 May 2015 15:56:59 -0700 Subject: [PATCH 07/25] greybus: gb-audio: Add I2C device for rt5647 codec Add the I2C device node for the rt5647 codec. Eventually, this will be done automatically somewhere else but for now its done in the audio driver. Signed-off-by: Mark A. Greer Acked-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio.c | 20 +++++++++++++++++++- drivers/staging/greybus/audio.h | 2 ++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/staging/greybus/audio.c b/drivers/staging/greybus/audio.c index d4d1eff2d099..1cc7c04d562b 100644 --- a/drivers/staging/greybus/audio.c +++ b/drivers/staging/greybus/audio.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -157,6 +156,9 @@ static int gb_i2s_transmitter_connection_init(struct gb_connection *connection) struct gb_snd *snd_dev; struct platform_device *codec, *dai; struct asoc_simple_card_info *simple_card; +#if USE_RT5645 + struct i2c_board_info rt5647_info; +#endif unsigned long flags; int ret; @@ -219,6 +221,18 @@ static int gb_i2s_transmitter_connection_init(struct gb_connection *connection) goto out_get_ver; } +#if USE_RT5645 + rt5647_info.addr = RT5647_I2C_ADDR; + strlcpy(rt5647_info.type, "rt5647", I2C_NAME_SIZE); + + snd_dev->rt5647 = i2c_new_device(i2c_get_adapter(RT5647_I2C_ADAPTER_NR), + &rt5647_info); + if (!snd_dev->rt5647) { + pr_err("can't create rt5647 i2c device\n"); + goto out_get_ver; + } +#endif + return 0; out_get_ver: @@ -238,6 +252,10 @@ static void gb_i2s_transmitter_connection_exit(struct gb_connection *connection) snd_dev = (struct gb_snd *)connection->private; +#if USE_RT5645 + i2c_unregister_device(snd_dev->rt5647); +#endif + platform_device_unregister(&snd_dev->card); platform_device_unregister(&snd_dev->cpu_dai); platform_device_unregister(snd_dev->codec); diff --git a/drivers/staging/greybus/audio.h b/drivers/staging/greybus/audio.h index 5095df9096f6..020a8fc1d267 100644 --- a/drivers/staging/greybus/audio.h +++ b/drivers/staging/greybus/audio.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include "greybus.h" @@ -41,6 +42,7 @@ struct gb_snd { struct platform_device cpu_dai; struct platform_device *codec; struct asoc_simple_card_info *simple_card_info; + struct i2c_client *rt5647; struct gb_connection *mgmt_connection; struct gb_connection *i2s_tx_connection; struct gb_connection *i2s_rx_connection; From e803cf712c48e2923b89e134adde56a004a99722 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 21 May 2015 15:57:00 -0700 Subject: [PATCH 08/25] greybus: gb-audio: Remove useless comment Remove comment about adding start delay since it will be done when support for A/V synchronization is added. Signed-off-by: Mark A. Greer Acked-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio-gb-cmds.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/greybus/audio-gb-cmds.c b/drivers/staging/greybus/audio-gb-cmds.c index ffecf3abee5e..8a101286d7be 100644 --- a/drivers/staging/greybus/audio-gb-cmds.c +++ b/drivers/staging/greybus/audio-gb-cmds.c @@ -170,7 +170,6 @@ int gb_i2s_mgmt_setup(struct gb_connection *connection) goto free_get_cfg; } - /* XXX Add start delay here (probably 1ms) */ ret = gb_i2s_mgmt_activate_cport(connection, CONFIG_I2S_REMOTE_DATA_CPORT); if (ret) { From f9a4fee7fad79d46ef6a3b0142bed35638c8d620 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 21 May 2015 15:57:01 -0700 Subject: [PATCH 09/25] greybus: gb-audio: Activate TX CPort in PCM workqueue Currently, the I2S TX CPort is configured and activated during the Greybus audio initialization. Unfortunately, this prevents the audio driver from ever changing the I2S configuration. To allow the I2S configuration to change according to ASOC requests, move the CPort activation & deactivation to the audio-pcm workqueue. Now, when audio is running but the CPort is not active, it will be activated. When audio is not running and the CPort is active, it will be deactivated. This has the side-effect of sending the first piece of audio data immediately after activating the CPort which is really how it should work anyway. Signed-off-by: Mark A. Greer Acked-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio-gb-cmds.c | 11 +---------- drivers/staging/greybus/audio-pcm.c | 24 ++++++++++++++++++++++-- drivers/staging/greybus/audio.c | 10 +--------- drivers/staging/greybus/audio.h | 1 + 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/drivers/staging/greybus/audio-gb-cmds.c b/drivers/staging/greybus/audio-gb-cmds.c index 8a101286d7be..d625f782b513 100644 --- a/drivers/staging/greybus/audio-gb-cmds.c +++ b/drivers/staging/greybus/audio-gb-cmds.c @@ -165,17 +165,8 @@ int gb_i2s_mgmt_setup(struct gb_connection *connection) ret = gb_i2s_mgmt_set_samples_per_message(connection, CONFIG_SAMPLES_PER_MSG); - if (ret) { + if (ret) pr_err("set_samples_per_msg failed: %d\n", ret); - goto free_get_cfg; - } - - ret = gb_i2s_mgmt_activate_cport(connection, - CONFIG_I2S_REMOTE_DATA_CPORT); - if (ret) { - pr_err("activate_cport failed: %d\n", ret); - goto free_get_cfg; - } free_get_cfg: kfree(get_cfg); diff --git a/drivers/staging/greybus/audio-pcm.c b/drivers/staging/greybus/audio-pcm.c index 92436300b3eb..8eb803a7a40a 100644 --- a/drivers/staging/greybus/audio-pcm.c +++ b/drivers/staging/greybus/audio-pcm.c @@ -32,15 +32,33 @@ static void gb_pcm_work(struct work_struct *work) struct snd_pcm_substream *substream = snd_dev->substream; struct snd_pcm_runtime *runtime = substream->runtime; unsigned int stride, frames, oldptr; - int period_elapsed; + int period_elapsed, ret; char *address; long len; if (!snd_dev) return; - if (!atomic_read(&snd_dev->running)) + if (!atomic_read(&snd_dev->running)) { + if (snd_dev->cport_active) { + ret = gb_i2s_mgmt_deactivate_cport( + snd_dev->mgmt_connection, + CONFIG_I2S_REMOTE_DATA_CPORT); + if (ret) /* XXX Do what else with failure? */ + pr_err("deactivate_cport failed: %d\n", ret); + + snd_dev->cport_active = false; + } + return; + } else if (!snd_dev->cport_active) { + ret = gb_i2s_mgmt_activate_cport(snd_dev->mgmt_connection, + CONFIG_I2S_REMOTE_DATA_CPORT); + if (ret) + pr_err("activate_cport failed: %d\n", ret); + + snd_dev->cport_active = true; + } address = runtime->dma_area + snd_dev->hwptr_done; @@ -88,6 +106,7 @@ static enum hrtimer_restart gb_pcm_timer_function(struct hrtimer *hrtimer) void gb_pcm_hrtimer_start(struct gb_snd *snd_dev) { atomic_set(&snd_dev->running, 1); + queue_work(snd_dev->workqueue, &snd_dev->work); /* Activates CPort */ hrtimer_start(&snd_dev->timer, ns_to_ktime(CONFIG_PERIOD_NS), HRTIMER_MODE_REL); } @@ -96,6 +115,7 @@ void gb_pcm_hrtimer_stop(struct gb_snd *snd_dev) { atomic_set(&snd_dev->running, 0); hrtimer_cancel(&snd_dev->timer); + queue_work(snd_dev->workqueue, &snd_dev->work); /* Deactivates CPort */ } static int gb_pcm_hrtimer_init(struct gb_snd *snd_dev) diff --git a/drivers/staging/greybus/audio.c b/drivers/staging/greybus/audio.c index 1cc7c04d562b..1057e468d5d4 100644 --- a/drivers/staging/greybus/audio.c +++ b/drivers/staging/greybus/audio.c @@ -292,13 +292,11 @@ static int gb_i2s_mgmt_connection_init(struct gb_connection *connection) if (!snd_dev->send_data_req_buf) { ret = -ENOMEM; - goto err_deactivate_cport; + goto err_free_snd_dev; } return 0; -err_deactivate_cport: - gb_i2s_mgmt_deactivate_cport(connection, CONFIG_I2S_REMOTE_DATA_CPORT); err_free_snd_dev: gb_free_snd(snd_dev); return ret; @@ -307,12 +305,6 @@ err_free_snd_dev: static void gb_i2s_mgmt_connection_exit(struct gb_connection *connection) { struct gb_snd *snd_dev = (struct gb_snd *)connection->private; - int ret; - - ret = gb_i2s_mgmt_deactivate_cport(connection, - CONFIG_I2S_REMOTE_DATA_CPORT); - if (ret) - pr_err("deactivate_cport failed: %d\n", ret); kfree(snd_dev->send_data_req_buf); snd_dev->send_data_req_buf = NULL; diff --git a/drivers/staging/greybus/audio.h b/drivers/staging/greybus/audio.h index 020a8fc1d267..50a9ebb6612e 100644 --- a/drivers/staging/greybus/audio.h +++ b/drivers/staging/greybus/audio.h @@ -53,6 +53,7 @@ struct gb_snd { struct snd_pcm_substream *substream; struct hrtimer timer; atomic_t running; + bool cport_active; struct workqueue_struct *workqueue; struct work_struct work; int hwptr_done; From 48229e592f95b4d0071f7711bd4c0e54104724e4 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 21 May 2015 15:57:02 -0700 Subject: [PATCH 10/25] greybus: gb-audio: Activate TX connection Bundle CPort ID Currently, the audio driver activates & deactivates a predefined CPort ID but that can vary depending on the manifest data of the module. Instead, use the TX connection's Bundle CPort ID which contains the correct CPort ID. Signed-off-by: Mark A. Greer Acked-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio-pcm.c | 6 +++--- drivers/staging/greybus/audio.h | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/staging/greybus/audio-pcm.c b/drivers/staging/greybus/audio-pcm.c index 8eb803a7a40a..30030f8d3c22 100644 --- a/drivers/staging/greybus/audio-pcm.c +++ b/drivers/staging/greybus/audio-pcm.c @@ -42,8 +42,8 @@ static void gb_pcm_work(struct work_struct *work) if (!atomic_read(&snd_dev->running)) { if (snd_dev->cport_active) { ret = gb_i2s_mgmt_deactivate_cport( - snd_dev->mgmt_connection, - CONFIG_I2S_REMOTE_DATA_CPORT); + snd_dev->mgmt_connection, + snd_dev->i2s_tx_connection->bundle_cport_id); if (ret) /* XXX Do what else with failure? */ pr_err("deactivate_cport failed: %d\n", ret); @@ -53,7 +53,7 @@ static void gb_pcm_work(struct work_struct *work) return; } else if (!snd_dev->cport_active) { ret = gb_i2s_mgmt_activate_cport(snd_dev->mgmt_connection, - CONFIG_I2S_REMOTE_DATA_CPORT); + snd_dev->i2s_tx_connection->bundle_cport_id); if (ret) pr_err("activate_cport failed: %d\n", ret); diff --git a/drivers/staging/greybus/audio.h b/drivers/staging/greybus/audio.h index 50a9ebb6612e..012c69a3ed83 100644 --- a/drivers/staging/greybus/audio.h +++ b/drivers/staging/greybus/audio.h @@ -22,7 +22,6 @@ #define CONFIG_PERIOD_NS 1000000 /* send msg every 1ms */ #define CONFIG_COUNT_MAX 20 -#define CONFIG_I2S_REMOTE_DATA_CPORT 7 /* XXX shouldn't be hardcoded...*/ /* Switch between dummy spdif and jetson rt5645 codec */ #define USE_RT5645 0 From 6b34099ec326e6c94fc5cf3ce3e1e4a9877c43ea Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 21 May 2015 15:57:03 -0700 Subject: [PATCH 11/25] greybus: gb-audio: Set I2S Configuration according to ASOC requests Currently, the audio driver unconditionally sets the I2S configuration to have a sample rate of 48KHz, two channels, 16 bits per channel, in little endian order. Make this more flexible by setting the I2S configuration according to the arguments passed to the PCM 'hw_params' callback. To accomplish this, query for the supported I2S configurations at Greybus protocol init time and save them in the 'snd_dev' structure. When the 'hw_params' callback is called, compare its arguments to the table of supported configurations. If there is a match, set the I2S connection accordingly. Signed-off-by: Mark A. Greer Acked-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio-gb-cmds.c | 79 +++++++++++++++---------- drivers/staging/greybus/audio-pcm.c | 15 +++++ drivers/staging/greybus/audio.c | 12 +++- drivers/staging/greybus/audio.h | 8 ++- 4 files changed, 80 insertions(+), 34 deletions(-) diff --git a/drivers/staging/greybus/audio-gb-cmds.c b/drivers/staging/greybus/audio-gb-cmds.c index d625f782b513..73f47d84f1aa 100644 --- a/drivers/staging/greybus/audio-gb-cmds.c +++ b/drivers/staging/greybus/audio-gb-cmds.c @@ -89,21 +89,12 @@ int gb_i2s_mgmt_set_samples_per_message( &request, sizeof(request), NULL, 0); } -/* - * XXX This is sort of a generic "setup" function which probably needs - * to be broken up, and tied into the constraints. - * - * I'm on the fence if we should just dictate that we only support - * 48k, 16bit, 2 channel, and avoid doign the whole probe for configurations - * and then picking one. - */ -int gb_i2s_mgmt_setup(struct gb_connection *connection) +int gb_i2s_mgmt_get_cfgs(struct gb_snd *snd_dev, + struct gb_connection *connection) { struct gb_i2s_mgmt_get_supported_configurations_response *get_cfg; - struct gb_i2s_mgmt_set_configuration_request set_cfg; - struct gb_i2s_mgmt_configuration *cfg; size_t size; - int i, ret; + int ret; size = sizeof(*get_cfg) + (CONFIG_COUNT_MAX * sizeof(get_cfg->config[0])); @@ -116,19 +107,48 @@ int gb_i2s_mgmt_setup(struct gb_connection *connection) size); if (ret) { pr_err("get_supported_config failed: %d\n", ret); - goto free_get_cfg; + goto err_free_get_cfg; } - /* Pick 48KHz 16-bits/channel */ - for (i = 0, cfg = get_cfg->config; i < CONFIG_COUNT_MAX; i++, cfg++) { - if ((le32_to_cpu(cfg->sample_frequency) == GB_SAMPLE_RATE) && - (cfg->num_channels == 2) && - (cfg->bytes_per_channel == 2) && - (cfg->byte_order & GB_I2S_MGMT_BYTE_ORDER_LE) && - (le32_to_cpu(cfg->spatial_locations) == - (GB_I2S_MGMT_SPATIAL_LOCATION_FL | - GB_I2S_MGMT_SPATIAL_LOCATION_FR)) && - (le32_to_cpu(cfg->ll_protocol) & GB_I2S_MGMT_PROTOCOL_I2S) && + snd_dev->i2s_configs = get_cfg; + + return 0; + +err_free_get_cfg: + kfree(get_cfg); + return ret; +} + +void gb_i2s_mgmt_free_cfgs(struct gb_snd *snd_dev) +{ + kfree(snd_dev->i2s_configs); + snd_dev->i2s_configs = NULL; +} + +int gb_i2s_mgmt_set_cfg(struct gb_snd *snd_dev, int rate, int chans, + int bytes_per_chan, int is_le) +{ + struct gb_i2s_mgmt_set_configuration_request set_cfg; + struct gb_i2s_mgmt_configuration *cfg; + int i, ret; + u8 byte_order = GB_I2S_MGMT_BYTE_ORDER_NA; + + if (bytes_per_chan > 1) { + if (is_le) + byte_order = GB_I2S_MGMT_BYTE_ORDER_LE; + else + byte_order = GB_I2S_MGMT_BYTE_ORDER_BE; + } + + for (i = 0, cfg = snd_dev->i2s_configs->config; + i < CONFIG_COUNT_MAX; + i++, cfg++) { + if ((cfg->sample_frequency == cpu_to_le32(rate)) && + (cfg->num_channels == chans) && + (cfg->bytes_per_channel == bytes_per_chan) && + (cfg->byte_order & byte_order) && + (cfg->ll_protocol & + cpu_to_le32(GB_I2S_MGMT_PROTOCOL_I2S)) && (cfg->ll_mclk_role & GB_I2S_MGMT_ROLE_MASTER) && (cfg->ll_bclk_role & GB_I2S_MGMT_ROLE_MASTER) && (cfg->ll_wclk_role & GB_I2S_MGMT_ROLE_MASTER) && @@ -142,12 +162,11 @@ int gb_i2s_mgmt_setup(struct gb_connection *connection) if (i >= CONFIG_COUNT_MAX) { pr_err("No valid configuration\n"); - ret = -EINVAL; - goto free_get_cfg; + return -EINVAL; } memcpy(&set_cfg, cfg, sizeof(set_cfg)); - set_cfg.config.byte_order = GB_I2S_MGMT_BYTE_ORDER_LE; + set_cfg.config.byte_order = byte_order; set_cfg.config.ll_protocol = cpu_to_le32(GB_I2S_MGMT_PROTOCOL_I2S); set_cfg.config.ll_mclk_role = GB_I2S_MGMT_ROLE_MASTER; set_cfg.config.ll_bclk_role = GB_I2S_MGMT_ROLE_MASTER; @@ -157,19 +176,17 @@ int gb_i2s_mgmt_setup(struct gb_connection *connection) set_cfg.config.ll_wclk_tx_edge = GB_I2S_MGMT_EDGE_RISING; set_cfg.config.ll_wclk_rx_edge = GB_I2S_MGMT_EDGE_FALLING; - ret = gb_i2s_mgmt_set_configuration(connection, &set_cfg); + ret = gb_i2s_mgmt_set_configuration(snd_dev->mgmt_connection, &set_cfg); if (ret) { pr_err("set_configuration failed: %d\n", ret); - goto free_get_cfg; + return ret; } - ret = gb_i2s_mgmt_set_samples_per_message(connection, + ret = gb_i2s_mgmt_set_samples_per_message(snd_dev->mgmt_connection, CONFIG_SAMPLES_PER_MSG); if (ret) pr_err("set_samples_per_msg failed: %d\n", ret); -free_get_cfg: - kfree(get_cfg); return ret; } diff --git a/drivers/staging/greybus/audio-pcm.c b/drivers/staging/greybus/audio-pcm.c index 30030f8d3c22..b32700841444 100644 --- a/drivers/staging/greybus/audio-pcm.c +++ b/drivers/staging/greybus/audio-pcm.c @@ -220,6 +220,21 @@ static int gb_pcm_close(struct snd_pcm_substream *substream) static int gb_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct gb_snd *snd_dev; + int rate, chans, bytes_per_chan, is_le, ret; + + snd_dev = snd_soc_dai_get_drvdata(rtd->cpu_dai); + + rate = params_rate(hw_params); + chans = params_channels(hw_params); + bytes_per_chan = snd_pcm_format_width(params_format(hw_params)) / 8; + is_le = snd_pcm_format_little_endian(params_format(hw_params)); + + ret = gb_i2s_mgmt_set_cfg(snd_dev, rate, chans, bytes_per_chan, is_le); + if (ret) + return ret; + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } diff --git a/drivers/staging/greybus/audio.c b/drivers/staging/greybus/audio.c index 1057e468d5d4..a1acbb039777 100644 --- a/drivers/staging/greybus/audio.c +++ b/drivers/staging/greybus/audio.c @@ -286,17 +286,23 @@ static int gb_i2s_mgmt_connection_init(struct gb_connection *connection) goto err_free_snd_dev; } - gb_i2s_mgmt_setup(connection); + ret = gb_i2s_mgmt_get_cfgs(snd_dev, connection); + if (ret) { + pr_err("can't get i2s configurations: %d\n", ret); + goto err_free_snd_dev; + } snd_dev->send_data_req_buf = kzalloc(SEND_DATA_BUF_LEN, GFP_KERNEL); if (!snd_dev->send_data_req_buf) { ret = -ENOMEM; - goto err_free_snd_dev; + goto err_free_i2s_configs; } return 0; +err_free_i2s_configs: + gb_i2s_mgmt_free_cfgs(snd_dev); err_free_snd_dev: gb_free_snd(snd_dev); return ret; @@ -306,6 +312,8 @@ static void gb_i2s_mgmt_connection_exit(struct gb_connection *connection) { struct gb_snd *snd_dev = (struct gb_snd *)connection->private; + gb_i2s_mgmt_free_cfgs(snd_dev); + kfree(snd_dev->send_data_req_buf); snd_dev->send_data_req_buf = NULL; diff --git a/drivers/staging/greybus/audio.h b/drivers/staging/greybus/audio.h index 012c69a3ed83..fa1bb54fd4da 100644 --- a/drivers/staging/greybus/audio.h +++ b/drivers/staging/greybus/audio.h @@ -45,6 +45,8 @@ struct gb_snd { struct gb_connection *mgmt_connection; struct gb_connection *i2s_tx_connection; struct gb_connection *i2s_rx_connection; + struct gb_i2s_mgmt_get_supported_configurations_response + *i2s_configs; char *send_data_req_buf; long send_data_sample_count; int gb_bundle_id; @@ -79,7 +81,11 @@ int gb_i2s_mgmt_set_configuration(struct gb_connection *connection, struct gb_i2s_mgmt_set_configuration_request *set_cfg); int gb_i2s_mgmt_set_samples_per_message(struct gb_connection *connection, uint16_t samples_per_message); -int gb_i2s_mgmt_setup(struct gb_connection *connection); +int gb_i2s_mgmt_get_cfgs(struct gb_snd *snd_dev, + struct gb_connection *connection); +void gb_i2s_mgmt_free_cfgs(struct gb_snd *snd_dev); +int gb_i2s_mgmt_set_cfg(struct gb_snd *snd_dev, int rate, int chans, + int bytes_per_chan, int is_le); int gb_i2s_send_data(struct gb_connection *connection, void *req_buf, void *source_addr, size_t len, int sample_num); From 0d17e0c9f164d9c56471438b51ad75f4e894effa Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 21 May 2015 15:57:04 -0700 Subject: [PATCH 12/25] greybus: gb-audio: Set samples per message during init A recent commit moved the I2S samples per message operation to the PCM's 'hw_params' callback. However, the 'hw_params' callback is called numerous times while the samples per message need only be done once (or seldom). Eliminate the unnecessary samples per message operations by doing it only once at Greybus protocol init time. Signed-off-by: Mark A. Greer Acked-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio-gb-cmds.c | 9 +-------- drivers/staging/greybus/audio.c | 7 +++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/staging/greybus/audio-gb-cmds.c b/drivers/staging/greybus/audio-gb-cmds.c index 73f47d84f1aa..9dbde0d07a49 100644 --- a/drivers/staging/greybus/audio-gb-cmds.c +++ b/drivers/staging/greybus/audio-gb-cmds.c @@ -177,15 +177,8 @@ int gb_i2s_mgmt_set_cfg(struct gb_snd *snd_dev, int rate, int chans, set_cfg.config.ll_wclk_rx_edge = GB_I2S_MGMT_EDGE_FALLING; ret = gb_i2s_mgmt_set_configuration(snd_dev->mgmt_connection, &set_cfg); - if (ret) { - pr_err("set_configuration failed: %d\n", ret); - return ret; - } - - ret = gb_i2s_mgmt_set_samples_per_message(snd_dev->mgmt_connection, - CONFIG_SAMPLES_PER_MSG); if (ret) - pr_err("set_samples_per_msg failed: %d\n", ret); + pr_err("set_configuration failed: %d\n", ret); return ret; } diff --git a/drivers/staging/greybus/audio.c b/drivers/staging/greybus/audio.c index a1acbb039777..76b6bdc59847 100644 --- a/drivers/staging/greybus/audio.c +++ b/drivers/staging/greybus/audio.c @@ -292,6 +292,13 @@ static int gb_i2s_mgmt_connection_init(struct gb_connection *connection) goto err_free_snd_dev; } + ret = gb_i2s_mgmt_set_samples_per_message(snd_dev->mgmt_connection, + CONFIG_SAMPLES_PER_MSG); + if (ret) { + pr_err("set_samples_per_msg failed: %d\n", ret); + goto err_free_i2s_configs; + } + snd_dev->send_data_req_buf = kzalloc(SEND_DATA_BUF_LEN, GFP_KERNEL); if (!snd_dev->send_data_req_buf) { From a702a09f20be5f52ea1789b92a228592f4777084 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 09:52:42 -0500 Subject: [PATCH 13/25] greybus: endo: rename gb_svc Change the name of "struct gb_svc" to be "struct svc_info". The structure now contains only the SVC's serial number and version (and are place holders anyway). We will be defining a structure that represents the SVC for the SVC protocol connection, and I want to take back that name. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/endo.c | 8 ++++---- drivers/staging/greybus/endo.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/staging/greybus/endo.c b/drivers/staging/greybus/endo.c index 42f26f07b52e..859c9c57989d 100644 --- a/drivers/staging/greybus/endo.c +++ b/drivers/staging/greybus/endo.c @@ -35,7 +35,7 @@ static ssize_t serial_number_show(struct device *dev, { struct gb_endo *endo = to_gb_endo(dev); - return sprintf(buf, "%s", &endo->svc.serial_number[0]); + return sprintf(buf, "%s", &endo->svc_info.serial_number[0]); } static DEVICE_ATTR_RO(serial_number); @@ -44,7 +44,7 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, { struct gb_endo *endo = to_gb_endo(dev); - return sprintf(buf, "%s", &endo->svc.version[0]); + return sprintf(buf, "%s", &endo->svc_info.version[0]); } static DEVICE_ATTR_RO(version); @@ -409,8 +409,8 @@ static int gb_endo_register(struct greybus_host_device *hd, // FIXME // Get the version and serial number from the SVC, right now we are // using "fake" numbers. - strcpy(&endo->svc.serial_number[0], "042"); - strcpy(&endo->svc.version[0], "0.0"); + strcpy(&endo->svc_info.serial_number[0], "042"); + strcpy(&endo->svc_info.version[0], "0.0"); dev_set_name(&endo->dev, "endo-0x%04x", endo->id); retval = device_add(&endo->dev); diff --git a/drivers/staging/greybus/endo.h b/drivers/staging/greybus/endo.h index dd0526949737..2920b130ce37 100644 --- a/drivers/staging/greybus/endo.h +++ b/drivers/staging/greybus/endo.h @@ -10,7 +10,7 @@ #define __ENDO_H /* Greybus "public" definitions" */ -struct gb_svc { +struct gb_svc_info { u8 serial_number[10]; u8 version[10]; }; @@ -36,9 +36,9 @@ struct endo_layout { }; struct gb_endo { - struct endo_layout layout; struct device dev; - struct gb_svc svc; + struct endo_layout layout; + struct gb_svc_info svc_info; u16 id; }; #define to_gb_endo(d) container_of(d, struct gb_endo, dev) From ee3ecf80284d973e491e653f74b2fd936c50bd2c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 09:52:43 -0500 Subject: [PATCH 14/25] greybus: endo: pass endo_id to gb_endo_create() We are going to want to defer creating the endo until we receive a probe operation from the SVC, which will supply the endo id. Change gb_endo_create() so it passes the endo_id value as an argument. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/core.c | 3 ++- drivers/staging/greybus/endo.c | 3 +-- drivers/staging/greybus/endo.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index e32d6c41e87e..27062e7a5824 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -177,6 +177,7 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver size_t buffer_size_max) { struct greybus_host_device *hd; + u16 endo_id = 0x4755; // FIXME - get endo "ID" from the SVC /* * Validate that the driver implements all of the callbacks @@ -210,7 +211,7 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver ida_init(&hd->cport_id_map); hd->buffer_size_max = buffer_size_max; - hd->endo = gb_endo_create(hd); + hd->endo = gb_endo_create(hd, endo_id); if (!hd->endo) { greybus_remove_hd(hd); return NULL; diff --git a/drivers/staging/greybus/endo.c b/drivers/staging/greybus/endo.c index 859c9c57989d..fb2f7c9c6dd7 100644 --- a/drivers/staging/greybus/endo.c +++ b/drivers/staging/greybus/endo.c @@ -423,11 +423,10 @@ static int gb_endo_register(struct greybus_host_device *hd, return retval; } -struct gb_endo *gb_endo_create(struct greybus_host_device *hd) +struct gb_endo *gb_endo_create(struct greybus_host_device *hd, u16 endo_id) { struct gb_endo *endo; int retval; - u16 endo_id = 0x4755; // FIXME - get endo "ID" from the SVC endo = kzalloc(sizeof(*endo), GFP_KERNEL); if (!endo) diff --git a/drivers/staging/greybus/endo.h b/drivers/staging/greybus/endo.h index 2920b130ce37..c1ccbcd576f3 100644 --- a/drivers/staging/greybus/endo.h +++ b/drivers/staging/greybus/endo.h @@ -47,7 +47,7 @@ struct gb_endo { /* Greybus "private" definitions */ struct greybus_host_device; -struct gb_endo *gb_endo_create(struct greybus_host_device *hd); +struct gb_endo *gb_endo_create(struct greybus_host_device *hd, u16 endo_id); void gb_endo_remove(struct gb_endo *endo); u8 endo_get_module_id(struct gb_endo *endo, u8 interface_id); From 6b7d5a1f47914b2e3917fb764b4b3fe3affe7f94 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 09:52:44 -0500 Subject: [PATCH 15/25] greybus: core: return error code when creating endo Return a pointer-coded error from gb_endo_create() rather than just a null pointer in the event an error occurs. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/core.c | 6 ++++-- drivers/staging/greybus/endo.c | 12 ++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index 27062e7a5824..95d8c70cf20d 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -177,6 +177,7 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver size_t buffer_size_max) { struct greybus_host_device *hd; + struct gb_endo *endo; u16 endo_id = 0x4755; // FIXME - get endo "ID" from the SVC /* @@ -211,11 +212,12 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver ida_init(&hd->cport_id_map); hd->buffer_size_max = buffer_size_max; - hd->endo = gb_endo_create(hd, endo_id); - if (!hd->endo) { + endo = gb_endo_create(hd, endo_id); + if (IS_ERR(endo)) { greybus_remove_hd(hd); return NULL; } + hd->endo = endo; return hd; } diff --git a/drivers/staging/greybus/endo.c b/drivers/staging/greybus/endo.c index fb2f7c9c6dd7..5b5a3c65de8f 100644 --- a/drivers/staging/greybus/endo.c +++ b/drivers/staging/greybus/endo.c @@ -430,16 +430,19 @@ struct gb_endo *gb_endo_create(struct greybus_host_device *hd, u16 endo_id) endo = kzalloc(sizeof(*endo), GFP_KERNEL); if (!endo) - return NULL; + return ERR_PTR(-ENOMEM); /* First check if the value supplied is a valid endo id */ - if (gb_endo_validate_id(hd, &endo->layout, endo_id)) + if (gb_endo_validate_id(hd, &endo->layout, endo_id)) { + retval = -EINVAL; goto free_endo; + } endo->id = endo_id; /* Register Endo device */ - if (gb_endo_register(hd, endo)) + retval = gb_endo_register(hd, endo); + if (retval) goto free_endo; /* Create modules/interfaces */ @@ -453,7 +456,8 @@ struct gb_endo *gb_endo_create(struct greybus_host_device *hd, u16 endo_id) free_endo: kfree(endo); - return NULL; + + return ERR_PTR(retval); } void gb_endo_remove(struct gb_endo *endo) From 8ea70fe0497c5dd11451e7cf1084844cbdb2a349 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 09:52:45 -0500 Subject: [PATCH 16/25] greybus: core: return error code when creating host device Return a pointer-coded error from greybus_create_hd() rather than NULL in the event an error occurs. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/core.c | 6 +++--- drivers/staging/greybus/es1.c | 4 ++-- drivers/staging/greybus/es2.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index 95d8c70cf20d..7bfdbadb6250 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -187,7 +187,7 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver if ((!driver->message_send) || (!driver->message_cancel) || (!driver->submit_svc)) { pr_err("Must implement all greybus_host_driver callbacks!\n"); - return NULL; + return ERR_PTR(-EINVAL); } /* @@ -202,7 +202,7 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL); if (!hd) - return NULL; + return ERR_PTR(-ENOMEM); kref_init(&hd->kref); hd->parent = parent; @@ -215,7 +215,7 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver endo = gb_endo_create(hd, endo_id); if (IS_ERR(endo)) { greybus_remove_hd(hd); - return NULL; + return ERR_CAST(endo); } hd->endo = endo; diff --git a/drivers/staging/greybus/es1.c b/drivers/staging/greybus/es1.c index e0fae26d8ba3..1ed10f4b8e49 100644 --- a/drivers/staging/greybus/es1.c +++ b/drivers/staging/greybus/es1.c @@ -556,9 +556,9 @@ static int ap_probe(struct usb_interface *interface, udev = usb_get_dev(interface_to_usbdev(interface)); hd = greybus_create_hd(&es1_driver, &udev->dev, ES1_GBUF_MSG_SIZE_MAX); - if (!hd) { + if (IS_ERR(hd)) { usb_put_dev(udev); - return -ENOMEM; + return PTR_ERR(hd); } es1 = hd_to_es1(hd); diff --git a/drivers/staging/greybus/es2.c b/drivers/staging/greybus/es2.c index 05aac3d7686b..4733adcb8a22 100644 --- a/drivers/staging/greybus/es2.c +++ b/drivers/staging/greybus/es2.c @@ -556,9 +556,9 @@ static int ap_probe(struct usb_interface *interface, udev = usb_get_dev(interface_to_usbdev(interface)); hd = greybus_create_hd(&es1_driver, &udev->dev, ES1_GBUF_MSG_SIZE_MAX); - if (!hd) { + if (IS_ERR(hd)) { usb_put_dev(udev); - return -ENOMEM; + return PTR_ERR(hd); } es1 = hd_to_es1(hd); From e9385e5d5ab64a0d05758d84f2980943d3f5f12d Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 12:35:31 -0500 Subject: [PATCH 17/25] greybus: include "gpbridge.h" from "greybus.h" Avoid the need for all the source files to include "gpbridge.h" by just having "greybus.h" include it. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio-dai.c | 2 +- drivers/staging/greybus/audio-gb-cmds.c | 2 +- drivers/staging/greybus/audio-pcm.c | 2 +- drivers/staging/greybus/audio.c | 2 +- drivers/staging/greybus/audio.h | 3 +-- drivers/staging/greybus/gpio.c | 1 - drivers/staging/greybus/greybus.h | 1 + drivers/staging/greybus/i2c.c | 2 -- drivers/staging/greybus/pwm.c | 2 +- drivers/staging/greybus/spi.c | 1 - 10 files changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/staging/greybus/audio-dai.c b/drivers/staging/greybus/audio-dai.c index 39b72f0d2138..0dd7364785ae 100644 --- a/drivers/staging/greybus/audio-dai.c +++ b/drivers/staging/greybus/audio-dai.c @@ -11,8 +11,8 @@ #include #include #include + #include "greybus.h" -#include "gpbridge.h" #include "audio.h" /* diff --git a/drivers/staging/greybus/audio-gb-cmds.c b/drivers/staging/greybus/audio-gb-cmds.c index 9dbde0d07a49..f6a29abca70f 100644 --- a/drivers/staging/greybus/audio-gb-cmds.c +++ b/drivers/staging/greybus/audio-gb-cmds.c @@ -1,6 +1,6 @@ #include + #include "greybus.h" -#include "gpbridge.h" #include "audio.h" #define GB_I2S_MGMT_VERSION_MAJOR 0x00 diff --git a/drivers/staging/greybus/audio-pcm.c b/drivers/staging/greybus/audio-pcm.c index b32700841444..a1faf7895b58 100644 --- a/drivers/staging/greybus/audio-pcm.c +++ b/drivers/staging/greybus/audio-pcm.c @@ -11,8 +11,8 @@ #include #include #include + #include "greybus.h" -#include "gpbridge.h" #include "audio.h" /* diff --git a/drivers/staging/greybus/audio.c b/drivers/staging/greybus/audio.c index 76b6bdc59847..c873f339da1d 100644 --- a/drivers/staging/greybus/audio.c +++ b/drivers/staging/greybus/audio.c @@ -10,8 +10,8 @@ #include #include #include + #include "greybus.h" -#include "gpbridge.h" #include "audio.h" diff --git a/drivers/staging/greybus/audio.h b/drivers/staging/greybus/audio.h index fa1bb54fd4da..c9087c9fc15c 100644 --- a/drivers/staging/greybus/audio.h +++ b/drivers/staging/greybus/audio.h @@ -7,9 +7,8 @@ #include #include #include -#include "greybus.h" -#include "gpbridge.h" +#include "greybus.h" #define GB_SAMPLE_RATE 48000 #define GB_RATES SNDRV_PCM_RATE_48000 diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c index 871f2d0558b0..6e5fe5b3db39 100644 --- a/drivers/staging/greybus/gpio.c +++ b/drivers/staging/greybus/gpio.c @@ -14,7 +14,6 @@ #include #include #include "greybus.h" -#include "gpbridge.h" struct gb_gpio_line { /* The following has to be an array of line_max entries */ diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index dbb4e78cf4c9..c58f12312d75 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -23,6 +23,7 @@ #include "kernel_ver.h" #include "greybus_id.h" #include "greybus_manifest.h" +#include "gpbridge.h" #include "manifest.h" #include "endo.h" #include "module.h" diff --git a/drivers/staging/greybus/i2c.c b/drivers/staging/greybus/i2c.c index 14fdea184c39..01afca8408a0 100644 --- a/drivers/staging/greybus/i2c.c +++ b/drivers/staging/greybus/i2c.c @@ -13,8 +13,6 @@ #include #include "greybus.h" -#include "gpbridge.h" - struct gb_i2c_device { struct gb_connection *connection; diff --git a/drivers/staging/greybus/pwm.c b/drivers/staging/greybus/pwm.c index 7f675bfed1d7..5dfeb0e761c1 100644 --- a/drivers/staging/greybus/pwm.c +++ b/drivers/staging/greybus/pwm.c @@ -11,8 +11,8 @@ #include #include #include + #include "greybus.h" -#include "gpbridge.h" struct gb_pwm_chip { struct gb_connection *connection; diff --git a/drivers/staging/greybus/spi.c b/drivers/staging/greybus/spi.c index 430c3ad70a5a..78a7f85a4bf6 100644 --- a/drivers/staging/greybus/spi.c +++ b/drivers/staging/greybus/spi.c @@ -14,7 +14,6 @@ #include #include "greybus.h" -#include "gpbridge.h" struct gb_spi { struct gb_connection *connection; From 22e17edaa7c24d254e572738420873813f47efb5 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 12:35:32 -0500 Subject: [PATCH 18/25] greybus: rename "gpbridge.h" The file "gpbridge.h" is now used as a single place to define all protocol message structures. These protocols are not necessarily related to the GP bridge, so the name of the file is misleading. Rename it "greybus_protocols.h". Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/greybus.h | 2 +- drivers/staging/greybus/{gpbridge.h => greybus_protocols.h} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename drivers/staging/greybus/{gpbridge.h => greybus_protocols.h} (100%) diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index c58f12312d75..4920458d65d0 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -23,7 +23,7 @@ #include "kernel_ver.h" #include "greybus_id.h" #include "greybus_manifest.h" -#include "gpbridge.h" +#include "greybus_protocols.h" #include "manifest.h" #include "endo.h" #include "module.h" diff --git a/drivers/staging/greybus/gpbridge.h b/drivers/staging/greybus/greybus_protocols.h similarity index 100% rename from drivers/staging/greybus/gpbridge.h rename to drivers/staging/greybus/greybus_protocols.h From 8a760437229ac327796902098f402ef75955b520 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 12:56:46 -0500 Subject: [PATCH 19/25] greybus: endo: encapsulate computing the max interface id The maximum interface id on an Endo is the result of a non-trivial calculation. It'll be needed for an upcoming patch, so create a macro to compute it. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/endo.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/staging/greybus/endo.c b/drivers/staging/greybus/endo.c index 5b5a3c65de8f..e4faa5cedb70 100644 --- a/drivers/staging/greybus/endo.c +++ b/drivers/staging/greybus/endo.c @@ -29,6 +29,20 @@ #define endo_back_left_ribs(id, ribs) (((id) >> (ribs)) & ENDO_BACK_SIDE_RIBS_MASK(ribs)) #define endo_back_right_ribs(id, ribs) ((id) & ENDO_BACK_SIDE_RIBS_MASK(ribs)) +/* + * An Endo has interface block positions on the front and back. + * Each has numeric ID, starting with 1 (interface 0 represents + * the SVC within the Endo itself). The maximum interface ID is the + * also the number of non-SVC interfaces possible on the endo. + * + * Total number of interfaces: + * - Front: 4 + * - Back left: max_ribs + 1 + * - Back right: max_ribs + 1 + */ +#define max_endo_interface_id(endo_layout) \ + (4 + ((endo_layout)->max_ribs + 1) * 2) + /* endo sysfs attributes */ static ssize_t serial_number_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -361,19 +375,12 @@ static int create_modules(struct gb_endo *endo) int prev_module_id = 0; int interface_id; int module_id; - int interfaces; + int max_id; - /* - * Total number of interfaces: - * - Front: 4 - * - Back: - * - Left: max_ribs + 1 - * - Right: max_ribs + 1 - */ - interfaces = 4 + (endo->layout.max_ribs + 1) * 2; + max_id = max_endo_interface_id(&endo->layout); /* Find module corresponding to each interface */ - for (interface_id = 1; interface_id <= interfaces; interface_id++) { + for (interface_id = 1; interface_id <= max_id; interface_id++) { module_id = endo_get_module_id(endo, interface_id); if (WARN_ON(!module_id)) From e45524f849434074ff91d75bb9360a08aa535ba4 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 12:56:47 -0500 Subject: [PATCH 20/25] greybus: endo: rework some attributes The SVC is not the same as the Endo. There are some attributes (such as the Endo ID) that are independent of attributes of the SVC (like its version). The current "Endo attributes" are really SVC attributes. Rename a few functions and variables to reflect that. Add a new attribute group for Endo-specific attributes, and populate it with the Endo ID. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/endo.c | 44 +++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/staging/greybus/endo.c b/drivers/staging/greybus/endo.c index e4faa5cedb70..72037fff2c31 100644 --- a/drivers/staging/greybus/endo.c +++ b/drivers/staging/greybus/endo.c @@ -44,35 +44,57 @@ (4 + ((endo_layout)->max_ribs + 1) * 2) /* endo sysfs attributes */ -static ssize_t serial_number_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t svc_serial_number_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gb_endo *endo = to_gb_endo(dev); return sprintf(buf, "%s", &endo->svc_info.serial_number[0]); } -static DEVICE_ATTR_RO(serial_number); +static DEVICE_ATTR_RO(svc_serial_number); -static ssize_t version_show(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t svc_version_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gb_endo *endo = to_gb_endo(dev); return sprintf(buf, "%s", &endo->svc_info.version[0]); } -static DEVICE_ATTR_RO(version); +static DEVICE_ATTR_RO(svc_version); -static struct attribute *endo_attrs[] = { - &dev_attr_serial_number.attr, - &dev_attr_version.attr, +static struct attribute *svc_attrs[] = { + &dev_attr_svc_serial_number.attr, + &dev_attr_svc_version.attr, NULL, }; -static const struct attribute_group endo_group = { - .attrs = endo_attrs, + +static const struct attribute_group svc_group = { + .attrs = svc_attrs, .name = "SVC", }; + +static ssize_t endo_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gb_endo *endo = to_gb_endo(dev); + + return sprintf(buf, "0x%04x", endo->id); +} +static DEVICE_ATTR_RO(endo_id); + +static struct attribute *endo_attrs[] = { + &dev_attr_endo_id.attr, + NULL, +}; + +static const struct attribute_group endo_group = { + .attrs = endo_attrs, + .name = "Endo", +}; + static const struct attribute_group *endo_groups[] = { &endo_group, + &svc_group, NULL, }; From 344943d2cdd85347637d0f3691c8c8bd34432247 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 12:56:48 -0500 Subject: [PATCH 21/25] greybus: endo: record AP interface id The AP resides in a particular position on an Endo, which is identified by an interface ID. (For now we'll assume the AP uses just one interface.) Record the this AP interface ID when creating an Endo. Add a sysfs attribute to display it as well. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/core.c | 5 +++-- drivers/staging/greybus/endo.c | 19 +++++++++++++++++-- drivers/staging/greybus/endo.h | 4 +++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index 7bfdbadb6250..223c396c9992 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -178,7 +178,8 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver { struct greybus_host_device *hd; struct gb_endo *endo; - u16 endo_id = 0x4755; // FIXME - get endo "ID" from the SVC + u16 endo_id = 0x4755; // FIXME - get endo "ID" from the SVC + u8 ap_intf_id = 0x01; // FIXME - get AP interface ID from the SVC /* * Validate that the driver implements all of the callbacks @@ -212,7 +213,7 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver ida_init(&hd->cport_id_map); hd->buffer_size_max = buffer_size_max; - endo = gb_endo_create(hd, endo_id); + endo = gb_endo_create(hd, endo_id, ap_intf_id); if (IS_ERR(endo)) { greybus_remove_hd(hd); return ERR_CAST(endo); diff --git a/drivers/staging/greybus/endo.c b/drivers/staging/greybus/endo.c index 72037fff2c31..7128a0478cd3 100644 --- a/drivers/staging/greybus/endo.c +++ b/drivers/staging/greybus/endo.c @@ -82,8 +82,18 @@ static ssize_t endo_id_show(struct device *dev, } static DEVICE_ATTR_RO(endo_id); +static ssize_t ap_intf_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gb_endo *endo = to_gb_endo(dev); + + return sprintf(buf, "0x%02x", endo->ap_intf_id); +} +static DEVICE_ATTR_RO(ap_intf_id); + static struct attribute *endo_attrs[] = { &dev_attr_endo_id.attr, + &dev_attr_ap_intf_id.attr, NULL, }; @@ -452,7 +462,8 @@ static int gb_endo_register(struct greybus_host_device *hd, return retval; } -struct gb_endo *gb_endo_create(struct greybus_host_device *hd, u16 endo_id) +struct gb_endo *gb_endo_create(struct greybus_host_device *hd, u16 endo_id, + u8 ap_intf_id) { struct gb_endo *endo; int retval; @@ -466,8 +477,12 @@ struct gb_endo *gb_endo_create(struct greybus_host_device *hd, u16 endo_id) retval = -EINVAL; goto free_endo; } - + if (ap_intf_id > max_endo_interface_id(&endo->layout)) { + retval = -EINVAL; + goto free_endo; + } endo->id = endo_id; + endo->ap_intf_id = ap_intf_id; /* Register Endo device */ retval = gb_endo_register(hd, endo); diff --git a/drivers/staging/greybus/endo.h b/drivers/staging/greybus/endo.h index c1ccbcd576f3..01ef5c86bf5a 100644 --- a/drivers/staging/greybus/endo.h +++ b/drivers/staging/greybus/endo.h @@ -40,6 +40,7 @@ struct gb_endo { struct endo_layout layout; struct gb_svc_info svc_info; u16 id; + u8 ap_intf_id; }; #define to_gb_endo(d) container_of(d, struct gb_endo, dev) @@ -47,7 +48,8 @@ struct gb_endo { /* Greybus "private" definitions */ struct greybus_host_device; -struct gb_endo *gb_endo_create(struct greybus_host_device *hd, u16 endo_id); +struct gb_endo *gb_endo_create(struct greybus_host_device *hd, + u16 endo_id, u8 ap_intf_id); void gb_endo_remove(struct gb_endo *endo); u8 endo_get_module_id(struct gb_endo *endo, u8 interface_id); From eb765e4e91c8614c11ef2c4af7ce1222a30d6b79 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 12:56:49 -0500 Subject: [PATCH 22/25] greybus: core: don't set up endo until host device is initialized Currently, the data structure representing an Endo is set up at the time a host device gets created. This is too early. Once the control infrastructure is in place, there's no sense in setting up the Endo utnil after we have heard from the SVC via a probe operation on our control CPort. And even then, there's no real point until we've successfully authenticated with the SVC, which will be indicated by the arrival of the Control protocol "connected" operation request notifying us that our SVC CPort is operational. In addition to this logical argument, we also can't actually receive any messages on the Control CPort until the host device is set up and ready to receive messages. At the point we're currently setting up the Endo data structure, that has not yet been done. Define a new exported function greybus_endo_setup(), which will be used (for now) as the entry point for setting up the Endo data structure. Arrange to call it in the host USB driver probe method, *after* we are set up for handling messages. Note: Once the control protocol has been implemented, this function may no longer need to be exported. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/core.c | 24 ++++++++++++++---------- drivers/staging/greybus/es1.c | 13 +++++++++++++ drivers/staging/greybus/es2.c | 13 +++++++++++++ drivers/staging/greybus/greybus.h | 2 ++ 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index 223c396c9992..290bee58511f 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -177,9 +177,6 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver size_t buffer_size_max) { struct greybus_host_device *hd; - struct gb_endo *endo; - u16 endo_id = 0x4755; // FIXME - get endo "ID" from the SVC - u8 ap_intf_id = 0x01; // FIXME - get AP interface ID from the SVC /* * Validate that the driver implements all of the callbacks @@ -213,17 +210,24 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver ida_init(&hd->cport_id_map); hd->buffer_size_max = buffer_size_max; - endo = gb_endo_create(hd, endo_id, ap_intf_id); - if (IS_ERR(endo)) { - greybus_remove_hd(hd); - return ERR_CAST(endo); - } - hd->endo = endo; - return hd; } EXPORT_SYMBOL_GPL(greybus_create_hd); +int greybus_endo_setup(struct greybus_host_device *hd, u16 endo_id, + u8 ap_intf_id) +{ + struct gb_endo *endo; + + endo = gb_endo_create(hd, endo_id, ap_intf_id); + if (IS_ERR(endo)) + return PTR_ERR(endo); + hd->endo = endo; + + return 0; +} +EXPORT_SYMBOL_GPL(greybus_endo_setup); + void greybus_remove_hd(struct greybus_host_device *hd) { /* diff --git a/drivers/staging/greybus/es1.c b/drivers/staging/greybus/es1.c index 1ed10f4b8e49..f6539549d27f 100644 --- a/drivers/staging/greybus/es1.c +++ b/drivers/staging/greybus/es1.c @@ -551,6 +551,8 @@ static int ap_probe(struct usb_interface *interface, bool bulk_out_found = false; int retval = -ENOMEM; int i; + u16 endo_id = 0x4755; // FIXME - get endo "ID" from the SVC + u8 ap_intf_id = 0x01; // FIXME - get endo "ID" from the SVC u8 svc_interval = 0; udev = usb_get_dev(interface_to_usbdev(interface)); @@ -659,6 +661,17 @@ static int ap_probe(struct usb_interface *interface, gb_debugfs_get(), es1, &apb1_log_enable_fops); + /* + * XXX Soon this will be initiated later, with a combination + * XXX of a Control protocol probe operation and a + * XXX subsequent Control protocol connected operation for + * XXX the SVC connection. At that point we know we're + * XXX properly connected to an Endo. + */ + retval = greybus_endo_setup(hd, endo_id, ap_intf_id); + if (retval) + goto error; + return 0; error: ap_disconnect(interface); diff --git a/drivers/staging/greybus/es2.c b/drivers/staging/greybus/es2.c index 4733adcb8a22..4f676cf3c583 100644 --- a/drivers/staging/greybus/es2.c +++ b/drivers/staging/greybus/es2.c @@ -551,6 +551,8 @@ static int ap_probe(struct usb_interface *interface, bool bulk_out_found = false; int retval = -ENOMEM; int i; + u16 endo_id = 0x4755; // FIXME - get endo "ID" from the SVC + u8 ap_intf_id = 0x01; // FIXME - get endo "ID" from the SVC u8 svc_interval = 0; udev = usb_get_dev(interface_to_usbdev(interface)); @@ -659,6 +661,17 @@ static int ap_probe(struct usb_interface *interface, gb_debugfs_get(), es1, &apb1_log_enable_fops); + /* + * XXX Soon this will be initiated later, with a combination + * XXX of a Control protocol probe operation and a + * XXX subsequent Control protocol connected operation for + * XXX the SVC connection. At that point we know we're + * XXX properly connected to an Endo. + */ + retval = greybus_endo_setup(hd, endo_id, ap_intf_id); + if (retval) + goto error; + return 0; error: ap_disconnect(interface); diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index 4920458d65d0..30a93eafe064 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -108,6 +108,8 @@ struct greybus_host_device { struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *hd, struct device *parent, size_t buffer_size_max); +int greybus_endo_setup(struct greybus_host_device *hd, u16 endo_id, + u8 ap_intf_id); void greybus_remove_hd(struct greybus_host_device *hd); struct greybus_driver { From 2de1a8b1a95ce36288b66a9b7c9f08ea82061b5f Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 12:59:15 -0500 Subject: [PATCH 23/25] greybus: add copyright statements The Greybus audio source files included no copyright statements. Add them. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio-dai.c | 9 +++++++++ drivers/staging/greybus/audio-gb-cmds.c | 9 +++++++++ drivers/staging/greybus/audio-pcm.c | 9 +++++++++ drivers/staging/greybus/audio.c | 9 +++++++++ drivers/staging/greybus/audio.h | 9 +++++++++ 5 files changed, 45 insertions(+) diff --git a/drivers/staging/greybus/audio-dai.c b/drivers/staging/greybus/audio-dai.c index 0dd7364785ae..9b162bfc2d17 100644 --- a/drivers/staging/greybus/audio-dai.c +++ b/drivers/staging/greybus/audio-dai.c @@ -1,3 +1,12 @@ +/* + * Greybus audio Digital Audio Interface (DAI) driver + * + * Copyright 2015 Google Inc. + * Copyright 2015 Linaro Ltd. + * + * Released under the GPLv2 only. + */ + #include #include #include diff --git a/drivers/staging/greybus/audio-gb-cmds.c b/drivers/staging/greybus/audio-gb-cmds.c index f6a29abca70f..9ca3164b1332 100644 --- a/drivers/staging/greybus/audio-gb-cmds.c +++ b/drivers/staging/greybus/audio-gb-cmds.c @@ -1,3 +1,12 @@ +/* + * Greybus audio commands + * + * Copyright 2015 Google Inc. + * Copyright 2015 Linaro Ltd. + * + * Released under the GPLv2 only. + */ + #include #include "greybus.h" diff --git a/drivers/staging/greybus/audio-pcm.c b/drivers/staging/greybus/audio-pcm.c index a1faf7895b58..c1b6aa551ce1 100644 --- a/drivers/staging/greybus/audio-pcm.c +++ b/drivers/staging/greybus/audio-pcm.c @@ -1,3 +1,12 @@ +/* + * Greybus audio Pulse Code Modulation (PCM) driver + * + * Copyright 2015 Google Inc. + * Copyright 2015 Linaro Ltd. + * + * Released under the GPLv2 only. + */ + #include #include #include diff --git a/drivers/staging/greybus/audio.c b/drivers/staging/greybus/audio.c index c873f339da1d..57c738b1293f 100644 --- a/drivers/staging/greybus/audio.c +++ b/drivers/staging/greybus/audio.c @@ -1,3 +1,12 @@ +/* + * Greybus audio driver + * + * Copyright 2015 Google Inc. + * Copyright 2015 Linaro Ltd. + * + * Released under the GPLv2 only. + */ + #include #include #include diff --git a/drivers/staging/greybus/audio.h b/drivers/staging/greybus/audio.h index c9087c9fc15c..da95c1b3cb1e 100644 --- a/drivers/staging/greybus/audio.h +++ b/drivers/staging/greybus/audio.h @@ -1,3 +1,12 @@ +/* + * Greybus audio + * + * Copyright 2015 Google Inc. + * Copyright 2015 Linaro Ltd. + * + * Released under the GPLv2 only. + */ + #ifndef __GB_AUDIO_H #define __GB_AUDIO_H #include From 4441f4759cfdf12840999676d2428a56f6248d8e Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 12:59:16 -0500 Subject: [PATCH 24/25] greybus: update copyrights Update the copyright statements for recently-modified source files. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/core.c | 4 ++-- drivers/staging/greybus/endo.c | 4 ++-- drivers/staging/greybus/endo.h | 1 + drivers/staging/greybus/es1.c | 6 +++--- drivers/staging/greybus/greybus.h | 4 ++-- drivers/staging/greybus/greybus_manifest.h | 4 ++-- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index 290bee58511f..6106175b57c5 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -1,8 +1,8 @@ /* * Greybus "Core" * - * Copyright 2014 Google Inc. - * Copyright 2014 Linaro Ltd. + * Copyright 2014-2015 Google Inc. + * Copyright 2014-2015 Linaro Ltd. * * Released under the GPLv2 only. */ diff --git a/drivers/staging/greybus/endo.c b/drivers/staging/greybus/endo.c index 7128a0478cd3..1e8485b07640 100644 --- a/drivers/staging/greybus/endo.c +++ b/drivers/staging/greybus/endo.c @@ -1,8 +1,8 @@ /* * Greybus endo code * - * Copyright 2015 Google Inc. - * Copyright 2014 Linaro Ltd. + * Copyright 2014-2015 Google Inc. + * Copyright 2014-2015 Linaro Ltd. * * Released under the GPLv2 only. */ diff --git a/drivers/staging/greybus/endo.h b/drivers/staging/greybus/endo.h index 01ef5c86bf5a..e211fb7d53bc 100644 --- a/drivers/staging/greybus/endo.h +++ b/drivers/staging/greybus/endo.h @@ -2,6 +2,7 @@ * Greybus endo code * * Copyright 2015 Google Inc. + * Copyright 2015 Linaro Ltd. * * Released under the GPLv2 only. */ diff --git a/drivers/staging/greybus/es1.c b/drivers/staging/greybus/es1.c index f6539549d27f..2acfe74fc7b7 100644 --- a/drivers/staging/greybus/es1.c +++ b/drivers/staging/greybus/es1.c @@ -1,8 +1,8 @@ /* - * Greybus "AP" USB driver + * Greybus "AP" USB driver for "ES1" controller chips * - * Copyright 2014 Google Inc. - * Copyright 2014 Linaro Ltd. + * Copyright 2014-2015 Google Inc. + * Copyright 2014-2015 Linaro Ltd. * * Released under the GPLv2 only. */ diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index 30a93eafe064..b9653f629a0a 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -1,8 +1,8 @@ /* * Greybus driver and device API * - * Copyright 2014 Google Inc. - * Copyright 2014 Linaro Ltd. + * Copyright 2014-2015 Google Inc. + * Copyright 2014-2015 Linaro Ltd. * * Released under the GPLv2 only. */ diff --git a/drivers/staging/greybus/greybus_manifest.h b/drivers/staging/greybus/greybus_manifest.h index 076d7114cb4e..de1b1dbefc55 100644 --- a/drivers/staging/greybus/greybus_manifest.h +++ b/drivers/staging/greybus/greybus_manifest.h @@ -4,8 +4,8 @@ * See "Greybus Application Protocol" document (version 0.1) for * details on these values and structures. * - * Copyright 2014 Google Inc. - * Copyright 2014 Linaro Ltd. + * Copyright 2014-2015 Google Inc. + * Copyright 2014-2015 Linaro Ltd. * * Released under the GPLv2 and BSD licenses. */ From 30c6d9d753724bc616ee1e2ca5cadc03747b8b07 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 22 May 2015 13:02:08 -0500 Subject: [PATCH 25/25] greybus: introduce SVC protocol This patch adds support for the Greybus SVC protocol. We may want to rearrange protocol numbers at some point, since this is a pretty fundamental protocol. Note: It has only been compile tested; no SVC CPorts have yet been defined, so this code is not yet exercised. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/Makefile | 2 + drivers/staging/greybus/greybus.h | 1 + drivers/staging/greybus/greybus_manifest.h | 1 + drivers/staging/greybus/greybus_protocols.h | 57 +++++ drivers/staging/greybus/svc.c | 256 ++++++++++++++++++++ drivers/staging/greybus/svc.h | 22 ++ 6 files changed, 339 insertions(+) create mode 100644 drivers/staging/greybus/svc.c create mode 100644 drivers/staging/greybus/svc.h diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile index e5cae29d5a32..42804547ba24 100644 --- a/drivers/staging/greybus/Makefile +++ b/drivers/staging/greybus/Makefile @@ -25,6 +25,7 @@ gb-phy-y := gpbridge.o \ audio-gb-cmds.o # Prefix all modules with gb- +gb-svc-y := svc.o gb-vibrator-y := vibrator.o gb-battery-y := battery.o gb-loopback-y := loopback.o @@ -33,6 +34,7 @@ gb-es1-y := es1.o gb-es2-y := es2.o obj-m += greybus.o +obj-m += gb-svc.o obj-m += gb-phy.o obj-m += gb-vibrator.o obj-m += gb-battery.o diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index b9653f629a0a..86b2f9c67d0b 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -26,6 +26,7 @@ #include "greybus_protocols.h" #include "manifest.h" #include "endo.h" +#include "svc.h" #include "module.h" #include "interface.h" #include "bundle.h" diff --git a/drivers/staging/greybus/greybus_manifest.h b/drivers/staging/greybus/greybus_manifest.h index de1b1dbefc55..d6175cec6c17 100644 --- a/drivers/staging/greybus/greybus_manifest.h +++ b/drivers/staging/greybus/greybus_manifest.h @@ -42,6 +42,7 @@ enum greybus_protocol { GREYBUS_PROTOCOL_LOOPBACK = 0x11, GREYBUS_PROTOCOL_I2S_RECEIVER = 0x12, GREYBUS_PROTOCOL_I2S_TRANSMITTER = 0x13, + GREYBUS_PROTOCOL_SVC = 0x14, /* ... */ GREYBUS_PROTOCOL_RAW = 0xfe, GREYBUS_PROTOCOL_VENDOR = 0xff, diff --git a/drivers/staging/greybus/greybus_protocols.h b/drivers/staging/greybus/greybus_protocols.h index c8208054d942..28c40a09a05b 100644 --- a/drivers/staging/greybus/greybus_protocols.h +++ b/drivers/staging/greybus/greybus_protocols.h @@ -489,4 +489,61 @@ struct gb_spi_transfer_response { __u8 data[0]; /* inbound data */ }; +/* Version of the Greybus SVC protocol we support */ +#define GB_SVC_VERSION_MAJOR 0x00 +#define GB_SVC_VERSION_MINOR 0x01 + +/* Greybus SVC request types */ +#define GB_SVC_TYPE_INVALID 0x00 +#define GB_SVC_TYPE_PROTOCOL_VERSION 0x01 +#define GB_SVC_TYPE_INTF_DEVICE_ID 0x02 +#define GB_SVC_TYPE_INTF_HOTPLUG 0x03 +#define GB_SVC_TYPE_INTF_HOT_UNPLUG 0x04 +#define GB_SVC_TYPE_INTF_RESET 0x05 +#define GB_SVC_TYPE_CONN_CREATE 0x06 +#define GB_SVC_TYPE_CONN_DESTROY 0x07 + +struct gb_svc_intf_device_id_request { + __u8 intf_id; + __u8 device_id; +}; +/* device id response has no payload */ + +struct gb_svc_intf_hotplug_request { + __u8 intf_id; + struct { + __le32 unipro_mfg_id; + __le32 unipro_prod_id; + __le32 ara_vend_id; + __le32 ara_prod_id; + } data; +}; +/* hotplug response has no payload */ + +struct gb_svc_intf_hot_unplug_request { + __u8 intf_id; +}; +/* hot unplug response has no payload */ + +struct gb_svc_intf_reset_request { + __u8 intf_id; +}; +/* interface reset response has no payload */ + +struct gb_svc_conn_create_request { + __u8 intf1_id; + __u16 cport1_id; + __u8 intf2_id; + __u16 cport2_id; +}; +/* connection create response has no payload */ + +struct gb_svc_conn_destroy_request { + __u8 intf1_id; + __u16 cport1_id; + __u8 intf2_id; + __u16 cport2_id; +}; +/* connection destroy response has no payload */ + #endif /* __GB_GPBRIDGE_H__ */ diff --git a/drivers/staging/greybus/svc.c b/drivers/staging/greybus/svc.c new file mode 100644 index 000000000000..e39eddbbcb9e --- /dev/null +++ b/drivers/staging/greybus/svc.c @@ -0,0 +1,256 @@ +/* + * SVC Greybus driver. + * + * Copyright 2015 Google Inc. + * Copyright 2015 Linaro Ltd. + * + * Released under the GPLv2 only. + */ + +#include +#include +#include + +#include "greybus.h" +#include "greybus_protocols.h" + +struct gb_svc { + struct gb_connection *connection; + u8 version_major; + u8 version_minor; +}; + +/* Define get_version() routine */ +define_get_version(gb_svc, SVC); + +static int intf_device_id_operation(struct gb_svc *svc, + u8 intf_id, u8 device_id) +{ + struct gb_svc_intf_device_id_request request; + + request.intf_id = intf_id; + request.device_id = device_id; + + return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_DEVICE_ID, + &request, sizeof(request), NULL, 0); +} + +static int intf_reset_operation(struct gb_svc *svc, u8 intf_id) +{ + struct gb_svc_intf_reset_request request; + + request.intf_id = intf_id; + + return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_RESET, + &request, sizeof(request), NULL, 0); +} + +static int connection_create_operation(struct gb_svc *svc, + u8 intf1_id, u16 cport1_id, + u8 intf2_id, u16 cport2_id) +{ + struct gb_svc_conn_create_request request; + + request.intf1_id = intf1_id; + request.cport1_id = cport1_id; + request.intf2_id = intf2_id; + request.cport2_id = cport2_id; + + return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_CREATE, + &request, sizeof(request), NULL, 0); +} + +static int connection_destroy_operation(struct gb_svc *svc, + u8 intf1_id, u16 cport1_id, + u8 intf2_id, u16 cport2_id) +{ + struct gb_svc_conn_destroy_request request; + + request.intf1_id = intf1_id; + request.cport1_id = cport1_id; + request.intf2_id = intf2_id; + request.cport2_id = cport2_id; + + return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_DESTROY, + &request, sizeof(request), NULL, 0); +} + +int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id) +{ + return intf_device_id_operation(svc, intf_id, device_id); +} +EXPORT_SYMBOL_GPL(gb_svc_intf_device_id); + +int gb_svc_intf_reset(struct gb_svc *svc, u8 intf_id) +{ + return intf_reset_operation(svc, intf_id); +} +EXPORT_SYMBOL_GPL(gb_svc_intf_reset); + +int gb_svc_connection_create(struct gb_svc *svc, + u8 intf1_id, u16 cport1_id, + u8 intf2_id, u16 cport2_id) +{ + return connection_create_operation(svc, intf1_id, cport1_id, + intf2_id, cport2_id); +} +EXPORT_SYMBOL_GPL(gb_svc_connection_create); + +int gb_svc_connection_destroy(struct gb_svc *svc, + u8 intf1_id, u16 cport1_id, + u8 intf2_id, u16 cport2_id) +{ + return connection_destroy_operation(svc, intf1_id, cport1_id, + intf2_id, cport2_id); +} +EXPORT_SYMBOL_GPL(gb_svc_connection_destroy); + +static int gb_svc_intf_hotplug_recv(struct gb_operation *op) +{ + struct gb_message *request = op->request; + struct gb_svc_intf_hotplug_request *hotplug; + u8 intf_id; + u32 unipro_mfg_id; + u32 unipro_prod_id; + u32 ara_vend_id; + u32 ara_prod_id; + + if (request->payload_size < sizeof(*hotplug)) { + dev_err(&op->connection->dev, + "short hotplug request received\n"); + return -EINVAL; + } + hotplug = request->payload; + + /* + * Grab the information we need. + * + * XXX I'd really like to acknowledge receipt, and then + * XXX continue processing the request. There's no need + * XXX for the SVC to wait. In fact, it might be best to + * XXX have the SVC get acknowledgement before we proceed. + * */ + intf_id = hotplug->intf_id; + unipro_mfg_id = hotplug->data.unipro_mfg_id; + unipro_prod_id = hotplug->data.unipro_prod_id; + ara_vend_id = hotplug->data.ara_vend_id; + ara_prod_id = hotplug->data.ara_prod_id; + + /* FIXME Set up the interface here; may required firmware download */ + + return 0; +} + +static int gb_svc_intf_hot_unplug_recv(struct gb_operation *op) +{ + struct gb_message *request = op->request; + struct gb_svc_intf_hot_unplug_request *hot_unplug; + u8 intf_id; + + if (request->payload_size < sizeof(*hot_unplug)) { + dev_err(&op->connection->dev, + "short hot unplug request received\n"); + return -EINVAL; + } + hot_unplug = request->payload; + + intf_id = hot_unplug->intf_id; + + /* FIXME Tear down the interface here */ + + return 0; + +} + +static int gb_svc_intf_reset_recv(struct gb_operation *op) +{ + struct gb_message *request = op->request; + struct gb_svc_intf_reset_request *reset; + u8 intf_id; + + if (request->payload_size < sizeof(*reset)) { + dev_err(&op->connection->dev, + "short reset request received\n"); + return -EINVAL; + } + reset = request->payload; + + intf_id = reset->intf_id; + + /* FIXME Reset the interface here */ + + return 0; +} + +static int gb_svc_request_recv(u8 type, struct gb_operation *op) +{ + switch (type) { + case GB_SVC_TYPE_INTF_HOTPLUG: + return gb_svc_intf_hotplug_recv(op); + case GB_SVC_TYPE_INTF_HOT_UNPLUG: + return gb_svc_intf_hot_unplug_recv(op); + case GB_SVC_TYPE_INTF_RESET: + return gb_svc_intf_reset_recv(op); + default: + dev_err(&op->connection->dev, + "unsupported request: %hhu\n", type); + return -EINVAL; + } +} + +/* + * Do initial setup of the SVC. + */ +static int gb_svc_device_setup(struct gb_svc *gb_svc) +{ + /* First thing we need to do is check the version */ + return get_version(gb_svc); +} + +static int gb_svc_connection_init(struct gb_connection *connection) +{ + struct gb_svc *svc; + int ret; + + svc = kzalloc(sizeof(*svc), GFP_KERNEL); + if (!svc) + return -ENOMEM; + + svc->connection = connection; + connection->private = svc; + ret = gb_svc_device_setup(svc); + if (ret) + kfree(svc); + + return ret; +} + +static void gb_svc_connection_exit(struct gb_connection *connection) +{ + struct gb_svc *svc = connection->private; + + if (!svc) + return; + + kfree(svc); +} + +static struct gb_protocol svc_protocol = { + .name = "svc", + .id = GREYBUS_PROTOCOL_SVC, + .major = 0, + .minor = 1, + .connection_init = gb_svc_connection_init, + .connection_exit = gb_svc_connection_exit, + .request_recv = gb_svc_request_recv, +}; + +int gb_svc_protocol_init(void) +{ + return gb_protocol_register(&svc_protocol); +} + +void gb_svc_protocol_exit(void) +{ + gb_protocol_deregister(&svc_protocol); +} diff --git a/drivers/staging/greybus/svc.h b/drivers/staging/greybus/svc.h new file mode 100644 index 000000000000..e26e63707e3d --- /dev/null +++ b/drivers/staging/greybus/svc.h @@ -0,0 +1,22 @@ +/* + * Greybus SVC code + * + * Copyright 2015 Google Inc. + * Copyright 2015 Linaro Ltd. + * + * Released under the GPLv2 only. + */ + +#ifndef __SVC_H +#define __SVC_H + +struct gb_svc; + +int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id); +int gb_svc_intf_reset(struct gb_svc *svc, u8 intf_id); +int gb_svc_connection_create(struct gb_svc *svc, u8 intf1_id, u16 cport1_id, + u8 intf2_id, u16 cport2_id); +int gb_svc_connection_destroy(struct gb_svc *svc, u8 intf1_id, u16 cport1_id, + u8 intf2_id, u16 cport2_id); + +#endif /* __SVC_H */