diff options
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c')
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c | 151 |
1 files changed, 141 insertions, 10 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c index 3af8f35f69..a04cd7f893 100644 --- a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c | |||
@@ -19,10 +19,13 @@ | |||
19 | #include "system.h" | 19 | #include "system.h" |
20 | #include "cpu.h" | 20 | #include "cpu.h" |
21 | #include "spi-imx31.h" | 21 | #include "spi-imx31.h" |
22 | #include "gpio-imx31.h" | ||
22 | #include "mc13783.h" | 23 | #include "mc13783.h" |
23 | #include "debug.h" | 24 | #include "debug.h" |
24 | #include "kernel.h" | 25 | #include "kernel.h" |
25 | 26 | ||
27 | #include "button-target.h" | ||
28 | |||
26 | /* This is all based on communicating with the MC13783 PMU which is on | 29 | /* This is all based on communicating with the MC13783 PMU which is on |
27 | * CSPI2 with the chip select at 0. The LCD controller resides on | 30 | * CSPI2 with the chip select at 0. The LCD controller resides on |
28 | * CSPI3 cs1, but we have no idea how to communicate to it */ | 31 | * CSPI3 cs1, but we have no idea how to communicate to it */ |
@@ -43,17 +46,68 @@ static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)]; | |||
43 | static const char *mc13783_thread_name = "pmic"; | 46 | static const char *mc13783_thread_name = "pmic"; |
44 | static struct wakeup mc13783_wake; | 47 | static struct wakeup mc13783_wake; |
45 | 48 | ||
49 | /* The next two functions are rather target-specific but they'll just be left | ||
50 | * here for the moment */ | ||
46 | static __attribute__((noreturn)) void mc13783_interrupt_thread(void) | 51 | static __attribute__((noreturn)) void mc13783_interrupt_thread(void) |
47 | { | 52 | { |
53 | const unsigned char status_regs[2] = | ||
54 | { | ||
55 | MC13783_INTERRUPT_STATUS0, | ||
56 | MC13783_INTERRUPT_STATUS1, | ||
57 | }; | ||
58 | uint32_t pending[2]; | ||
59 | uint32_t value; | ||
60 | |||
61 | mc13783_read_regset(status_regs, pending, 2); | ||
62 | mc13783_write_regset(status_regs, pending, 2); | ||
63 | |||
64 | gpio_enable_event(MC13783_GPIO_NUM, MC13783_EVENT_ID); | ||
65 | |||
66 | /* Check initial states */ | ||
67 | value = mc13783_read(MC13783_INTERRUPT_SENSE1); | ||
68 | button_power_set_state((value & MC13783_ON1B) == 0); | ||
69 | set_headphones_inserted((value & MC13783_ON2B) == 0); | ||
70 | |||
71 | /* Enable desired PMIC interrupts */ | ||
72 | mc13783_clear(MC13783_INTERRUPT_MASK1, MC13783_ON1B | MC13783_ON2B); | ||
73 | |||
48 | while (1) | 74 | while (1) |
49 | { | 75 | { |
50 | wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK); | 76 | wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK); |
77 | |||
78 | mc13783_read_regset(status_regs, pending, 2); | ||
79 | mc13783_write_regset(status_regs, pending, 2); | ||
80 | |||
81 | #if 0 | ||
82 | if (pending[0]) | ||
83 | { | ||
84 | /* Handle ...PENDING0 */ | ||
85 | } | ||
86 | #endif | ||
87 | |||
88 | if (pending[1]) | ||
89 | { | ||
90 | /* Handle ...PENDING1 */ | ||
91 | if (pending[1] & (MC13783_ON1B | MC13783_ON2B)) | ||
92 | { | ||
93 | value = mc13783_read(MC13783_INTERRUPT_SENSE1); | ||
94 | |||
95 | if (pending[1] & MC13783_ON1B) | ||
96 | button_power_set_state((value & MC13783_ON1B) == 0); | ||
97 | |||
98 | if (pending[1] & MC13783_ON2B) | ||
99 | set_headphones_inserted((value & MC13783_ON2B) == 0); | ||
100 | } | ||
101 | } | ||
51 | } | 102 | } |
52 | } | 103 | } |
53 | 104 | ||
54 | static __attribute__((interrupt("IRQ"))) void mc13783_interrupt(void) | 105 | /* GPIO interrupt handler for mc13783 */ |
106 | int mc13783_event(void) | ||
55 | { | 107 | { |
108 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); | ||
56 | wakeup_signal(&mc13783_wake); | 109 | wakeup_signal(&mc13783_wake); |
110 | return 1; /* Yes, it's handled */ | ||
57 | } | 111 | } |
58 | 112 | ||
59 | void mc13783_init(void) | 113 | void mc13783_init(void) |
@@ -64,25 +118,44 @@ void mc13783_init(void) | |||
64 | /* Enable the PMIC SPI module */ | 118 | /* Enable the PMIC SPI module */ |
65 | spi_enable_module(&mc13783_spi); | 119 | spi_enable_module(&mc13783_spi); |
66 | 120 | ||
121 | /* Mask any PMIC interrupts for now - poll initial status in thread | ||
122 | * and enable them there */ | ||
123 | mc13783_write(MC13783_INTERRUPT_MASK0, 0xffffff); | ||
124 | mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff); | ||
125 | |||
126 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); | ||
127 | |||
67 | create_thread(mc13783_interrupt_thread, mc13783_thread_stack, | 128 | create_thread(mc13783_interrupt_thread, mc13783_thread_stack, |
68 | sizeof(mc13783_thread_stack), 0, mc13783_thread_name | 129 | sizeof(mc13783_thread_stack), 0, mc13783_thread_name |
69 | IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU)); | 130 | IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU)); |
70 | } | 131 | } |
71 | 132 | ||
72 | void mc13783_set(unsigned address, uint32_t bits) | 133 | uint32_t mc13783_set(unsigned address, uint32_t bits) |
73 | { | 134 | { |
74 | spi_lock(&mc13783_spi); | 135 | spi_lock(&mc13783_spi); |
136 | |||
75 | uint32_t data = mc13783_read(address); | 137 | uint32_t data = mc13783_read(address); |
76 | mc13783_write(address, data | bits); | 138 | |
139 | if (data != (uint32_t)-1) | ||
140 | mc13783_write(address, data | bits); | ||
141 | |||
77 | spi_unlock(&mc13783_spi); | 142 | spi_unlock(&mc13783_spi); |
143 | |||
144 | return data; | ||
78 | } | 145 | } |
79 | 146 | ||
80 | void mc13783_clear(unsigned address, uint32_t bits) | 147 | uint32_t mc13783_clear(unsigned address, uint32_t bits) |
81 | { | 148 | { |
82 | spi_lock(&mc13783_spi); | 149 | spi_lock(&mc13783_spi); |
150 | |||
83 | uint32_t data = mc13783_read(address); | 151 | uint32_t data = mc13783_read(address); |
84 | mc13783_write(address, data & ~bits); | 152 | |
153 | if (data != (uint32_t)-1) | ||
154 | mc13783_write(address, data & ~bits); | ||
155 | |||
85 | spi_unlock(&mc13783_spi); | 156 | spi_unlock(&mc13783_spi); |
157 | |||
158 | return data; | ||
86 | } | 159 | } |
87 | 160 | ||
88 | int mc13783_write(unsigned address, uint32_t data) | 161 | int mc13783_write(unsigned address, uint32_t data) |
@@ -108,7 +181,7 @@ int mc13783_write_multiple(unsigned start, const uint32_t *data, int count) | |||
108 | { | 181 | { |
109 | int i; | 182 | int i; |
110 | struct spi_transfer xfer; | 183 | struct spi_transfer xfer; |
111 | uint32_t packets[64]; | 184 | uint32_t packets[MC13783_NUM_REGS]; |
112 | 185 | ||
113 | if (start + count > MC13783_NUM_REGS) | 186 | if (start + count > MC13783_NUM_REGS) |
114 | return -1; | 187 | return -1; |
@@ -129,6 +202,36 @@ int mc13783_write_multiple(unsigned start, const uint32_t *data, int count) | |||
129 | return count - xfer.count; | 202 | return count - xfer.count; |
130 | } | 203 | } |
131 | 204 | ||
205 | int mc13783_write_regset(const unsigned char *regs, const uint32_t *data, | ||
206 | int count) | ||
207 | { | ||
208 | int i; | ||
209 | struct spi_transfer xfer; | ||
210 | uint32_t packets[MC13783_NUM_REGS]; | ||
211 | |||
212 | if (count > MC13783_NUM_REGS) | ||
213 | return -1; | ||
214 | |||
215 | for (i = 0; i < count; i++) | ||
216 | { | ||
217 | uint32_t reg = regs[i]; | ||
218 | |||
219 | if (reg >= MC13783_NUM_REGS) | ||
220 | return -1; | ||
221 | |||
222 | packets[i] = (1 << 31) | (reg << 25) | (data[i] & 0xffffff); | ||
223 | } | ||
224 | |||
225 | xfer.txbuf = packets; | ||
226 | xfer.rxbuf = packets; | ||
227 | xfer.count = count; | ||
228 | |||
229 | if (!spi_transfer(&mc13783_spi, &xfer)) | ||
230 | return -1; | ||
231 | |||
232 | return count - xfer.count; | ||
233 | } | ||
234 | |||
132 | uint32_t mc13783_read(unsigned address) | 235 | uint32_t mc13783_read(unsigned address) |
133 | { | 236 | { |
134 | uint32_t packet; | 237 | uint32_t packet; |
@@ -146,25 +249,53 @@ uint32_t mc13783_read(unsigned address) | |||
146 | if (!spi_transfer(&mc13783_spi, &xfer)) | 249 | if (!spi_transfer(&mc13783_spi, &xfer)) |
147 | return (uint32_t)-1; | 250 | return (uint32_t)-1; |
148 | 251 | ||
149 | return packet & 0xffffff; | 252 | return packet; |
150 | } | 253 | } |
151 | 254 | ||
152 | int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count) | 255 | int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count) |
153 | { | 256 | { |
154 | int i; | 257 | int i; |
155 | uint32_t packets[64]; | ||
156 | struct spi_transfer xfer; | 258 | struct spi_transfer xfer; |
157 | 259 | ||
158 | if (start + count > MC13783_NUM_REGS) | 260 | if (start + count > MC13783_NUM_REGS) |
159 | return -1; | 261 | return -1; |
160 | 262 | ||
161 | xfer.txbuf = packets; | 263 | xfer.txbuf = buffer; |
162 | xfer.rxbuf = buffer; | 264 | xfer.rxbuf = buffer; |
163 | xfer.count = count; | 265 | xfer.count = count; |
164 | 266 | ||
165 | /* Prepare TX payload */ | 267 | /* Prepare TX payload */ |
166 | for (i = 0; i < count; i++, start++) | 268 | for (i = 0; i < count; i++, start++) |
167 | packets[i] = start << 25; | 269 | buffer[i] = start << 25; |
270 | |||
271 | if (!spi_transfer(&mc13783_spi, &xfer)) | ||
272 | return -1; | ||
273 | |||
274 | return count - xfer.count; | ||
275 | } | ||
276 | |||
277 | int mc13783_read_regset(const unsigned char *regs, uint32_t *buffer, | ||
278 | int count) | ||
279 | { | ||
280 | int i; | ||
281 | struct spi_transfer xfer; | ||
282 | |||
283 | if (count > MC13783_NUM_REGS) | ||
284 | return -1; | ||
285 | |||
286 | for (i = 0; i < count; i++) | ||
287 | { | ||
288 | unsigned reg = regs[i]; | ||
289 | |||
290 | if (reg >= MC13783_NUM_REGS) | ||
291 | return -1; | ||
292 | |||
293 | buffer[i] = reg << 25; | ||
294 | } | ||
295 | |||
296 | xfer.txbuf = buffer; | ||
297 | xfer.rxbuf = buffer; | ||
298 | xfer.count = count; | ||
168 | 299 | ||
169 | if (!spi_transfer(&mc13783_spi, &xfer)) | 300 | if (!spi_transfer(&mc13783_spi, &xfer)) |
170 | return -1; | 301 | return -1; |