diff options
Diffstat (limited to 'firmware/target/hosted/samsungypr/radio-ypr.c')
-rw-r--r-- | firmware/target/hosted/samsungypr/radio-ypr.c | 126 |
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 | |||
36 | static int radio_dev = -1; | ||
37 | |||
38 | void radiodev_open(void) { | ||
39 | radio_dev = open("/dev/si470x", O_RDWR); | ||
40 | } | ||
41 | |||
42 | void radiodev_close(void) { | ||
43 | close(radio_dev); | ||
44 | } | ||
45 | |||
46 | /* High-level registers access */ | ||
47 | void 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 | |||
52 | uint16_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 */ | ||
59 | int 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 | |||
66 | int 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 */ | ||
80 | static struct event_queue rds_queue; | ||
81 | static uint32_t rds_stack[DEFAULT_STACK_SIZE / sizeof(uint32_t)]; | ||
82 | static uint16_t rds_data[4]; | ||
83 | |||
84 | enum { | ||
85 | Q_POWERUP, | ||
86 | }; | ||
87 | |||
88 | static 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 */ | ||
113 | void si4700_rds_powerup(bool on) | ||
114 | { | ||
115 | queue_post(&rds_queue, Q_POWERUP, on); | ||
116 | } | ||
117 | |||
118 | /* One-time RDS init at startup */ | ||
119 | void 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 */ | ||