diff options
-rw-r--r-- | drivers/staging/greybus/Makefile | 6 | ||||
-rw-r--r-- | drivers/staging/greybus/audio-dai.c | 112 | ||||
-rw-r--r-- | drivers/staging/greybus/audio-gb-cmds.c | 188 | ||||
-rw-r--r-- | drivers/staging/greybus/audio-pcm.c | 308 | ||||
-rw-r--r-- | drivers/staging/greybus/audio.c | 470 | ||||
-rw-r--r-- | drivers/staging/greybus/audio.h | 113 | ||||
-rw-r--r-- | drivers/staging/greybus/gpbridge.c | 7 | ||||
-rw-r--r-- | drivers/staging/greybus/protocol.h | 3 |
8 files changed, 1 insertions, 1206 deletions
diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile index ba60430ef760..cf4cf2178ed6 100644 --- a/drivers/staging/greybus/Makefile +++ b/drivers/staging/greybus/Makefile @@ -21,11 +21,7 @@ gb-phy-y := gpbridge.o \ hid.o \ i2c.o \ spi.o \ - usb.o \ - audio.o \ - audio-pcm.o \ - audio-dai.o \ - audio-gb-cmds.o + usb.o # Prefix all modules with gb- gb-vibrator-y := vibrator.o diff --git a/drivers/staging/greybus/audio-dai.c b/drivers/staging/greybus/audio-dai.c deleted file mode 100644 index 9b162bfc2d17..000000000000 --- a/drivers/staging/greybus/audio-dai.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Greybus audio Digital Audio Interface (DAI) driver - * - * Copyright 2015 Google Inc. - * Copyright 2015 Linaro Ltd. - * - * Released under the GPLv2 only. - */ - -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/workqueue.h> -#include <linux/i2c.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/dmaengine_pcm.h> -#include <sound/simple_card.h> - -#include "greybus.h" -#include "audio.h" - -/* - * This is the greybus cpu dai logic. It really doesn't do much - * other then provide the TRIGGER_START/STOP hooks that start - * and stop the timer sending audio data in the pcm logic. - */ - - -static int gb_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct gb_snd *snd_dev; - - - snd_dev = snd_soc_dai_get_drvdata(rtd->cpu_dai); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - gb_pcm_hrtimer_start(snd_dev); - break; - case SNDRV_PCM_TRIGGER_STOP: - gb_pcm_hrtimer_stop(snd_dev); - break; - default: - return -EINVAL; - } - return 0; -} - -/* - * XXX This is annoying, if we don't have a set_fmt function - * the subsystem returns -ENOTSUPP, which causes applications - * to fail, so add a dummy function here. - */ -static int gb_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - return 0; -} - -static const struct snd_soc_dai_ops gb_dai_ops = { - .trigger = gb_dai_trigger, - .set_fmt = gb_dai_set_fmt, -}; - -static struct snd_soc_dai_driver gb_cpu_dai = { - .name = "gb-cpu-dai", - .playback = { - .rates = GB_RATES, - .formats = GB_FMTS, - .channels_min = 1, - .channels_max = 2, - }, - .ops = &gb_dai_ops, -}; - -static const struct snd_soc_component_driver gb_soc_component = { - .name = "gb-component", -}; - -static int gb_plat_probe(struct platform_device *pdev) -{ - struct gb_snd *snd_dev; - int ret; - - snd_dev = (struct gb_snd *)pdev->dev.platform_data; - dev_set_drvdata(&pdev->dev, snd_dev); - - ret = snd_soc_register_component(&pdev->dev, &gb_soc_component, - &gb_cpu_dai, 1); - return ret; -} - -static int gb_plat_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - snd_soc_unregister_platform(&pdev->dev); - return 0; -} - -struct platform_driver gb_audio_plat_driver = { - .driver = { - .name = "gb-dai-audio", - }, - .probe = gb_plat_probe, - .remove = gb_plat_remove, -}; diff --git a/drivers/staging/greybus/audio-gb-cmds.c b/drivers/staging/greybus/audio-gb-cmds.c deleted file mode 100644 index 112aed994fd2..000000000000 --- a/drivers/staging/greybus/audio-gb-cmds.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Greybus audio commands - * - * Copyright 2015 Google Inc. - * Copyright 2015 Linaro Ltd. - * - * Released under the GPLv2 only. - */ - -#include <linux/kernel.h> - -#include "greybus.h" -#include "audio.h" - -/*********************************** - * GB I2S helper functions - ***********************************/ -int gb_i2s_mgmt_activate_cport(struct gb_connection *connection, - uint16_t cport) -{ - struct gb_i2s_mgmt_activate_cport_request request; - - memset(&request, 0, sizeof(request)); - request.cport = cpu_to_le16(cport); - - return gb_operation_sync(connection, GB_I2S_MGMT_TYPE_ACTIVATE_CPORT, - &request, sizeof(request), NULL, 0); -} - -int gb_i2s_mgmt_deactivate_cport(struct gb_connection *connection, - uint16_t cport) -{ - struct gb_i2s_mgmt_deactivate_cport_request request; - - memset(&request, 0, sizeof(request)); - request.cport = cpu_to_le16(cport); - - return gb_operation_sync(connection, GB_I2S_MGMT_TYPE_DEACTIVATE_CPORT, - &request, sizeof(request), NULL, 0); -} - -int gb_i2s_mgmt_get_supported_configurations( - struct gb_connection *connection, - struct gb_i2s_mgmt_get_supported_configurations_response *get_cfg, - size_t size) -{ - return gb_operation_sync(connection, - GB_I2S_MGMT_TYPE_GET_SUPPORTED_CONFIGURATIONS, - NULL, 0, get_cfg, size); -} - -int gb_i2s_mgmt_set_configuration(struct gb_connection *connection, - struct gb_i2s_mgmt_set_configuration_request *set_cfg) -{ - return gb_operation_sync(connection, GB_I2S_MGMT_TYPE_SET_CONFIGURATION, - set_cfg, sizeof(*set_cfg), NULL, 0); -} - -int gb_i2s_mgmt_set_samples_per_message( - struct gb_connection *connection, - uint16_t samples_per_message) -{ - struct gb_i2s_mgmt_set_samples_per_message_request request; - - memset(&request, 0, sizeof(request)); - request.samples_per_message = cpu_to_le16(samples_per_message); - - return gb_operation_sync(connection, - GB_I2S_MGMT_TYPE_SET_SAMPLES_PER_MESSAGE, - &request, sizeof(request), NULL, 0); -} - -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; - size_t size; - int ret; - - size = sizeof(*get_cfg) + - (CONFIG_COUNT_MAX * sizeof(get_cfg->config[0])); - - get_cfg = kzalloc(size, GFP_KERNEL); - if (!get_cfg) - return -ENOMEM; - - ret = gb_i2s_mgmt_get_supported_configurations(connection, get_cfg, - size); - if (ret) { - pr_err("get_supported_config failed: %d\n", ret); - goto err_free_get_cfg; - } - - 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) && - (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_RISING) && - (cfg->ll_wclk_rx_edge & GB_I2S_MGMT_EDGE_FALLING) && - (cfg->ll_data_offset == 1)) - break; - } - - if (i >= CONFIG_COUNT_MAX) { - pr_err("No valid configuration\n"); - return -EINVAL; - } - - memcpy(&set_cfg, cfg, sizeof(set_cfg)); - 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; - 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_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(snd_dev->mgmt_connection, &set_cfg); - if (ret) - pr_err("set_configuration failed: %d\n", ret); - - return ret; -} - -int gb_i2s_send_data(struct gb_connection *connection, - void *req_buf, void *source_addr, - size_t len, int sample_num) -{ - struct gb_i2s_send_data_request *gb_req; - int ret; - - gb_req = req_buf; - gb_req->sample_number = cpu_to_le32(sample_num); - - memcpy((void *)&gb_req->data[0], source_addr, len); - - if (len < MAX_SEND_DATA_LEN) - for (; len < MAX_SEND_DATA_LEN; len++) - gb_req->data[len] = gb_req->data[len - SAMPLE_SIZE]; - - gb_req->size = cpu_to_le32(len); - - ret = gb_operation_sync(connection, GB_I2S_DATA_TYPE_SEND_DATA, - (void *) gb_req, SEND_DATA_BUF_LEN, NULL, 0); - return ret; -} diff --git a/drivers/staging/greybus/audio-pcm.c b/drivers/staging/greybus/audio-pcm.c deleted file mode 100644 index e62152a7be9e..000000000000 --- a/drivers/staging/greybus/audio-pcm.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Greybus audio Pulse Code Modulation (PCM) driver - * - * Copyright 2015 Google Inc. - * Copyright 2015 Linaro Ltd. - * - * Released under the GPLv2 only. - */ - -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/workqueue.h> -#include <linux/i2c.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/dmaengine_pcm.h> -#include <sound/simple_card.h> - -#include "greybus.h" -#include "audio.h" - -/* - * timer/workqueue logic for pushing pcm data. - * - * Since when we are playing audio, we don't get any - * status or feedback from the codec, we have to use a - * hrtimer to trigger sending data to the remote codec. - * However since the hrtimer runs in irq context, so we - * have to schedule a workqueue to actually send the - * greybus data. - */ - -static void gb_pcm_work(struct work_struct *work) -{ - struct gb_snd *snd_dev = container_of(work, struct gb_snd, work); - struct snd_pcm_substream *substream = snd_dev->substream; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int stride, frames, oldptr; - int period_elapsed, ret; - char *address; - long len; - - if (!snd_dev) - return; - - if (!atomic_read(&snd_dev->running)) { - if (snd_dev->cport_active) { - ret = gb_i2s_mgmt_deactivate_cport( - snd_dev->mgmt_connection, - snd_dev->i2s_tx_connection->intf_cport_id); - if (ret) /* XXX Do what else with failure? */ - pr_err("deactivate_cport failed: %d\n", ret); - - snd_dev->cport_active = false; - snd_dev->send_data_sample_count = 0; - } - - return; - } else if (!snd_dev->cport_active) { - ret = gb_i2s_mgmt_activate_cport(snd_dev->mgmt_connection, - snd_dev->i2s_tx_connection->intf_cport_id); - if (ret) - pr_err("activate_cport failed: %d\n", ret); - - snd_dev->cport_active = true; - } - - address = runtime->dma_area + snd_dev->hwptr_done; - - len = frames_to_bytes(runtime, - runtime->buffer_size) - snd_dev->hwptr_done; - len = min(len, MAX_SEND_DATA_LEN); - gb_i2s_send_data(snd_dev->i2s_tx_connection, snd_dev->send_data_req_buf, - address, len, snd_dev->send_data_sample_count); - - snd_dev->send_data_sample_count += CONFIG_SAMPLES_PER_MSG; - - stride = runtime->frame_bits >> 3; - frames = len/stride; - - snd_pcm_stream_lock(substream); - oldptr = snd_dev->hwptr_done; - snd_dev->hwptr_done += len; - if (snd_dev->hwptr_done >= runtime->buffer_size * stride) - snd_dev->hwptr_done -= runtime->buffer_size * stride; - - frames = (len + (oldptr % stride)) / stride; - - period_elapsed = 0; - snd_dev->transfer_done += frames; - if (snd_dev->transfer_done >= runtime->period_size) { - snd_dev->transfer_done -= runtime->period_size; - period_elapsed = 1; - } - - snd_pcm_stream_unlock(substream); - if (period_elapsed) - snd_pcm_period_elapsed(snd_dev->substream); -} - -static enum hrtimer_restart gb_pcm_timer_function(struct hrtimer *hrtimer) -{ - struct gb_snd *snd_dev = container_of(hrtimer, struct gb_snd, timer); - - if (!atomic_read(&snd_dev->running)) - return HRTIMER_NORESTART; - queue_work(snd_dev->workqueue, &snd_dev->work); - hrtimer_forward_now(hrtimer, ns_to_ktime(CONFIG_PERIOD_NS)); - return HRTIMER_RESTART; -} - -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); -} - -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) -{ - hrtimer_init(&snd_dev->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - snd_dev->timer.function = gb_pcm_timer_function; - atomic_set(&snd_dev->running, 0); - snd_dev->workqueue = alloc_workqueue("gb-audio", WQ_HIGHPRI, 0); - if (!snd_dev->workqueue) - return -ENOMEM; - INIT_WORK(&snd_dev->work, gb_pcm_work); - return 0; -} - - -/* - * Core gb pcm structure - */ -static struct snd_pcm_hardware gb_plat_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID, - .formats = GB_FMTS, - .rates = GB_RATES, - .rate_min = 8000, - .rate_max = GB_SAMPLE_RATE, - .channels_min = 1, - .channels_max = 2, - /* XXX - All the values below are junk */ - .buffer_bytes_max = 64 * 1024, - .period_bytes_min = 32, - .period_bytes_max = 8192, - .periods_min = 2, - .periods_max = 32, -}; - -static snd_pcm_uframes_t gb_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct gb_snd *snd_dev; - - snd_dev = snd_soc_dai_get_drvdata(rtd->cpu_dai); - - return snd_dev->hwptr_done / (substream->runtime->frame_bits >> 3); -} - -static int gb_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct gb_snd *snd_dev; - - snd_dev = snd_soc_dai_get_drvdata(rtd->cpu_dai); - snd_dev->hwptr_done = 0; - snd_dev->transfer_done = 0; - return 0; -} - -static unsigned int rates[] = {GB_SAMPLE_RATE}; -static struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static int gb_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct gb_snd *snd_dev; - unsigned long flags; - int ret; - - snd_dev = snd_soc_dai_get_drvdata(rtd->cpu_dai); - - spin_lock_irqsave(&snd_dev->lock, flags); - runtime->private_data = snd_dev; - snd_dev->substream = substream; - ret = gb_pcm_hrtimer_init(snd_dev); - spin_unlock_irqrestore(&snd_dev->lock, flags); - - if (ret) - return ret; - - snd_soc_set_runtime_hwparams(substream, &gb_plat_pcm_hardware); - - ret = snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_rates); - if (ret < 0) - return ret; - - return snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); -} - -static int gb_pcm_close(struct snd_pcm_substream *substream) -{ - substream->runtime->private_data = NULL; - return 0; -} - -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)); -} - -static int gb_pcm_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - -static struct snd_pcm_ops gb_pcm_ops = { - .open = gb_pcm_open, - .close = gb_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = gb_pcm_hw_params, - .hw_free = gb_pcm_hw_free, - .prepare = gb_pcm_prepare, - .pointer = gb_pcm_pointer, -}; - -static void gb_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - -static int gb_pcm_new(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_pcm *pcm = rtd->pcm; - - return snd_pcm_lib_preallocate_pages_for_all( - pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); -} - -static struct snd_soc_platform_driver gb_soc_platform = { - .ops = &gb_pcm_ops, - .pcm_new = gb_pcm_new, - .pcm_free = gb_pcm_free, -}; - -static int gb_soc_platform_probe(struct platform_device *pdev) -{ - return snd_soc_register_platform(&pdev->dev, &gb_soc_platform); -} - -static int gb_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; -} - -struct platform_driver gb_audio_pcm_driver = { - .driver = { - .name = "gb-pcm-audio", - .owner = THIS_MODULE, - }, - .probe = gb_soc_platform_probe, - .remove = gb_soc_platform_remove, -}; diff --git a/drivers/staging/greybus/audio.c b/drivers/staging/greybus/audio.c deleted file mode 100644 index 684229ccab6c..000000000000 --- a/drivers/staging/greybus/audio.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Greybus audio driver - * - * Copyright 2015 Google Inc. - * Copyright 2015 Linaro Ltd. - * - * Released under the GPLv2 only. - */ - -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/workqueue.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/dmaengine_pcm.h> -#include <sound/simple_card.h> - -#include "greybus.h" -#include "audio.h" - - -#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 - */ -static DEFINE_SPINLOCK(gb_snd_list_lock); -static LIST_HEAD(gb_snd_list); -static int device_count; - -static struct gb_snd *gb_find_snd(int bundle_id) -{ - struct gb_snd *tmp, *ret = NULL; - unsigned long flags; - - spin_lock_irqsave(&gb_snd_list_lock, flags); - list_for_each_entry(tmp, &gb_snd_list, list) - if (tmp->gb_bundle_id == bundle_id) { - ret = tmp; - break; - } - spin_unlock_irqrestore(&gb_snd_list_lock, flags); - return ret; -} - -static struct gb_snd *gb_get_snd(int bundle_id) -{ - struct gb_snd *snd_dev; - unsigned long flags; - - snd_dev = gb_find_snd(bundle_id); - if (snd_dev) - return snd_dev; - - snd_dev = kzalloc(sizeof(*snd_dev), GFP_KERNEL); - if (!snd_dev) - return NULL; - - spin_lock_init(&snd_dev->lock); - snd_dev->device_count = device_count++; - snd_dev->gb_bundle_id = bundle_id; - spin_lock_irqsave(&gb_snd_list_lock, flags); - list_add(&snd_dev->list, &gb_snd_list); - spin_unlock_irqrestore(&gb_snd_list_lock, flags); - return snd_dev; -} - -static void gb_free_snd(struct gb_snd *snd) -{ - unsigned long flags; - - spin_lock_irqsave(&gb_snd_list_lock, flags); - if (!snd->i2s_tx_connection && - !snd->mgmt_connection) { - list_del(&snd->list); - spin_unlock_irqrestore(&gb_snd_list_lock, flags); - kfree(snd); - } else { - spin_unlock_irqrestore(&gb_snd_list_lock, flags); - } -} - - - - -/* - * This is the ASoC simple card binds the platform codec, - * cpu-dai and codec-dai togheter - */ -struct gb_card_info_object { - struct asoc_simple_card_info card_info; - char codec_name[255]; - char platform_name[255]; - char dai_name[255]; -}; - - -static struct asoc_simple_card_info *setup_card_info(int device_count) -{ - struct gb_card_info_object *obj; - - obj = kzalloc(sizeof(struct gb_card_info_object), GFP_KERNEL); - if (!obj) - return NULL; - - obj->card_info.name = "Greybus Audio Module"; - obj->card_info.card = "gb-card"; - obj->card_info.codec = obj->codec_name; - 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 = SND_SOC_DAIFMT_CBM_CFM; -#endif -#if USE_RT5645 - 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"; -#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"); - obj->card_info.codec_dai.name = "dit-hifi"; -#endif - sprintf(obj->platform_name, "gb-pcm-audio.%i", device_count); - sprintf(obj->dai_name, "gb-dai-audio.%i", device_count); - - return &obj->card_info; -} - -static void free_card_info(struct asoc_simple_card_info *ci) -{ - struct gb_card_info_object *obj; - - obj = container_of(ci, struct gb_card_info_object, card_info); - kfree(obj); -} - - -/* - * XXX this is sort of cruddy but I get warnings if - * we don't have dev.release handler set. - */ -static void default_release(struct device *dev) -{ -} - -/* - * GB connection hooks - */ -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; - struct i2c_adapter *i2c_adap; -#endif - unsigned long flags; - int ret; - - snd_dev = gb_get_snd(connection->bundle->id); - if (!snd_dev) - return -ENOMEM; - - codec = platform_device_register_simple("spdif-dit", -1, NULL, 0); - if (!codec) { - ret = -ENOMEM; - goto out; - } - - dai = platform_device_register_simple("gb-pcm-audio", snd_dev->device_count, NULL, 0); - if (!dai) { - ret = -ENOMEM; - goto out; - } - - simple_card = setup_card_info(snd_dev->device_count); - if (!simple_card) { - ret = -ENOMEM; - goto out; - } - - spin_lock_irqsave(&snd_dev->lock, flags); - snd_dev->card.name = "asoc-simple-card"; - snd_dev->card.id = snd_dev->device_count; - snd_dev->card.dev.release = default_release; /* XXX - suspicious */ - - snd_dev->cpu_dai.name = "gb-dai-audio"; - snd_dev->cpu_dai.id = snd_dev->device_count; - snd_dev->cpu_dai.dev.release = default_release; /* XXX - suspicious */ - - - snd_dev->simple_card_info = simple_card; - snd_dev->card.dev.platform_data = simple_card; - - snd_dev->codec = codec; - snd_dev->i2s_tx_connection = connection; - snd_dev->cpu_dai.dev.platform_data = snd_dev; - snd_dev->i2s_tx_connection->private = snd_dev; - spin_unlock_irqrestore(&snd_dev->lock, flags); - - ret = platform_device_register(&snd_dev->cpu_dai); - if (ret) { - pr_err("cpu_dai platform_device register failed\n"); - goto out_dai; - } - - ret = platform_device_register(&snd_dev->card); - if (ret) { - pr_err("card platform_device register failed\n"); - goto out_card; - } - -#if USE_RT5645 - rt5647_info.addr = RT5647_I2C_ADDR; - strlcpy(rt5647_info.type, "rt5647", I2C_NAME_SIZE); - - i2c_adap = i2c_get_adapter(RT5647_I2C_ADAPTER_NR); - if (!i2c_adap) { - pr_err("codec unavailable\n"); - ret = -ENODEV; - goto out_get_ver; - } - - snd_dev->rt5647 = i2c_new_device(i2c_adap, &rt5647_info); - if (!snd_dev->rt5647) { - pr_err("can't create rt5647 i2c device\n"); - goto out_get_ver; - } -#endif - - return 0; - -#if USE_RT5645 -out_get_ver: - platform_device_unregister(&snd_dev->card); -#endif -out_card: - platform_device_unregister(&snd_dev->cpu_dai); -out_dai: - platform_device_unregister(codec); -out: - gb_free_snd(snd_dev); - return ret; -} - -static void gb_i2s_transmitter_connection_exit(struct gb_connection *connection) -{ - struct gb_snd *snd_dev; - - 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); - - free_card_info(snd_dev->simple_card_info); - snd_dev->i2s_tx_connection = NULL; - gb_free_snd(snd_dev); -} - -static int gb_i2s_mgmt_connection_init(struct gb_connection *connection) -{ - struct gb_snd *snd_dev; - unsigned long flags; - int ret; - - snd_dev = gb_get_snd(connection->bundle->id); - if (!snd_dev) - return -ENOMEM; - - spin_lock_irqsave(&snd_dev->lock, flags); - snd_dev->mgmt_connection = connection; - connection->private = snd_dev; - spin_unlock_irqrestore(&snd_dev->lock, flags); - - 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; - } - - 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) { - ret = -ENOMEM; - 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; -} - -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; - - snd_dev->mgmt_connection = NULL; - gb_free_snd(snd_dev); -} - -static int gb_i2s_mgmt_report_event_recv(u8 type, struct gb_operation *op) -{ - struct gb_connection *connection = op->connection; - struct gb_i2s_mgmt_report_event_request *req = op->request->payload; - char *event_name; - - if (type != GB_I2S_MGMT_TYPE_REPORT_EVENT) { - dev_err(&connection->bundle->dev, "Invalid request type: %d\n", - type); - return -EINVAL; - } - - if (op->request->payload_size < sizeof(*req)) { - dev_err(&connection->bundle->dev, - "Short request received (%zu < %zu)\n", - op->request->payload_size, sizeof(*req)); - return -EINVAL; - } - - switch (req->event) { - case GB_I2S_MGMT_EVENT_UNSPECIFIED: - event_name = "UNSPECIFIED"; - break; - case GB_I2S_MGMT_EVENT_HALT: - /* XXX Should stop streaming now */ - event_name = "HALT"; - break; - case GB_I2S_MGMT_EVENT_INTERNAL_ERROR: - event_name = "INTERNAL_ERROR"; - break; - case GB_I2S_MGMT_EVENT_PROTOCOL_ERROR: - event_name = "PROTOCOL_ERROR"; - break; - case GB_I2S_MGMT_EVENT_FAILURE: - event_name = "FAILURE"; - break; - case GB_I2S_MGMT_EVENT_OUT_OF_SEQUENCE: - event_name = "OUT_OF_SEQUENCE"; - break; - case GB_I2S_MGMT_EVENT_UNDERRUN: - event_name = "UNDERRUN"; - break; - case GB_I2S_MGMT_EVENT_OVERRUN: - event_name = "OVERRUN"; - break; - case GB_I2S_MGMT_EVENT_CLOCKING: - event_name = "CLOCKING"; - break; - case GB_I2S_MGMT_EVENT_DATA_LEN: - event_name = "DATA_LEN"; - break; - default: - dev_warn(&connection->bundle->dev, - "Unknown I2S Event received: %d\n", req->event); - return -EINVAL; - } - - dev_warn(&connection->bundle->dev, "I2S Event received: %d - '%s'\n", - req->event, event_name); - - return 0; -} - -static struct gb_protocol gb_i2s_receiver_protocol = { - .name = GB_AUDIO_DATA_DRIVER_NAME, - .id = GREYBUS_PROTOCOL_I2S_RECEIVER, - .major = 0, - .minor = 1, - .connection_init = gb_i2s_transmitter_connection_init, - .connection_exit = gb_i2s_transmitter_connection_exit, - .request_recv = NULL, -}; - -static struct gb_protocol gb_i2s_mgmt_protocol = { - .name = GB_AUDIO_MGMT_DRIVER_NAME, - .id = GREYBUS_PROTOCOL_I2S_MGMT, - .major = 0, - .minor = 1, - .connection_init = gb_i2s_mgmt_connection_init, - .connection_exit = gb_i2s_mgmt_connection_exit, - .request_recv = gb_i2s_mgmt_report_event_recv, -}; - - -/* - * This is the basic hook get things initialized and registered w/ gb - */ - -int gb_audio_protocol_init(void) -{ - int err; - - err = gb_protocol_register(&gb_i2s_mgmt_protocol); - if (err) { - pr_err("Can't register i2s mgmt protocol driver: %d\n", -err); - return err; - } - - err = gb_protocol_register(&gb_i2s_receiver_protocol); - if (err) { - pr_err("Can't register Audio protocol driver: %d\n", -err); - goto err_unregister_i2s_mgmt; - } - - err = platform_driver_register(&gb_audio_plat_driver); - if (err) { - pr_err("Can't register platform driver: %d\n", -err); - goto err_unregister_plat; - } - - err = platform_driver_register(&gb_audio_pcm_driver); - if (err) { - pr_err("Can't register pcm driver: %d\n", -err); - goto err_unregister_pcm; - } - - return 0; - -err_unregister_pcm: - platform_driver_unregister(&gb_audio_plat_driver); -err_unregister_plat: - gb_protocol_deregister(&gb_i2s_receiver_protocol); -err_unregister_i2s_mgmt: - gb_protocol_deregister(&gb_i2s_mgmt_protocol); - return err; -} - -void gb_audio_protocol_exit(void) -{ - platform_driver_unregister(&gb_audio_pcm_driver); - platform_driver_unregister(&gb_audio_plat_driver); - gb_protocol_deregister(&gb_i2s_receiver_protocol); - gb_protocol_deregister(&gb_i2s_mgmt_protocol); -} diff --git a/drivers/staging/greybus/audio.h b/drivers/staging/greybus/audio.h deleted file mode 100644 index e4975930f29a..000000000000 --- a/drivers/staging/greybus/audio.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Greybus audio - * - * Copyright 2015 Google Inc. - * Copyright 2015 Linaro Ltd. - * - * Released under the GPLv2 only. - */ - -#ifndef __GB_AUDIO_H -#define __GB_AUDIO_H -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/platform_device.h> -#include <sound/soc.h> - -#include "greybus.h" - -#define GB_SAMPLE_RATE 48000 -#define GB_RATES SNDRV_PCM_RATE_48000 -#define GB_FMTS SNDRV_PCM_FMTBIT_S16_LE -#define PREALLOC_BUFFER (32 * 1024) -#define PREALLOC_BUFFER_MAX (32 * 1024) - -/* assuming 1 ms samples @ 48KHz */ -#define CONFIG_SAMPLES_PER_MSG 48L -#define CONFIG_PERIOD_NS 1000000 /* send msg every 1ms */ - -#define CONFIG_COUNT_MAX 20 - -/* Switch between dummy spdif and jetson rt5645 codec */ -#define USE_RT5645 0 - -#define SAMPLE_SIZE 4 -#define MAX_SEND_DATA_LEN (CONFIG_SAMPLES_PER_MSG * SAMPLE_SIZE) -#define SEND_DATA_BUF_LEN (sizeof(struct gb_i2s_send_data_request) + \ - MAX_SEND_DATA_LEN) - - -/* - * This is the gb_snd structure which ties everything together - * and fakes DMA interrupts via a timer. - */ -struct gb_snd { - struct platform_device card; - 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; - struct gb_i2s_mgmt_get_supported_configurations_response - *i2s_configs; - char *send_data_req_buf; - long send_data_sample_count; - int gb_bundle_id; - int device_count; - 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; - int transfer_done; - struct list_head list; - spinlock_t lock; -}; - - -/* - * GB I2S cmd functions - */ -int gb_i2s_mgmt_activate_cport(struct gb_connection *connection, - uint16_t cport); -int gb_i2s_mgmt_deactivate_cport(struct gb_connection *connection, - uint16_t cport); -int gb_i2s_mgmt_get_supported_configurations( - struct gb_connection *connection, - struct gb_i2s_mgmt_get_supported_configurations_response *get_cfg, - size_t size); -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_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); - - -/* - * GB PCM hooks - */ -void gb_pcm_hrtimer_start(struct gb_snd *snd_dev); -void gb_pcm_hrtimer_stop(struct gb_snd *snd_dev); - - -/* - * Platform drivers - */ -extern struct platform_driver gb_audio_pcm_driver; -extern struct platform_driver gb_audio_plat_driver; - - -#endif /* __GB_AUDIO_H */ diff --git a/drivers/staging/greybus/gpbridge.c b/drivers/staging/greybus/gpbridge.c index 2324270e5c55..404684a3c516 100644 --- a/drivers/staging/greybus/gpbridge.c +++ b/drivers/staging/greybus/gpbridge.c @@ -53,15 +53,9 @@ static int __init gpbridge_init(void) pr_err("error initializing hid protocol\n"); goto error_hid; } - if (gb_audio_protocol_init()) { - pr_err("error initializing audio protocols\n"); - goto error_audio; - } return 0; -error_audio: - gb_hid_protocol_exit(); error_hid: gb_spi_protocol_exit(); error_spi: @@ -83,7 +77,6 @@ module_init(gpbridge_init); static void __exit gpbridge_exit(void) { - gb_audio_protocol_exit(); gb_hid_protocol_exit(); gb_spi_protocol_exit(); gb_i2c_protocol_exit(); diff --git a/drivers/staging/greybus/protocol.h b/drivers/staging/greybus/protocol.h index 2e0f4d667897..ad9f543206a6 100644 --- a/drivers/staging/greybus/protocol.h +++ b/drivers/staging/greybus/protocol.h @@ -85,9 +85,6 @@ extern void gb_spi_protocol_exit(void); extern int gb_hid_protocol_init(void); extern void gb_hid_protocol_exit(void); -extern int gb_audio_protocol_init(void); -extern void gb_audio_protocol_exit(void); - /* __protocol: Pointer to struct gb_protocol */ #define gb_protocol_driver(__protocol) \ static int __init protocol_init(void) \ |