Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / media / platform / vivid / vivid-rds-gen.c
diff --git a/kernel/drivers/media/platform/vivid/vivid-rds-gen.c b/kernel/drivers/media/platform/vivid/vivid-rds-gen.c
new file mode 100644 (file)
index 0000000..c382343
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * vivid-rds-gen.c - rds (radio data system) generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include "vivid-rds-gen.h"
+
+static u8 vivid_get_di(const struct vivid_rds_gen *rds, unsigned grp)
+{
+       switch (grp) {
+       case 0:
+               return (rds->dyn_pty << 2) | (grp & 3);
+       case 1:
+               return (rds->compressed << 2) | (grp & 3);
+       case 2:
+               return (rds->art_head << 2) | (grp & 3);
+       case 3:
+               return (rds->mono_stereo << 2) | (grp & 3);
+       }
+       return 0;
+}
+
+/*
+ * This RDS generator creates 57 RDS groups (one group == four RDS blocks).
+ * Groups 0-3, 22-25 and 44-47 (spaced 22 groups apart) are filled with a
+ * standard 0B group containing the PI code and PS name.
+ *
+ * Groups 4-19 and 26-41 use group 2A for the radio text.
+ *
+ * Group 56 contains the time (group 4A).
+ *
+ * All remaining groups use a filler group 15B block that just repeats
+ * the PI and PTY codes.
+ */
+void vivid_rds_generate(struct vivid_rds_gen *rds)
+{
+       struct v4l2_rds_data *data = rds->data;
+       unsigned grp;
+       struct tm tm;
+       unsigned date;
+       unsigned time;
+       int l;
+
+       for (grp = 0; grp < VIVID_RDS_GEN_GROUPS; grp++, data += VIVID_RDS_GEN_BLKS_PER_GRP) {
+               data[0].lsb = rds->picode & 0xff;
+               data[0].msb = rds->picode >> 8;
+               data[0].block = V4L2_RDS_BLOCK_A | (V4L2_RDS_BLOCK_A << 3);
+               data[1].lsb = rds->pty << 5;
+               data[1].msb = (rds->pty >> 3) | (rds->tp << 2);
+               data[1].block = V4L2_RDS_BLOCK_B | (V4L2_RDS_BLOCK_B << 3);
+               data[3].block = V4L2_RDS_BLOCK_D | (V4L2_RDS_BLOCK_D << 3);
+
+               switch (grp) {
+               case 0 ... 3:
+               case 22 ... 25:
+               case 44 ... 47: /* Group 0B */
+                       data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
+                       data[1].lsb |= vivid_get_di(rds, grp % 22);
+                       data[1].msb |= 1 << 3;
+                       data[2].lsb = rds->picode & 0xff;
+                       data[2].msb = rds->picode >> 8;
+                       data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
+                       data[3].lsb = rds->psname[2 * (grp % 22) + 1];
+                       data[3].msb = rds->psname[2 * (grp % 22)];
+                       break;
+               case 4 ... 19:
+               case 26 ... 41: /* Group 2A */
+                       data[1].lsb |= (grp - 4) % 22;
+                       data[1].msb |= 4 << 3;
+                       data[2].msb = rds->radiotext[4 * ((grp - 4) % 22)];
+                       data[2].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 1];
+                       data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
+                       data[3].msb = rds->radiotext[4 * ((grp - 4) % 22) + 2];
+                       data[3].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 3];
+                       break;
+               case 56:
+                       /*
+                        * Group 4A
+                        *
+                        * Uses the algorithm from Annex G of the RDS standard
+                        * EN 50067:1998 to convert a UTC date to an RDS Modified
+                        * Julian Day.
+                        */
+                       time_to_tm(get_seconds(), 0, &tm);
+                       l = tm.tm_mon <= 1;
+                       date = 14956 + tm.tm_mday + ((tm.tm_year - l) * 1461) / 4 +
+                               ((tm.tm_mon + 2 + l * 12) * 306001) / 10000;
+                       time = (tm.tm_hour << 12) |
+                              (tm.tm_min << 6) |
+                              (sys_tz.tz_minuteswest >= 0 ? 0x20 : 0) |
+                              (abs(sys_tz.tz_minuteswest) / 30);
+                       data[1].lsb &= ~3;
+                       data[1].lsb |= date >> 15;
+                       data[1].msb |= 8 << 3;
+                       data[2].lsb = (date << 1) & 0xfe;
+                       data[2].lsb |= (time >> 16) & 1;
+                       data[2].msb = (date >> 7) & 0xff;
+                       data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
+                       data[3].lsb = time & 0xff;
+                       data[3].msb = (time >> 8) & 0xff;
+                       break;
+               default: /* Group 15B */
+                       data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
+                       data[1].lsb |= vivid_get_di(rds, grp % 22);
+                       data[1].msb |= 0x1f << 3;
+                       data[2].lsb = rds->picode & 0xff;
+                       data[2].msb = rds->picode >> 8;
+                       data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
+                       data[3].lsb = rds->pty << 5;
+                       data[3].lsb |= (rds->ta << 4) | (rds->ms << 3);
+                       data[3].lsb |= vivid_get_di(rds, grp % 22);
+                       data[3].msb |= rds->pty >> 3;
+                       data[3].msb |= 0x1f << 3;
+                       break;
+               }
+       }
+}
+
+void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq,
+                         bool alt)
+{
+       /* Alternate PTY between Info and Weather */
+       if (rds->use_rbds) {
+               rds->picode = 0x2e75; /* 'KLNX' call sign */
+               rds->pty = alt ? 29 : 2;
+       } else {
+               rds->picode = 0x8088;
+               rds->pty = alt ? 16 : 3;
+       }
+       rds->mono_stereo = true;
+       rds->art_head = false;
+       rds->compressed = false;
+       rds->dyn_pty = false;
+       rds->tp = true;
+       rds->ta = alt;
+       rds->ms = true;
+       snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d",
+                freq / 16, ((freq & 0xf) * 10) / 16);
+       if (alt)
+               strlcpy(rds->radiotext,
+                       " The Radio Data System can switch between different Radio Texts ",
+                       sizeof(rds->radiotext));
+       else
+               strlcpy(rds->radiotext,
+                       "An example of Radio Text as transmitted by the Radio Data System",
+                       sizeof(rds->radiotext));
+}