forked from projectara/greybus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaudio-gb-cmds.c
188 lines (154 loc) · 5.15 KB
/
audio-gb-cmds.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
* 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;
}