Skip to content

Commit c740acf

Browse files
RenJianingrkhuangtao
authored andcommitted
usb: gadget: u_audio: add uevent for ppm compensation
This patch add uevent to notify the application layer how much ppm is different between USB clk and AUDIO clk. The event include two parts USB_STATE and PPM. For example: g_audio_work: sent uac uevent USB_STATE=SET_AUDIO_CLK PPM=12 g_audio_work: sent uac uevent USB_STATE=SET_AUDIO_CLK PPM=-1 Note: The ppm compensation depends on the method implement of clk drift and compensation in the audio driver (eg. sound/soc/ rockchip/rockchip_i2s.c). So if you want the ppm compensation to take effect, please make sure the related driver has implemented. Change-Id: I71cb431cf4798028e1b62c1570eb5911b17b3ddc Signed-off-by: Ren Jianing <[email protected]> Signed-off-by: Frank Wang <[email protected]>
1 parent 23d4162 commit c740acf

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

drivers/usb/gadget/function/u_audio.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ enum {
3535
UAC_RATE_CTRL,
3636
};
3737

38+
#define CLK_PPM_GROUP_SIZE 20
39+
3840
/* Runtime data params for one stream */
3941
struct uac_rtd_params {
4042
struct snd_uac_chip *uac; /* parent chip */
@@ -1278,6 +1280,10 @@ static void g_audio_work(struct work_struct *data)
12781280
snprintf(str, sizeof(str), "VOLUME=0x%hx", prm->volume);
12791281
uac_event[2] = str;
12801282
break;
1283+
case SET_AUDIO_CLK:
1284+
uac_event[0] = "USB_STATE=SET_AUDIO_CLK";
1285+
snprintf(str, sizeof(str), "PPM=%d", audio->params.ppm);
1286+
uac_event[1] = str;
12811287
default:
12821288
break;
12831289
}
@@ -1290,6 +1296,107 @@ static void g_audio_work(struct work_struct *data)
12901296
}
12911297
}
12921298

1299+
static void ppm_calculate_work(struct work_struct *data)
1300+
{
1301+
struct g_audio *g_audio = container_of(data, struct g_audio,
1302+
ppm_work.work);
1303+
struct usb_gadget *gadget = g_audio->gadget;
1304+
uint32_t frame_number, fn_msec, clk_msec;
1305+
struct frame_number_data *fn = g_audio->fn;
1306+
uint64_t time_now, time_msec_tmp;
1307+
int32_t ppm;
1308+
static int32_t ppms[CLK_PPM_GROUP_SIZE];
1309+
static int32_t ppm_sum;
1310+
int32_t cnt = fn->second % CLK_PPM_GROUP_SIZE;
1311+
1312+
time_now = ktime_get_raw();
1313+
frame_number = gadget->ops->get_frame(gadget);
1314+
1315+
if (g_audio->fn->time_last &&
1316+
time_now - g_audio->fn->time_last > 1500000000ULL)
1317+
dev_warn(g_audio->device, "PPM work scheduled too slow!\n");
1318+
1319+
g_audio->fn->time_last = time_now;
1320+
1321+
/*
1322+
* If usb is disconnected, the controller will not receive the
1323+
* SoF signal and frame number will be invalid. Because we can't
1324+
* get accurate time of disconnect and whether the gadget will be
1325+
* plugged into the same host next time or not. We must clear all
1326+
* statistics.
1327+
*/
1328+
if (gadget->state != USB_STATE_CONFIGURED) {
1329+
memset(g_audio->fn, 0, sizeof(*g_audio->fn));
1330+
dev_dbg(g_audio->device, "Disconnect. frame number is cleared\n");
1331+
goto out;
1332+
}
1333+
1334+
/* Fist statistic to record begin frame number and system time */
1335+
if (!g_audio->fn->second++) {
1336+
g_audio->fn->time_begin = g_audio->fn->time_last;
1337+
g_audio->fn->fn_begin = frame_number;
1338+
g_audio->fn->fn_last = frame_number;
1339+
goto out;
1340+
}
1341+
1342+
/*
1343+
* For DWC3 Controller, only 13 bits is used to store frame(micro)
1344+
* number. In other words, the frame number will overflow at most
1345+
* 2.047 seconds. We add another registor fn_overflow the record
1346+
* total frame number.
1347+
*/
1348+
if (frame_number <= g_audio->fn->fn_last)
1349+
g_audio->fn->fn_overflow++;
1350+
g_audio->fn->fn_last = frame_number;
1351+
1352+
if (!g_audio->fn->fn_overflow)
1353+
goto out;
1354+
1355+
/* The lower 3 bits represent micro number frame, we don't need it */
1356+
fn_msec = (((fn->fn_overflow - 1) << 14) +
1357+
(BIT(14) + fn->fn_last - fn->fn_begin) + BIT(2)) >> 3;
1358+
time_msec_tmp = fn->time_last - fn->time_begin + 500000ULL;
1359+
do_div(time_msec_tmp, 1000000U);
1360+
clk_msec = (uint32_t)time_msec_tmp;
1361+
1362+
/*
1363+
* According to the definition of ppm:
1364+
* host_clk = (1 + ppm / 1000000) * gadget_clk
1365+
* we can get:
1366+
* ppm = (host_clk - gadget_clk) * 1000000 / gadget_clk
1367+
*/
1368+
ppm = (fn_msec > clk_msec) ?
1369+
(fn_msec - clk_msec) * 1000000L / clk_msec :
1370+
-((clk_msec - fn_msec) * 1000000L / clk_msec);
1371+
1372+
ppm_sum = ppm_sum - ppms[cnt] + ppm;
1373+
ppms[cnt] = ppm;
1374+
1375+
dev_dbg(g_audio->device,
1376+
"frame %u msec %u ppm_calc %d ppm_avage(%d) %d\n",
1377+
fn_msec, clk_msec, ppm, CLK_PPM_GROUP_SIZE,
1378+
ppm_sum / CLK_PPM_GROUP_SIZE);
1379+
1380+
/*
1381+
* We calculate the average of ppm over a period of time. If the
1382+
* latest frame number is too far from the average, no event will
1383+
* be sent.
1384+
*/
1385+
if (abs(ppm_sum / CLK_PPM_GROUP_SIZE - ppm) < 3) {
1386+
ppm = ppm_sum > 0 ?
1387+
(ppm_sum + CLK_PPM_GROUP_SIZE / 2) / CLK_PPM_GROUP_SIZE :
1388+
(ppm_sum - CLK_PPM_GROUP_SIZE / 2) / CLK_PPM_GROUP_SIZE;
1389+
if (ppm != g_audio->params.ppm) {
1390+
g_audio->params.ppm = ppm;
1391+
g_audio->usb_state[SET_AUDIO_CLK] = true;
1392+
schedule_work(&g_audio->work);
1393+
}
1394+
}
1395+
1396+
out:
1397+
schedule_delayed_work(&g_audio->ppm_work, 1 * HZ);
1398+
}
1399+
12931400
int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
12941401
const char *card_name)
12951402
{
@@ -1314,6 +1421,12 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
13141421
p_chmask = params->p_chmask;
13151422
c_chmask = params->c_chmask;
13161423

1424+
g_audio->fn = kzalloc(sizeof(*g_audio->fn), GFP_KERNEL);
1425+
if (!g_audio->fn) {
1426+
err = -ENOMEM;
1427+
goto fail;
1428+
}
1429+
13171430
if (c_chmask) {
13181431
struct uac_rtd_params *prm = &uac->c_prm;
13191432

@@ -1543,6 +1656,8 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
15431656
}
15441657

15451658
INIT_WORK(&g_audio->work, g_audio_work);
1659+
INIT_DELAYED_WORK(&g_audio->ppm_work, ppm_calculate_work);
1660+
ppm_calculate_work(&g_audio->ppm_work.work);
15461661

15471662
if (!err)
15481663
return 0;
@@ -1555,6 +1670,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
15551670
kfree(uac->p_prm.rbuf);
15561671
kfree(uac->c_prm.rbuf);
15571672
kfree(uac);
1673+
kfree(g_audio->fn);
15581674

15591675
return err;
15601676
}
@@ -1569,6 +1685,7 @@ void g_audio_cleanup(struct g_audio *g_audio)
15691685
return;
15701686

15711687
cancel_work_sync(&g_audio->work);
1688+
cancel_delayed_work_sync(&g_audio->ppm_work);
15721689
device_destroy(g_audio->device->class, g_audio->device->devt);
15731690
g_audio->device = NULL;
15741691

@@ -1582,6 +1699,7 @@ void g_audio_cleanup(struct g_audio *g_audio)
15821699
kfree(uac->p_prm.rbuf);
15831700
kfree(uac->c_prm.rbuf);
15841701
kfree(uac);
1702+
kfree(g_audio->fn);
15851703
}
15861704
EXPORT_SYMBOL_GPL(g_audio_cleanup);
15871705

drivers/usb/gadget/function/u_audio.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ struct uac_params {
5353

5454
/* rates are dynamic, in uac_rtd_params */
5555

56+
int ppm; /* difference between audio clk and usb clk */
57+
5658
int req_number; /* number of preallocated requests */
5759
int fb_max; /* upper frequency drift feedback limit per-mil */
5860
};
@@ -66,6 +68,7 @@ enum usb_state_index {
6668
SET_VOLUME_IN,
6769
SET_MUTE_OUT,
6870
SET_MUTE_IN,
71+
SET_AUDIO_CLK,
6972
SET_USB_STATE_MAX,
7073
};
7174

@@ -74,12 +77,24 @@ enum stream_state_index {
7477
STATE_IN,
7578
};
7679

80+
struct frame_number_data {
81+
uint32_t fn_begin; /* frame number when starting statistics */
82+
uint32_t fn_last; /* frame number in the latest statistics */
83+
uint32_t fn_overflow; /* the time of frame number overflow */
84+
uint32_t second; /* total seconds counted */
85+
ktime_t time_begin; /* system time when starting statistics */
86+
ktime_t time_last; /* system time in the latest statistics */
87+
};
88+
7789
struct g_audio {
7890
struct device *device;
7991
bool usb_state[SET_USB_STATE_MAX];
8092
bool stream_state[2];
8193
struct work_struct work;
8294

95+
struct frame_number_data *fn;
96+
struct delayed_work ppm_work;
97+
8398
struct usb_function func;
8499
struct usb_gadget *gadget;
85100

0 commit comments

Comments
 (0)