[media] vivid: add support for radio receivers and transmitters
[firefly-linux-kernel-4.4.55.git] / drivers / media / platform / vivid / vivid-rds-gen.c
1 /*
2  * vivid-rds-gen.c - rds (radio data system) generator support functions.
3  *
4  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5  *
6  * This program is free software; you may redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
14  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
15  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17  * SOFTWARE.
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/ktime.h>
22 #include <linux/videodev2.h>
23
24 #include "vivid-rds-gen.h"
25
26 static u8 vivid_get_di(const struct vivid_rds_gen *rds, unsigned grp)
27 {
28         switch (grp) {
29         case 0:
30                 return (rds->dyn_pty << 2) | (grp & 3);
31         case 1:
32                 return (rds->compressed << 2) | (grp & 3);
33         case 2:
34                 return (rds->art_head << 2) | (grp & 3);
35         case 3:
36                 return (rds->mono_stereo << 2) | (grp & 3);
37         }
38         return 0;
39 }
40
41 /*
42  * This RDS generator creates 57 RDS groups (one group == four RDS blocks).
43  * Groups 0-3, 22-25 and 44-47 (spaced 22 groups apart) are filled with a
44  * standard 0B group containing the PI code and PS name.
45  *
46  * Groups 4-19 and 26-41 use group 2A for the radio text.
47  *
48  * Group 56 contains the time (group 4A).
49  *
50  * All remaining groups use a filler group 15B block that just repeats
51  * the PI and PTY codes.
52  */
53 void vivid_rds_generate(struct vivid_rds_gen *rds)
54 {
55         struct v4l2_rds_data *data = rds->data;
56         unsigned grp;
57         struct tm tm;
58         unsigned date;
59         unsigned time;
60         int l;
61
62         for (grp = 0; grp < VIVID_RDS_GEN_GROUPS; grp++, data += VIVID_RDS_GEN_BLKS_PER_GRP) {
63                 data[0].lsb = rds->picode & 0xff;
64                 data[0].msb = rds->picode >> 8;
65                 data[0].block = V4L2_RDS_BLOCK_A | (V4L2_RDS_BLOCK_A << 3);
66                 data[1].lsb = rds->pty << 5;
67                 data[1].msb = (rds->pty >> 3) | (rds->tp << 2);
68                 data[1].block = V4L2_RDS_BLOCK_B | (V4L2_RDS_BLOCK_B << 3);
69                 data[3].block = V4L2_RDS_BLOCK_D | (V4L2_RDS_BLOCK_D << 3);
70
71                 switch (grp) {
72                 case 0 ... 3:
73                 case 22 ... 25:
74                 case 44 ... 47: /* Group 0B */
75                         data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
76                         data[1].lsb |= vivid_get_di(rds, grp % 22);
77                         data[1].msb |= 1 << 3;
78                         data[2].lsb = rds->picode & 0xff;
79                         data[2].msb = rds->picode >> 8;
80                         data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
81                         data[3].lsb = rds->psname[2 * (grp % 22) + 1];
82                         data[3].msb = rds->psname[2 * (grp % 22)];
83                         break;
84                 case 4 ... 19:
85                 case 26 ... 41: /* Group 2A */
86                         data[1].lsb |= (grp - 4) % 22;
87                         data[1].msb |= 4 << 3;
88                         data[2].msb = rds->radiotext[4 * ((grp - 4) % 22)];
89                         data[2].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 1];
90                         data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
91                         data[3].msb = rds->radiotext[4 * ((grp - 4) % 22) + 2];
92                         data[3].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 3];
93                         break;
94                 case 56:
95                         /*
96                          * Group 4A
97                          *
98                          * Uses the algorithm from Annex G of the RDS standard
99                          * EN 50067:1998 to convert a UTC date to an RDS Modified
100                          * Julian Day.
101                          */
102                         time_to_tm(get_seconds(), 0, &tm);
103                         l = tm.tm_mon <= 1;
104                         date = 14956 + tm.tm_mday + ((tm.tm_year - l) * 1461) / 4 +
105                                 ((tm.tm_mon + 2 + l * 12) * 306001) / 10000;
106                         time = (tm.tm_hour << 12) |
107                                (tm.tm_min << 6) |
108                                (sys_tz.tz_minuteswest >= 0 ? 0x20 : 0) |
109                                (abs(sys_tz.tz_minuteswest) / 30);
110                         data[1].lsb &= ~3;
111                         data[1].lsb |= date >> 15;
112                         data[1].msb |= 8 << 3;
113                         data[2].lsb = (date << 1) & 0xfe;
114                         data[2].lsb |= (time >> 16) & 1;
115                         data[2].msb = (date >> 7) & 0xff;
116                         data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
117                         data[3].lsb = time & 0xff;
118                         data[3].msb = (time >> 8) & 0xff;
119                         break;
120                 default: /* Group 15B */
121                         data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
122                         data[1].lsb |= vivid_get_di(rds, grp % 22);
123                         data[1].msb |= 0x1f << 3;
124                         data[2].lsb = rds->picode & 0xff;
125                         data[2].msb = rds->picode >> 8;
126                         data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
127                         data[3].lsb = rds->pty << 5;
128                         data[3].lsb |= (rds->ta << 4) | (rds->ms << 3);
129                         data[3].lsb |= vivid_get_di(rds, grp % 22);
130                         data[3].msb |= rds->pty >> 3;
131                         data[3].msb |= 0x1f << 3;
132                         break;
133                 }
134         }
135 }
136
137 void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq,
138                           bool alt)
139 {
140         /* Alternate PTY between Info and Weather */
141         if (rds->use_rbds) {
142                 rds->picode = 0x2e75; /* 'KLNX' call sign */
143                 rds->pty = alt ? 29 : 2;
144         } else {
145                 rds->picode = 0x8088;
146                 rds->pty = alt ? 16 : 3;
147         }
148         rds->mono_stereo = true;
149         rds->art_head = false;
150         rds->compressed = false;
151         rds->dyn_pty = false;
152         rds->tp = true;
153         rds->ta = alt;
154         rds->ms = true;
155         snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d",
156                  freq / 16, ((freq & 0xf) * 10) / 16);
157         if (alt)
158                 strlcpy(rds->radiotext,
159                         " The Radio Data System can switch between different Radio Texts ",
160                         sizeof(rds->radiotext));
161         else
162                 strlcpy(rds->radiotext,
163                         "An example of Radio Text as transmitted by the Radio Data System",
164                         sizeof(rds->radiotext));
165 }