blob: 9ca3164b13323674eb814d6e4fa5a1a0b1969b0a [file] [log] [blame]
Alex Elder2de1a8b2015-05-22 12:59:15 -05001/*
2 * Greybus audio commands
3 *
4 * Copyright 2015 Google Inc.
5 * Copyright 2015 Linaro Ltd.
6 *
7 * Released under the GPLv2 only.
8 */
9
John Stultza4749bb2015-05-08 12:57:36 -070010#include <linux/kernel.h>
Alex Eldere9385e52015-05-22 12:35:31 -050011
John Stultza4749bb2015-05-08 12:57:36 -070012#include "greybus.h"
John Stultza4749bb2015-05-08 12:57:36 -070013#include "audio.h"
14
15#define GB_I2S_MGMT_VERSION_MAJOR 0x00
16#define GB_I2S_MGMT_VERSION_MINOR 0x01
17
18#define GB_I2S_DATA_VERSION_MAJOR 0x00
19#define GB_I2S_MGMT_VERSION_MINOR 0x01
20
21/***********************************
22 * GB I2S helper functions
23 ***********************************/
24int gb_i2s_mgmt_get_version(struct gb_connection *connection)
25{
26 struct gb_protocol_version_response response;
27
28 memset(&response, 0, sizeof(response));
29 return gb_protocol_get_version(connection,
30 GB_I2S_MGMT_TYPE_PROTOCOL_VERSION,
31 NULL, 0, &response,
32 GB_I2S_MGMT_VERSION_MAJOR);
33}
34
35int gb_i2s_data_get_version(struct gb_connection *connection)
36{
37 struct gb_protocol_version_response response;
38
39 memset(&response, 0, sizeof(response));
40 return gb_protocol_get_version(connection,
41 GB_I2S_DATA_TYPE_PROTOCOL_VERSION,
42 NULL, 0, &response,
43 GB_I2S_DATA_VERSION_MAJOR);
44}
45
46int gb_i2s_mgmt_activate_cport(struct gb_connection *connection,
47 uint16_t cport)
48{
49 struct gb_i2s_mgmt_activate_cport_request request;
50
51 memset(&request, 0, sizeof(request));
Greg Kroah-Hartman64a54802015-05-11 14:09:32 -070052 request.cport = cpu_to_le16(cport);
John Stultza4749bb2015-05-08 12:57:36 -070053
54 return gb_operation_sync(connection, GB_I2S_MGMT_TYPE_ACTIVATE_CPORT,
55 &request, sizeof(request), NULL, 0);
56}
57
58int gb_i2s_mgmt_deactivate_cport(struct gb_connection *connection,
59 uint16_t cport)
60{
61 struct gb_i2s_mgmt_deactivate_cport_request request;
62
63 memset(&request, 0, sizeof(request));
Greg Kroah-Hartman64a54802015-05-11 14:09:32 -070064 request.cport = cpu_to_le16(cport);
John Stultza4749bb2015-05-08 12:57:36 -070065
66 return gb_operation_sync(connection, GB_I2S_MGMT_TYPE_DEACTIVATE_CPORT,
67 &request, sizeof(request), NULL, 0);
68}
69
70int gb_i2s_mgmt_get_supported_configurations(
71 struct gb_connection *connection,
72 struct gb_i2s_mgmt_get_supported_configurations_response *get_cfg,
73 size_t size)
74{
75 return gb_operation_sync(connection,
76 GB_I2S_MGMT_TYPE_GET_SUPPORTED_CONFIGURATIONS,
77 NULL, 0, get_cfg, size);
78}
79
80int gb_i2s_mgmt_set_configuration(struct gb_connection *connection,
81 struct gb_i2s_mgmt_set_configuration_request *set_cfg)
82{
83 return gb_operation_sync(connection, GB_I2S_MGMT_TYPE_SET_CONFIGURATION,
84 set_cfg, sizeof(*set_cfg), NULL, 0);
85}
86
87int gb_i2s_mgmt_set_samples_per_message(
88 struct gb_connection *connection,
89 uint16_t samples_per_message)
90{
91 struct gb_i2s_mgmt_set_samples_per_message_request request;
92
93 memset(&request, 0, sizeof(request));
Greg Kroah-Hartman64a54802015-05-11 14:09:32 -070094 request.samples_per_message = cpu_to_le16(samples_per_message);
John Stultza4749bb2015-05-08 12:57:36 -070095
96 return gb_operation_sync(connection,
97 GB_I2S_MGMT_TYPE_SET_SAMPLES_PER_MESSAGE,
98 &request, sizeof(request), NULL, 0);
99}
100
Mark A. Greer6b340992015-05-21 15:57:03 -0700101int gb_i2s_mgmt_get_cfgs(struct gb_snd *snd_dev,
102 struct gb_connection *connection)
John Stultza4749bb2015-05-08 12:57:36 -0700103{
104 struct gb_i2s_mgmt_get_supported_configurations_response *get_cfg;
John Stultza4749bb2015-05-08 12:57:36 -0700105 size_t size;
Mark A. Greer6b340992015-05-21 15:57:03 -0700106 int ret;
John Stultza4749bb2015-05-08 12:57:36 -0700107
108 size = sizeof(*get_cfg) +
109 (CONFIG_COUNT_MAX * sizeof(get_cfg->config[0]));
110
111 get_cfg = kzalloc(size, GFP_KERNEL);
112 if (!get_cfg)
113 return -ENOMEM;
114
115 ret = gb_i2s_mgmt_get_supported_configurations(connection, get_cfg,
116 size);
117 if (ret) {
118 pr_err("get_supported_config failed: %d\n", ret);
Mark A. Greer6b340992015-05-21 15:57:03 -0700119 goto err_free_get_cfg;
John Stultza4749bb2015-05-08 12:57:36 -0700120 }
121
Mark A. Greer6b340992015-05-21 15:57:03 -0700122 snd_dev->i2s_configs = get_cfg;
123
124 return 0;
125
126err_free_get_cfg:
127 kfree(get_cfg);
128 return ret;
129}
130
131void gb_i2s_mgmt_free_cfgs(struct gb_snd *snd_dev)
132{
133 kfree(snd_dev->i2s_configs);
134 snd_dev->i2s_configs = NULL;
135}
136
137int gb_i2s_mgmt_set_cfg(struct gb_snd *snd_dev, int rate, int chans,
138 int bytes_per_chan, int is_le)
139{
140 struct gb_i2s_mgmt_set_configuration_request set_cfg;
141 struct gb_i2s_mgmt_configuration *cfg;
142 int i, ret;
143 u8 byte_order = GB_I2S_MGMT_BYTE_ORDER_NA;
144
145 if (bytes_per_chan > 1) {
146 if (is_le)
147 byte_order = GB_I2S_MGMT_BYTE_ORDER_LE;
148 else
149 byte_order = GB_I2S_MGMT_BYTE_ORDER_BE;
150 }
151
152 for (i = 0, cfg = snd_dev->i2s_configs->config;
153 i < CONFIG_COUNT_MAX;
154 i++, cfg++) {
155 if ((cfg->sample_frequency == cpu_to_le32(rate)) &&
156 (cfg->num_channels == chans) &&
157 (cfg->bytes_per_channel == bytes_per_chan) &&
158 (cfg->byte_order & byte_order) &&
159 (cfg->ll_protocol &
160 cpu_to_le32(GB_I2S_MGMT_PROTOCOL_I2S)) &&
John Stultza4749bb2015-05-08 12:57:36 -0700161 (cfg->ll_mclk_role & GB_I2S_MGMT_ROLE_MASTER) &&
162 (cfg->ll_bclk_role & GB_I2S_MGMT_ROLE_MASTER) &&
163 (cfg->ll_wclk_role & GB_I2S_MGMT_ROLE_MASTER) &&
164 (cfg->ll_wclk_polarity & GB_I2S_MGMT_POLARITY_NORMAL) &&
165 (cfg->ll_wclk_change_edge & GB_I2S_MGMT_EDGE_FALLING) &&
Mark A. Greer0e995aa2015-05-21 15:54:27 -0700166 (cfg->ll_wclk_tx_edge & GB_I2S_MGMT_EDGE_RISING) &&
167 (cfg->ll_wclk_rx_edge & GB_I2S_MGMT_EDGE_FALLING) &&
John Stultza4749bb2015-05-08 12:57:36 -0700168 (cfg->ll_data_offset == 1))
169 break;
170 }
171
172 if (i >= CONFIG_COUNT_MAX) {
173 pr_err("No valid configuration\n");
Mark A. Greer6b340992015-05-21 15:57:03 -0700174 return -EINVAL;
John Stultza4749bb2015-05-08 12:57:36 -0700175 }
176
177 memcpy(&set_cfg, cfg, sizeof(set_cfg));
Mark A. Greer6b340992015-05-21 15:57:03 -0700178 set_cfg.config.byte_order = byte_order;
Greg Kroah-Hartman64a54802015-05-11 14:09:32 -0700179 set_cfg.config.ll_protocol = cpu_to_le32(GB_I2S_MGMT_PROTOCOL_I2S);
John Stultza4749bb2015-05-08 12:57:36 -0700180 set_cfg.config.ll_mclk_role = GB_I2S_MGMT_ROLE_MASTER;
181 set_cfg.config.ll_bclk_role = GB_I2S_MGMT_ROLE_MASTER;
182 set_cfg.config.ll_wclk_role = GB_I2S_MGMT_ROLE_MASTER;
183 set_cfg.config.ll_wclk_polarity = GB_I2S_MGMT_POLARITY_NORMAL;
Mark A. Greer0e995aa2015-05-21 15:54:27 -0700184 set_cfg.config.ll_wclk_change_edge = GB_I2S_MGMT_EDGE_FALLING;
185 set_cfg.config.ll_wclk_tx_edge = GB_I2S_MGMT_EDGE_RISING;
186 set_cfg.config.ll_wclk_rx_edge = GB_I2S_MGMT_EDGE_FALLING;
John Stultza4749bb2015-05-08 12:57:36 -0700187
Mark A. Greer6b340992015-05-21 15:57:03 -0700188 ret = gb_i2s_mgmt_set_configuration(snd_dev->mgmt_connection, &set_cfg);
Mark A. Greerf9a4fee2015-05-21 15:57:01 -0700189 if (ret)
Mark A. Greer0d17e0c2015-05-21 15:57:04 -0700190 pr_err("set_configuration failed: %d\n", ret);
John Stultza4749bb2015-05-08 12:57:36 -0700191
John Stultza4749bb2015-05-08 12:57:36 -0700192 return ret;
193}
194
195int gb_i2s_send_data(struct gb_connection *connection,
196 void *req_buf, void *source_addr,
197 size_t len, int sample_num)
198{
199 struct gb_i2s_send_data_request *gb_req;
200 int ret;
201
202 gb_req = req_buf;
Greg Kroah-Hartman64a54802015-05-11 14:09:32 -0700203 gb_req->sample_number = cpu_to_le32(sample_num);
John Stultza4749bb2015-05-08 12:57:36 -0700204
205 memcpy((void *)&gb_req->data[0], source_addr, len);
206
207 if (len < MAX_SEND_DATA_LEN)
208 for (; len < MAX_SEND_DATA_LEN; len++)
209 gb_req->data[len] = gb_req->data[len - SAMPLE_SIZE];
210
Greg Kroah-Hartman64a54802015-05-11 14:09:32 -0700211 gb_req->size = cpu_to_le32(len);
John Stultza4749bb2015-05-08 12:57:36 -0700212
213 ret = gb_operation_sync(connection, GB_I2S_DATA_TYPE_SEND_DATA,
214 (void *) gb_req, SEND_DATA_BUF_LEN, NULL, 0);
215 return ret;
216}