diff options
author | Bertrik Sikken <bertrik@sikken.nl> | 2009-07-07 21:57:16 +0000 |
---|---|---|
committer | Bertrik Sikken <bertrik@sikken.nl> | 2009-07-07 21:57:16 +0000 |
commit | 4e965b4b6c22a4ed206eed418c0e1b9296cc2113 (patch) | |
tree | d440a630bd43b4baab72138588bab8fa674a163b /firmware | |
parent | 8d4d4610b6814c0c4a4abe9523b4b6b2b80ac9a4 (diff) | |
download | rockbox-4e965b4b6c22a4ed206eed418c0e1b9296cc2113.tar.gz rockbox-4e965b4b6c22a4ed206eed418c0e1b9296cc2113.zip |
Meizu: implement i2c for the meizu fmradio and update the tea5760 tuner driver
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21703 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/drivers/tuner/tea5760uk.c | 111 | ||||
-rw-r--r-- | firmware/export/tea5760.h | 56 | ||||
-rw-r--r-- | firmware/export/tuner.h | 5 | ||||
-rw-r--r-- | firmware/target/arm/s5l8700/fmradio-i2c-meizu.c | 146 | ||||
-rw-r--r-- | firmware/tuner.c | 16 |
5 files changed, 296 insertions, 38 deletions
diff --git a/firmware/drivers/tuner/tea5760uk.c b/firmware/drivers/tuner/tea5760uk.c index 781e51967c..db07e20cf4 100644 --- a/firmware/drivers/tuner/tea5760uk.c +++ b/firmware/drivers/tuner/tea5760uk.c | |||
@@ -28,10 +28,20 @@ | |||
28 | #include "fmradio.h" | 28 | #include "fmradio.h" |
29 | #include "fmradio_i2c.h" /* physical interface driver */ | 29 | #include "fmradio_i2c.h" /* physical interface driver */ |
30 | 30 | ||
31 | #define I2C_ADR 0xC0 | 31 | #define I2C_ADR 0x22 |
32 | static unsigned char write_bytes[7] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | 32 | |
33 | 33 | static bool tuner_present = false; | |
34 | static void tea5760uk_set_clear(int byte, unsigned char bits, int set) | 34 | static unsigned char write_bytes[7] = { |
35 | 0x00, /* INTREG LSB */ | ||
36 | 0x80, /* FRQSET MSB */ | ||
37 | 0x00, /* FRQSET LSB */ | ||
38 | 0x08, /* TNCTRL MSB */ | ||
39 | 0xD2, /* TNCTRL LSB */ | ||
40 | 0x00, /* TESTREG MSB */ | ||
41 | 0x40 /* TESTREG LSB */ | ||
42 | }; | ||
43 | |||
44 | static void tea5760_set_clear(int byte, unsigned char bits, int set) | ||
35 | { | 45 | { |
36 | write_bytes[byte] &= ~bits; | 46 | write_bytes[byte] &= ~bits; |
37 | if (set) | 47 | if (set) |
@@ -39,58 +49,60 @@ static void tea5760uk_set_clear(int byte, unsigned char bits, int set) | |||
39 | } | 49 | } |
40 | 50 | ||
41 | /* tuner abstraction layer: set something to the tuner */ | 51 | /* tuner abstraction layer: set something to the tuner */ |
42 | int tea5760uk_set(int setting, int value) | 52 | int tea5760_set(int setting, int value) |
43 | { | 53 | { |
44 | switch(setting) | 54 | switch(setting) |
45 | { | 55 | { |
46 | case RADIO_SLEEP: | 56 | case RADIO_SLEEP: |
47 | /* init values */ | 57 | if (value) { |
48 | write_bytes[0] |= (1<<7); /* mute */ | 58 | /* sleep / standby mode */ |
49 | #if CONFIG_TUNER_XTAL == 32768 | 59 | tea5760_set_clear(3, (1<<6), 0); |
50 | /* 32.768kHz, soft mute, stereo noise cancelling */ | 60 | } |
51 | write_bytes[3] |= (1<<4) | (1<<3) | (1<<1); | 61 | else { |
52 | #else | 62 | /* active mode */ |
53 | /* soft mute, stereo noise cancelling */ | 63 | tea5760_set_clear(3, (1<<6), 1); |
54 | write_bytes[3] |= (1<<3) | (1<<1); | 64 | /* disable hard mute */ |
55 | #endif | 65 | tea5760_set_clear(4, (1<<7), 0); |
56 | /* sleep / standby mode */ | 66 | } |
57 | tea5760uk_set_clear(3, (1<<6), value); | ||
58 | break; | 67 | break; |
59 | 68 | ||
60 | case RADIO_FREQUENCY: | 69 | case RADIO_FREQUENCY: |
61 | { | 70 | { |
62 | int n; | 71 | int n; |
63 | #if CONFIG_TUNER_XTAL == 32768 | 72 | |
73 | /* low side injection */ | ||
74 | tea5760_set_clear(4, (1<<4), 0); | ||
64 | n = (4 * (value - 225000) + 16384) / 32768; | 75 | n = (4 * (value - 225000) + 16384) / 32768; |
65 | #else | 76 | |
66 | n = (4 * (value - 225000)) / 50000; | 77 | /* set frequency in preset mode */ |
67 | #endif | 78 | write_bytes[1] = (n >> 8) & 0x3F; |
68 | write_bytes[6] = (write_bytes[6] & 0xC0) | (n >> 8); | 79 | write_bytes[2] = n; |
69 | write_bytes[7] = n; | ||
70 | } | 80 | } |
71 | break; | 81 | break; |
72 | 82 | ||
73 | case RADIO_SCAN_FREQUENCY: | 83 | case RADIO_SCAN_FREQUENCY: |
74 | tea5760uk_set(RADIO_FREQUENCY, value); | 84 | tea5760_set(RADIO_FREQUENCY, value); |
75 | sleep(HZ/30); | 85 | sleep(40*HZ/1000); |
76 | return tea5760uk_get(RADIO_TUNED); | 86 | return tea5760_get(RADIO_TUNED); |
77 | 87 | ||
78 | case RADIO_MUTE: | 88 | case RADIO_MUTE: |
79 | tea5760uk_set_clear(3, (1<<2), value); | 89 | tea5760_set_clear(3, (1<<2), value); |
80 | break; | 90 | break; |
81 | 91 | ||
82 | case RADIO_REGION: | 92 | case RADIO_REGION: |
83 | { | 93 | { |
84 | const struct tea5760uk_region_data *rd = | 94 | const struct tea5760_region_data *rd = |
85 | &tea5760uk_region_data[value]; | 95 | &tea5760_region_data[value]; |
86 | 96 | ||
87 | tea5760uk_set_clear(4, (1<<1), rd->deemphasis); | 97 | tea5760_set_clear(4, (1<<1), rd->deemphasis); |
88 | tea5760uk_set_clear(3, (1<<5), rd->band); | 98 | tea5760_set_clear(3, (1<<5), rd->band); |
89 | break; | ||
90 | } | 99 | } |
100 | break; | ||
101 | |||
91 | case RADIO_FORCE_MONO: | 102 | case RADIO_FORCE_MONO: |
92 | tea5760uk_set_clear(4, (1<<3), value); | 103 | tea5760_set_clear(4, (1<<3), value); |
93 | break; | 104 | break; |
105 | |||
94 | default: | 106 | default: |
95 | return -1; | 107 | return -1; |
96 | } | 108 | } |
@@ -100,7 +112,7 @@ int tea5760uk_set(int setting, int value) | |||
100 | } | 112 | } |
101 | 113 | ||
102 | /* tuner abstraction layer: read something from the tuner */ | 114 | /* tuner abstraction layer: read something from the tuner */ |
103 | int tea5760uk_get(int setting) | 115 | int tea5760_get(int setting) |
104 | { | 116 | { |
105 | unsigned char read_bytes[16]; | 117 | unsigned char read_bytes[16]; |
106 | int val = -1; /* default for unsupported query */ | 118 | int val = -1; /* default for unsupported query */ |
@@ -110,7 +122,7 @@ int tea5760uk_get(int setting) | |||
110 | switch(setting) | 122 | switch(setting) |
111 | { | 123 | { |
112 | case RADIO_PRESENT: | 124 | case RADIO_PRESENT: |
113 | val = 1; /* true */ | 125 | val = tuner_present ? 1 : 0; |
114 | break; | 126 | break; |
115 | 127 | ||
116 | case RADIO_TUNED: | 128 | case RADIO_TUNED: |
@@ -130,8 +142,31 @@ int tea5760uk_get(int setting) | |||
130 | return val; | 142 | return val; |
131 | } | 143 | } |
132 | 144 | ||
133 | void tea5760uk_dbg_info(struct tea5760uk_dbg_info *info) | 145 | void tea5760_init(void) |
134 | { | 146 | { |
135 | fmradio_i2c_read(I2C_ADR, info->read_regs, 5); | 147 | unsigned char buf[16]; |
136 | memcpy(info->write_regs, write_bytes, 5); | 148 | unsigned short manid, chipid; |
149 | |||
150 | /* read all registers */ | ||
151 | fmradio_i2c_read(I2C_ADR, buf, sizeof(buf)); | ||
152 | |||
153 | /* check device id */ | ||
154 | manid = (buf[12] << 8) | buf[13]; | ||
155 | chipid = (buf[14] << 8) | buf[15]; | ||
156 | if ((manid == 0x202B) && (chipid == 0x5760)) | ||
157 | { | ||
158 | tuner_present = true; | ||
159 | } | ||
160 | |||
161 | /* write initial values */ | ||
162 | tea5760_set_clear(3, (1<<1), 1); /* soft mute on */ | ||
163 | tea5760_set_clear(3, (1<<0), 1); /* stereo noise cancellation on */ | ||
164 | fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); | ||
137 | } | 165 | } |
166 | |||
167 | void tea5760_dbg_info(struct tea5760_dbg_info *info) | ||
168 | { | ||
169 | fmradio_i2c_read(I2C_ADR, info->read_regs, sizeof(info->read_regs)); | ||
170 | memcpy(info->write_regs, write_bytes, sizeof(info->write_regs)); | ||
171 | } | ||
172 | |||
diff --git a/firmware/export/tea5760.h b/firmware/export/tea5760.h new file mode 100644 index 0000000000..8fa54dfa78 --- /dev/null +++ b/firmware/export/tea5760.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * Tuner header for the Philips TEA5760 | ||
10 | * | ||
11 | * Copyright (C) 2009 Bertrik Sikken | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | |||
23 | #ifndef _TEA5760_H_ | ||
24 | #define _TEA5760_H_ | ||
25 | |||
26 | #include "config.h" | ||
27 | #include "tuner.h" | ||
28 | |||
29 | #define HAVE_RADIO_REGION | ||
30 | |||
31 | struct tea5760_region_data | ||
32 | { | ||
33 | unsigned char deemphasis; /* 1: 50us, 0: 75us */ | ||
34 | unsigned char band; /* 0: europe, 1: japan (BL in TEA spec)*/ | ||
35 | } __attribute__((packed)); | ||
36 | |||
37 | extern const struct tea5760_region_data tea5760_region_data[TUNER_NUM_REGIONS]; | ||
38 | |||
39 | struct tea5760_dbg_info | ||
40 | { | ||
41 | unsigned char read_regs[16]; | ||
42 | unsigned char write_regs[7]; | ||
43 | }; | ||
44 | |||
45 | int tea5760_set(int setting, int value); | ||
46 | int tea5760_get(int setting); | ||
47 | void tea5760_init(void); | ||
48 | void tea5760_dbg_info(struct tea5760_dbg_info *info); | ||
49 | |||
50 | #ifndef CONFIG_TUNER_MULTI | ||
51 | #define tuner_set tea5760_set | ||
52 | #define tuner_get tea5760_get | ||
53 | #endif | ||
54 | |||
55 | #endif /* _TEA5760_H_ */ | ||
56 | |||
diff --git a/firmware/export/tuner.h b/firmware/export/tuner.h index 6d6a690d77..f92e94269c 100644 --- a/firmware/export/tuner.h +++ b/firmware/export/tuner.h | |||
@@ -96,6 +96,11 @@ extern int (*tuner_get)(int setting); | |||
96 | #include "s1a0903x01.h" | 96 | #include "s1a0903x01.h" |
97 | #endif | 97 | #endif |
98 | 98 | ||
99 | /** Philips TEA5760 **/ | ||
100 | #if (CONFIG_TUNER & TEA5760) | ||
101 | #include "tea5760.h" | ||
102 | #endif | ||
103 | |||
99 | /** Philips TEA5767 **/ | 104 | /** Philips TEA5767 **/ |
100 | #if (CONFIG_TUNER & TEA5767) | 105 | #if (CONFIG_TUNER & TEA5767) |
101 | /* Ondio FM, FM Recorder, Recorder V2, iRiver h100/h300, iAudio x5 */ | 106 | /* Ondio FM, FM Recorder, Recorder V2, iRiver h100/h300, iAudio x5 */ |
diff --git a/firmware/target/arm/s5l8700/fmradio-i2c-meizu.c b/firmware/target/arm/s5l8700/fmradio-i2c-meizu.c new file mode 100644 index 0000000000..5a4113a6a5 --- /dev/null +++ b/firmware/target/arm/s5l8700/fmradio-i2c-meizu.c | |||
@@ -0,0 +1,146 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2008 by Bertrik Sikken | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | /* | ||
23 | FM radio i2c interface, allows the radio driver to talk to the tuner chip. | ||
24 | |||
25 | It is implemented using the generic i2c driver, which does "bit-banged" | ||
26 | I2C with a couple of GPIO pins. | ||
27 | */ | ||
28 | |||
29 | #include "config.h" | ||
30 | |||
31 | #include "inttypes.h" | ||
32 | #include "s5l8700.h" | ||
33 | #include "generic_i2c.h" | ||
34 | #include "fmradio_i2c.h" | ||
35 | |||
36 | #define I2C_GPIO PDAT3 | ||
37 | #define I2C_GPIO_DIR PCON3 | ||
38 | #define I2C_SCL_PIN 4 | ||
39 | #define I2C_SDA_PIN 2 | ||
40 | |||
41 | #define SCL_DIR_MASK (3<<(4*I2C_SCL_PIN)) | ||
42 | #define SCL_DIR_OUT (1<<(4*I2C_SCL_PIN)) | ||
43 | #define SCL_DIR_IN 0 | ||
44 | #define SDA_DIR_MASK (3<<(4*I2C_SDA_PIN)) | ||
45 | #define SDA_DIR_OUT (1<<(4*I2C_SDA_PIN)) | ||
46 | #define SDA_DIR_IN 0 | ||
47 | |||
48 | static int fm_i2c_bus; | ||
49 | |||
50 | static void fm_scl_hi(void) | ||
51 | { | ||
52 | I2C_GPIO |= 1 << I2C_SCL_PIN; | ||
53 | } | ||
54 | |||
55 | static void fm_scl_lo(void) | ||
56 | { | ||
57 | I2C_GPIO &= ~(1 << I2C_SCL_PIN); | ||
58 | } | ||
59 | |||
60 | static void fm_sda_hi(void) | ||
61 | { | ||
62 | I2C_GPIO |= 1 << I2C_SDA_PIN; | ||
63 | } | ||
64 | |||
65 | static void fm_sda_lo(void) | ||
66 | { | ||
67 | I2C_GPIO &= ~(1 << I2C_SDA_PIN); | ||
68 | } | ||
69 | |||
70 | static void fm_sda_input(void) | ||
71 | { | ||
72 | I2C_GPIO_DIR = (I2C_GPIO_DIR & ~SDA_DIR_MASK) | SDA_DIR_IN; | ||
73 | } | ||
74 | |||
75 | static void fm_sda_output(void) | ||
76 | { | ||
77 | I2C_GPIO_DIR = (I2C_GPIO_DIR & ~SDA_DIR_MASK) | SDA_DIR_OUT; | ||
78 | } | ||
79 | |||
80 | static void fm_scl_input(void) | ||
81 | { | ||
82 | I2C_GPIO_DIR = (I2C_GPIO_DIR & ~SCL_DIR_MASK) | SCL_DIR_IN; | ||
83 | } | ||
84 | |||
85 | static void fm_scl_output(void) | ||
86 | { | ||
87 | I2C_GPIO_DIR = (I2C_GPIO_DIR & ~SCL_DIR_MASK) | SCL_DIR_OUT; | ||
88 | } | ||
89 | |||
90 | static int fm_sda(void) | ||
91 | { | ||
92 | return (I2C_GPIO & (1 << I2C_SDA_PIN)); | ||
93 | } | ||
94 | |||
95 | static int fm_scl(void) | ||
96 | { | ||
97 | return (I2C_GPIO & (1 << I2C_SCL_PIN)); | ||
98 | } | ||
99 | |||
100 | /* simple and crude delay, used for all delays in the generic i2c driver */ | ||
101 | static void fm_delay(void) | ||
102 | { | ||
103 | volatile int i; | ||
104 | |||
105 | /* this loop is uncalibrated and could use more sophistication */ | ||
106 | for (i = 0; i < 20; i++) { | ||
107 | } | ||
108 | } | ||
109 | |||
110 | /* interface towards the generic i2c driver */ | ||
111 | static const struct i2c_interface fm_i2c_interface = { | ||
112 | .scl_hi = fm_scl_hi, | ||
113 | .scl_lo = fm_scl_lo, | ||
114 | .sda_hi = fm_sda_hi, | ||
115 | .sda_lo = fm_sda_lo, | ||
116 | .sda_input = fm_sda_input, | ||
117 | .sda_output = fm_sda_output, | ||
118 | .scl_input = fm_scl_input, | ||
119 | .scl_output = fm_scl_output, | ||
120 | .scl = fm_scl, | ||
121 | .sda = fm_sda, | ||
122 | |||
123 | .delay_hd_sta = fm_delay, | ||
124 | .delay_hd_dat = fm_delay, | ||
125 | .delay_su_dat = fm_delay, | ||
126 | .delay_su_sto = fm_delay, | ||
127 | .delay_su_sta = fm_delay, | ||
128 | .delay_thigh = fm_delay | ||
129 | }; | ||
130 | |||
131 | /* initialise i2c for fmradio */ | ||
132 | void fmradio_i2c_init(void) | ||
133 | { | ||
134 | fm_i2c_bus = i2c_add_node(&fm_i2c_interface); | ||
135 | } | ||
136 | |||
137 | int fmradio_i2c_write(unsigned char address, const unsigned char* buf, int count) | ||
138 | { | ||
139 | return i2c_write_data(fm_i2c_bus, address, -1, buf, count); | ||
140 | } | ||
141 | |||
142 | int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count) | ||
143 | { | ||
144 | return i2c_read_data(fm_i2c_bus, address, -1, buf, count); | ||
145 | } | ||
146 | |||
diff --git a/firmware/tuner.c b/firmware/tuner.c index c5da27079c..a471c4e970 100644 --- a/firmware/tuner.c +++ b/firmware/tuner.c | |||
@@ -49,6 +49,16 @@ const unsigned char lv24020lp_region_data[TUNER_NUM_REGIONS] = | |||
49 | }; | 49 | }; |
50 | #endif /* (CONFIG_TUNER & LV24020LP) */ | 50 | #endif /* (CONFIG_TUNER & LV24020LP) */ |
51 | 51 | ||
52 | #if (CONFIG_TUNER & TEA5760) | ||
53 | const struct tea5760_region_data tea5760_region_data[TUNER_NUM_REGIONS] = | ||
54 | { | ||
55 | [REGION_EUROPE] = { 1, 0 }, /* 50uS, US/Europe band */ | ||
56 | [REGION_US_CANADA] = { 0, 0 }, /* 75uS, US/Europe band */ | ||
57 | [REGION_JAPAN] = { 1, 1 }, /* 50uS, Japanese band */ | ||
58 | [REGION_KOREA] = { 1, 0 }, /* 50uS, US/Europe band */ | ||
59 | }; | ||
60 | #endif /* (CONFIG_TUNER & TEA5760) */ | ||
61 | |||
52 | #if (CONFIG_TUNER & TEA5767) | 62 | #if (CONFIG_TUNER & TEA5767) |
53 | const struct tea5767_region_data tea5767_region_data[TUNER_NUM_REGIONS] = | 63 | const struct tea5767_region_data tea5767_region_data[TUNER_NUM_REGIONS] = |
54 | { | 64 | { |
@@ -95,6 +105,12 @@ void tuner_init(void) | |||
95 | lv24020lp_get, | 105 | lv24020lp_get, |
96 | lv24020lp_init()) | 106 | lv24020lp_init()) |
97 | #endif | 107 | #endif |
108 | #if (CONFIG_TUNER & TEA5760) | ||
109 | TUNER_TYPE_CASE(TEA5760, | ||
110 | tea5760_set, | ||
111 | tea5760_get, | ||
112 | tea5760_init()) | ||
113 | #endif | ||
98 | #if (CONFIG_TUNER & TEA5767) | 114 | #if (CONFIG_TUNER & TEA5767) |
99 | TUNER_TYPE_CASE(TEA5767, | 115 | TUNER_TYPE_CASE(TEA5767, |
100 | tea5767_set, | 116 | tea5767_set, |