summaryrefslogtreecommitdiff
path: root/firmware/target/hosted/samsungypr/radio-ypr.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/hosted/samsungypr/radio-ypr.c')
-rw-r--r--firmware/target/hosted/samsungypr/radio-ypr.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/firmware/target/hosted/samsungypr/radio-ypr.c b/firmware/target/hosted/samsungypr/radio-ypr.c
new file mode 100644
index 0000000000..1929bb7c90
--- /dev/null
+++ b/firmware/target/hosted/samsungypr/radio-ypr.c
@@ -0,0 +1,126 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Module wrapper for SI4709 FM Radio Chip, using /dev/si470x (si4709.ko)
10 * Samsung YP-R0 & Samsung YP-R1
11 *
12 * Copyright (c) 2012 Lorenzo Miori
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include <unistd.h>
25#include <fcntl.h>
26#include <sys/ioctl.h>
27#include "stdint.h"
28#include "string.h"
29#include "kernel.h"
30
31#include "radio-ypr.h"
32#include "rds.h"
33#include "si4700.h"
34#include "power.h"
35
36static int radio_dev = -1;
37
38void radiodev_open(void) {
39 radio_dev = open("/dev/si470x", O_RDWR);
40}
41
42void radiodev_close(void) {
43 close(radio_dev);
44}
45
46/* High-level registers access */
47void si4709_write_reg(int addr, uint16_t value) {
48 sSi4709_t r = { .addr = addr, .value = value };
49 ioctl(radio_dev, IOCTL_SI4709_WRITE_BYTE, &r);
50}
51
52uint16_t si4709_read_reg(int addr) {
53 sSi4709_t r = { .addr = addr, .value = 0 };
54 ioctl(radio_dev, IOCTL_SI4709_READ_BYTE, &r);
55 return r.value;
56}
57
58/* Low-level i2c channel access */
59int fmradio_i2c_write(unsigned char address, unsigned char* buf, int count)
60{
61 (void)address;
62 sSi4709_i2c_t r = { .size = count, .buf = buf };
63 return ioctl(radio_dev, IOCTL_SI4709_I2C_WRITE, &r);
64}
65
66int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count)
67{
68 (void)address;
69 sSi4709_i2c_t r = { .size = count, .buf = buf };
70 return ioctl(radio_dev, IOCTL_SI4709_I2C_READ, &r);
71}
72
73#ifdef HAVE_RDS_CAP
74
75/* Register we are going to poll */
76#define STATUSRSSI 0xA
77#define STATUSRSSI_RDSR (0x1 << 15)
78
79/* Low-level RDS Support */
80static struct event_queue rds_queue;
81static uint32_t rds_stack[DEFAULT_STACK_SIZE / sizeof(uint32_t)];
82static uint16_t rds_data[4];
83
84enum {
85 Q_POWERUP,
86};
87
88static void NORETURN_ATTR rds_thread(void)
89{
90 /* start up frozen */
91 int timeout = TIMEOUT_BLOCK;
92 struct queue_event ev;
93
94 while (true) {
95 queue_wait_w_tmo(&rds_queue, &ev, timeout);
96 switch (ev.id) {
97 case Q_POWERUP:
98 /* power up: timeout after 1 tick, else block indefinitely */
99 timeout = ev.data ? 1 : TIMEOUT_BLOCK;
100 break;
101 case SYS_TIMEOUT:
102 /* Captures RDS data and processes it */
103 if ((si4709_read_reg(STATUSRSSI) & STATUSRSSI_RDSR) >> 8) {
104 if (si4700_rds_read_raw(rds_data) && rds_process(rds_data))
105 si4700_rds_set_event();
106 }
107 break;
108 }
109 }
110}
111
112/* true after full radio power up, and false before powering down */
113void si4700_rds_powerup(bool on)
114{
115 queue_post(&rds_queue, Q_POWERUP, on);
116}
117
118/* One-time RDS init at startup */
119void si4700_rds_init(void)
120{
121 queue_init(&rds_queue, false);
122 create_thread(rds_thread, rds_stack, sizeof(rds_stack), 0, "rds"
123 IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU));
124 rds_init();
125}
126#endif /* HAVE_RDS_CAP */