summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gigabeat-s
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s')
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/adc-imx31.c103
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/adc-target.h29
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c40
3 files changed, 129 insertions, 43 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c b/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c
index 1fd2247ef1..b1b79a7989 100644
--- a/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2006 by Wade Brown 10 * Copyright (C) 2008 by Michael Sevakis
11 * 11 *
12 * All files in this archive are subject to the GNU General Public License. 12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement. 13 * See the file COPYING in the source tree root for full license agreement.
@@ -16,37 +16,96 @@
16 * KIND, either express or implied. 16 * KIND, either express or implied.
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#include "cpu.h" 19#include "config.h"
20#include "system.h"
21#include "mc13783.h"
20#include "adc-target.h" 22#include "adc-target.h"
21#include "kernel.h" 23#include "kernel.h"
22 24
23/* prototypes */ 25/* Do this so we may read all channels in a single SPI message */
24static unsigned short __adc_read(int channel); 26static const unsigned char reg_array[NUM_ADC_CHANNELS/2] =
25static void adc_tick(void);
26
27void adc_init(void)
28{ 27{
29} 28 MC13783_ADC2,
29 MC13783_ADC2,
30 MC13783_ADC2,
31 MC13783_ADC2,
32 MC13783_ADC2,
33 MC13783_ADC2,
34 MC13783_ADC2,
35 MC13783_ADC2,
36};
30 37
31/* Called to get the recent ADC reading */ 38static uint32_t channels[2][NUM_ADC_CHANNELS/2];
32inline unsigned short adc_read(int channel) 39static struct wakeup adc_wake;
40static struct mutex adc_mtx;
41static long last_adc_read[2]; /* One for each input group */
42
43/* Read 10-bit ADC channel */
44unsigned short adc_read(int channel)
33{ 45{
34 (void)channel; 46 uint32_t data;
35 return 0; 47 int input_select;
48
49 if ((unsigned)channel >= NUM_ADC_CHANNELS)
50 return ADC_READ_ERROR;
51
52 mutex_lock(&adc_mtx);
53
54 input_select = channel >> 3;
55
56 /* Limit the traffic through here */
57 if (TIME_AFTER(current_tick, last_adc_read[input_select]))
58 {
59 /* Keep enable, start conversion, increment from channel 0,
60 * increment from channel 4 */
61 uint32_t adc1 = MC13783_ADEN | MC13783_ASC | MC13783_ADA1w(0) |
62 MC13783_ADA2w(4);
63
64 if (input_select == 1)
65 adc1 |= MC13783_ADSEL; /* 2nd set of inputs */
66
67 /* Start conversion */
68 mc13783_write(MC13783_ADC1, adc1);
69
70 /* Wait for done signal */
71 wakeup_wait(&adc_wake, TIMEOUT_BLOCK);
72
73 /* Read all 8 channels that are converted - two channels in each
74 * word. */
75 mc13783_read_regset(reg_array, channels[input_select],
76 NUM_ADC_CHANNELS/2);
77
78 last_adc_read[input_select] = current_tick;
79 }
80
81 data = channels[input_select][channel & 7];
82
83 mutex_unlock(&adc_mtx);
84
85 /* Extract the bitfield depending on even or odd channel number */
86 return (channel & 1) ? MC13783_ADD2r(data) : MC13783_ADD1r(data);
36} 87}
37 88
38/** 89/* Called when conversion is complete */
39 * Read the ADC by polling 90void adc_done(void)
40 * @param channel The ADC channel to read
41 * @return 10bit reading from ADC channel or ADC_READ_ERROR if timeout
42 */
43static unsigned short __adc_read(int channel)
44{ 91{
45 (void)channel; 92 wakeup_signal(&adc_wake);
46 return 0;
47} 93}
48 94
49/* add this to the tick so that the ADC converts are done in the background */ 95void adc_init(void)
50static void adc_tick(void)
51{ 96{
97 wakeup_init(&adc_wake);
98 mutex_init(&adc_mtx);
99
100 /* Init so first reads get data */
101 last_adc_read[0] = last_adc_read[1] = current_tick-1;
102
103 /* Enable increment-by-read, thermistor */
104 mc13783_write(MC13783_ADC0, MC13783_ADINC2 | MC13783_ADINC1 |
105 MC13783_RTHEN);
106 /* Enable ADC, set multi-channel mode */
107 mc13783_write(MC13783_ADC1, MC13783_ADEN);
108 /* Enable the ADCDONE interrupt - notifications are dispatched by
109 * event handler. */
110 mc13783_clear(MC13783_INTERRUPT_MASK0, MC13783_ADCDONE);
52} 111}
diff --git a/firmware/target/arm/imx31/gigabeat-s/adc-target.h b/firmware/target/arm/imx31/gigabeat-s/adc-target.h
index 8d2beaf320..6b066b0b59 100644
--- a/firmware/target/arm/imx31/gigabeat-s/adc-target.h
+++ b/firmware/target/arm/imx31/gigabeat-s/adc-target.h
@@ -20,18 +20,29 @@
20#define _ADC_TARGET_H_ 20#define _ADC_TARGET_H_
21 21
22/* only two channels used by the Gigabeat */ 22/* only two channels used by the Gigabeat */
23#define NUM_ADC_CHANNELS 2 23#define NUM_ADC_CHANNELS 16
24
25#define ADC_BATTERY 0
26#define ADC_UNKNOWN_1 1
27#define ADC_UNKNOWN_2 2
28#define ADC_UNKNOWN_3 3
29#define ADC_UNKNOWN_4 4
30#define ADC_UNKNOWN_5 5
31#define ADC_UNKNOWN_6 6
32#define ADC_UNKNOWN_7 7
33#define ADC_HPREMOTE 8
34#define ADC_UNKNOWN_9 9
35#define ADC_UNKNOWN_10 10
36#define ADC_UNKNOWN_11 11
37#define ADC_UNKNOWN_12 12
38#define ADC_UNKNOWN_13 13
39#define ADC_UNKNOWN_14 14
40#define ADC_UNKNOWN_15 15
24 41
25#define ADC_BATTERY 0
26#define ADC_HPREMOTE 1
27#define ADC_UNKNOWN_3 2
28#define ADC_UNKNOWN_4 3
29#define ADC_UNKNOWN_5 4
30#define ADC_UNKNOWN_6 5
31#define ADC_UNKNOWN_7 6
32#define ADC_UNKNOWN_8 7
33 42
34#define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */ 43#define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */
35#define ADC_READ_ERROR 0xFFFF 44#define ADC_READ_ERROR 0xFFFF
36 45
46void adc_done(void);
47
37#endif 48#endif
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c
index fdb214a33d..d62df92ac5 100644
--- a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c
@@ -26,6 +26,7 @@
26 26
27#include "power-imx31.h" 27#include "power-imx31.h"
28#include "button-target.h" 28#include "button-target.h"
29#include "adc-target.h"
29 30
30/* This is all based on communicating with the MC13783 PMU which is on 31/* This is all based on communicating with the MC13783 PMU which is on
31 * CSPI2 with the chip select at 0. The LCD controller resides on 32 * CSPI2 with the chip select at 0. The LCD controller resides on
@@ -64,17 +65,21 @@ static __attribute__((noreturn)) void mc13783_interrupt_thread(void)
64 65
65 gpio_enable_event(MC13783_GPIO_NUM, MC13783_EVENT_ID); 66 gpio_enable_event(MC13783_GPIO_NUM, MC13783_EVENT_ID);
66 67
67 /* Check initial states */ 68 /* Check initial states for events with a sense bit */
68 value = mc13783_read(MC13783_INTERRUPT_SENSE0); 69 value = mc13783_read(MC13783_INTERRUPT_SENSE0);
69 set_charger_inserted(value & MC13783_CHGDET); 70 set_charger_inserted(value & MC13783_CHGDET);
70 71
71 value = mc13783_read(MC13783_INTERRUPT_SENSE1); 72 value = mc13783_read(MC13783_INTERRUPT_SENSE1);
72 button_power_set_state((value & MC13783_ON1B) == 0); 73 button_power_set_state((value & MC13783_ONOFD1) == 0);
73 set_headphones_inserted((value & MC13783_ON2B) == 0); 74 set_headphones_inserted((value & MC13783_ONOFD2) == 0);
74 75
75 /* Enable desired PMIC interrupts */ 76 pending[0] = pending[1] = 0xffffff;
77 mc13783_write_regset(status_regs, pending, 2);
78
79 /* Enable desired PMIC interrupts - some are unmasked in the drivers that
80 * handle a specific task */
76 mc13783_clear(MC13783_INTERRUPT_MASK0, MC13783_CHGDET); 81 mc13783_clear(MC13783_INTERRUPT_MASK0, MC13783_CHGDET);
77 mc13783_clear(MC13783_INTERRUPT_MASK1, MC13783_ON1B | MC13783_ON2B); 82 mc13783_clear(MC13783_INTERRUPT_MASK1, MC13783_ONOFD1 | MC13783_ONOFD2);
78 83
79 while (1) 84 while (1)
80 { 85 {
@@ -83,10 +88,16 @@ static __attribute__((noreturn)) void mc13783_interrupt_thread(void)
83 mc13783_read_regset(status_regs, pending, 2); 88 mc13783_read_regset(status_regs, pending, 2);
84 mc13783_write_regset(status_regs, pending, 2); 89 mc13783_write_regset(status_regs, pending, 2);
85 90
86
87 if (pending[0]) 91 if (pending[0])
88 { 92 {
89 /* Handle ...PENDING0 */ 93 /* Handle ...PENDING0 */
94
95 /* Handle interrupts without a sense bit */
96 if (pending[0] & MC13783_ADCDONE)
97 adc_done();
98
99 /* Handle interrupts that have a sense bit that needs to
100 * be checked */
90 if (pending[0] & MC13783_CHGDET) 101 if (pending[0] & MC13783_CHGDET)
91 { 102 {
92 value = mc13783_read(MC13783_INTERRUPT_SENSE0); 103 value = mc13783_read(MC13783_INTERRUPT_SENSE0);
@@ -96,19 +107,24 @@ static __attribute__((noreturn)) void mc13783_interrupt_thread(void)
96 } 107 }
97 } 108 }
98 109
99
100 if (pending[1]) 110 if (pending[1])
101 { 111 {
102 /* Handle ...PENDING1 */ 112 /* Handle ...PENDING1 */
103 if (pending[1] & (MC13783_ON1B | MC13783_ON2B)) 113
114 /* Handle interrupts without a sense bit */
115 /* ... */
116
117 /* Handle interrupts that have a sense bit that needs to
118 * be checked */
119 if (pending[1] & (MC13783_ONOFD1 | MC13783_ONOFD2))
104 { 120 {
105 value = mc13783_read(MC13783_INTERRUPT_SENSE1); 121 value = mc13783_read(MC13783_INTERRUPT_SENSE1);
106 122
107 if (pending[1] & MC13783_ON1B) 123 if (pending[1] & MC13783_ONOFD1)
108 button_power_set_state((value & MC13783_ON1B) == 0); 124 button_power_set_state((value & MC13783_ONOFD1) == 0);
109 125
110 if (pending[1] & MC13783_ON2B) 126 if (pending[1] & MC13783_ONOFD2)
111 set_headphones_inserted((value & MC13783_ON2B) == 0); 127 set_headphones_inserted((value & MC13783_ONOFD2) == 0);
112 } 128 }
113 } 129 }
114 } 130 }