Loading drivers/staging/greybus/Makefile +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading drivers/staging/greybus/audio-dai.c +10 −1 Original line number Diff line number Diff line /* * 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> Loading @@ -11,8 +20,8 @@ #include <sound/soc.h> #include <sound/dmaengine_pcm.h> #include <sound/simple_card.h> #include "greybus.h" #include "gpbridge.h" #include "audio.h" /* Loading drivers/staging/greybus/audio-gb-cmds.c +62 −53 Original line number Diff line number Diff line /* * Greybus audio commands * * Copyright 2015 Google Inc. * Copyright 2015 Linaro Ltd. * * Released under the GPLv2 only. */ #include <linux/kernel.h> #include "greybus.h" #include "gpbridge.h" #include "audio.h" #define GB_I2S_MGMT_VERSION_MAJOR 0x00 Loading Loading @@ -89,21 +98,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])); Loading @@ -116,70 +116,79 @@ 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; } snd_dev->i2s_configs = get_cfg; return 0; err_free_get_cfg: kfree(get_cfg); return ret; } /* 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) && 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_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; } 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; 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) { 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; } ret = gb_i2s_mgmt_set_samples_per_message(connection, CONFIG_SAMPLES_PER_MSG); if (ret) { pr_err("set_samples_per_msg failed: %d\n", ret); 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) { pr_err("activate_cport failed: %d\n", ret); goto free_get_cfg; } free_get_cfg: kfree(get_cfg); return ret; } Loading drivers/staging/greybus/audio-pcm.c +47 −3 Original line number Diff line number Diff line /* * 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> Loading @@ -11,8 +20,8 @@ #include <sound/soc.h> #include <sound/dmaengine_pcm.h> #include <sound/simple_card.h> #include "greybus.h" #include "gpbridge.h" #include "audio.h" /* Loading @@ -32,15 +41,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, snd_dev->i2s_tx_connection->bundle_cport_id); 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, snd_dev->i2s_tx_connection->bundle_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; Loading Loading @@ -88,6 +115,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); } Loading @@ -96,6 +124,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) Loading Loading @@ -200,6 +229,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)); } Loading drivers/staging/greybus/audio.c +56 −15 Original line number Diff line number Diff line /* * 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 <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 "gpbridge.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 */ Loading Loading @@ -107,13 +118,17 @@ 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; sprintf(obj->codec_name, "rt5645.%s", "6-001b"); /* XXX do i2c bus addr dynamically */ 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; #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"); Loading Loading @@ -150,6 +165,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; Loading Loading @@ -212,6 +230,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: Loading @@ -231,6 +261,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); Loading Loading @@ -261,19 +295,30 @@ 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; } 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_deactivate_cport; goto err_free_i2s_configs; } return 0; err_deactivate_cport: gb_i2s_mgmt_deactivate_cport(connection, CONFIG_I2S_REMOTE_DATA_CPORT); err_free_i2s_configs: gb_i2s_mgmt_free_cfgs(snd_dev); err_free_snd_dev: gb_free_snd(snd_dev); return ret; Loading @@ -282,12 +327,8 @@ static int gb_i2s_mgmt_connection_init(struct gb_connection *connection) 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); gb_i2s_mgmt_free_cfgs(snd_dev); kfree(snd_dev->send_data_req_buf); snd_dev->send_data_req_buf = NULL; Loading Loading
drivers/staging/greybus/Makefile +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading
drivers/staging/greybus/audio-dai.c +10 −1 Original line number Diff line number Diff line /* * 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> Loading @@ -11,8 +20,8 @@ #include <sound/soc.h> #include <sound/dmaengine_pcm.h> #include <sound/simple_card.h> #include "greybus.h" #include "gpbridge.h" #include "audio.h" /* Loading
drivers/staging/greybus/audio-gb-cmds.c +62 −53 Original line number Diff line number Diff line /* * Greybus audio commands * * Copyright 2015 Google Inc. * Copyright 2015 Linaro Ltd. * * Released under the GPLv2 only. */ #include <linux/kernel.h> #include "greybus.h" #include "gpbridge.h" #include "audio.h" #define GB_I2S_MGMT_VERSION_MAJOR 0x00 Loading Loading @@ -89,21 +98,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])); Loading @@ -116,70 +116,79 @@ 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; } snd_dev->i2s_configs = get_cfg; return 0; err_free_get_cfg: kfree(get_cfg); return ret; } /* 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) && 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_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; } 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; 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) { 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; } ret = gb_i2s_mgmt_set_samples_per_message(connection, CONFIG_SAMPLES_PER_MSG); if (ret) { pr_err("set_samples_per_msg failed: %d\n", ret); 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) { pr_err("activate_cport failed: %d\n", ret); goto free_get_cfg; } free_get_cfg: kfree(get_cfg); return ret; } Loading
drivers/staging/greybus/audio-pcm.c +47 −3 Original line number Diff line number Diff line /* * 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> Loading @@ -11,8 +20,8 @@ #include <sound/soc.h> #include <sound/dmaengine_pcm.h> #include <sound/simple_card.h> #include "greybus.h" #include "gpbridge.h" #include "audio.h" /* Loading @@ -32,15 +41,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, snd_dev->i2s_tx_connection->bundle_cport_id); 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, snd_dev->i2s_tx_connection->bundle_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; Loading Loading @@ -88,6 +115,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); } Loading @@ -96,6 +124,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) Loading Loading @@ -200,6 +229,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)); } Loading
drivers/staging/greybus/audio.c +56 −15 Original line number Diff line number Diff line /* * 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 <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 "gpbridge.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 */ Loading Loading @@ -107,13 +118,17 @@ 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; sprintf(obj->codec_name, "rt5645.%s", "6-001b"); /* XXX do i2c bus addr dynamically */ 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; #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"); Loading Loading @@ -150,6 +165,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; Loading Loading @@ -212,6 +230,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: Loading @@ -231,6 +261,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); Loading Loading @@ -261,19 +295,30 @@ 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; } 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_deactivate_cport; goto err_free_i2s_configs; } return 0; err_deactivate_cport: gb_i2s_mgmt_deactivate_cport(connection, CONFIG_I2S_REMOTE_DATA_CPORT); err_free_i2s_configs: gb_i2s_mgmt_free_cfgs(snd_dev); err_free_snd_dev: gb_free_snd(snd_dev); return ret; Loading @@ -282,12 +327,8 @@ static int gb_i2s_mgmt_connection_init(struct gb_connection *connection) 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); gb_i2s_mgmt_free_cfgs(snd_dev); kfree(snd_dev->send_data_req_buf); snd_dev->send_data_req_buf = NULL; Loading