diff options
-rw-r--r-- | firmware/target/arm/as3525/kernel-as3525.c | 122 | ||||
-rw-r--r-- | firmware/target/arm/as3525/sansa-c200v2/backlight-c200v2.c | 37 | ||||
-rw-r--r-- | firmware/target/arm/as3525/sansa-c200v2/backlight-target.h | 7 |
3 files changed, 161 insertions, 5 deletions
diff --git a/firmware/target/arm/as3525/kernel-as3525.c b/firmware/target/arm/as3525/kernel-as3525.c index 9250f320b9..4c421e50fc 100644 --- a/firmware/target/arm/as3525/kernel-as3525.c +++ b/firmware/target/arm/as3525/kernel-as3525.c | |||
@@ -36,7 +36,7 @@ | |||
36 | /* The scrollwheel is polled every 5 ms (the tick tasks only every 10) */ | 36 | /* The scrollwheel is polled every 5 ms (the tick tasks only every 10) */ |
37 | static int poll_scrollwheel = 0; | 37 | static int poll_scrollwheel = 0; |
38 | 38 | ||
39 | void INT_TIMER2(void) | 39 | static inline void do_scrollwheel(void) |
40 | { | 40 | { |
41 | if (!poll_scrollwheel) | 41 | if (!poll_scrollwheel) |
42 | call_tick_tasks(); /* Run through the list of tick tasks | 42 | call_tick_tasks(); /* Run through the list of tick tasks |
@@ -48,16 +48,131 @@ void INT_TIMER2(void) | |||
48 | } | 48 | } |
49 | 49 | ||
50 | poll_scrollwheel ^= 1; | 50 | poll_scrollwheel ^= 1; |
51 | } | ||
52 | #else | ||
53 | static inline void do_scrollwheel(void) | ||
54 | { | ||
55 | call_tick_tasks(); /* Run through the list of tick tasks */ | ||
56 | } | ||
57 | #endif | ||
58 | |||
59 | #if defined(SANSA_C200V2) | ||
60 | #include "backlight-target.h" | ||
61 | |||
62 | static int timer2_cycles_per_tick = 0; | ||
63 | static int timer2_cycles_pwmon = 0; | ||
64 | static int timer2_cycles_pwmoff = 0; | ||
65 | static int timer2_pwm_state = 0; | ||
66 | static int timer2_pwm_on = 0; | ||
67 | |||
68 | void _set_timer2_pwm_ratio(int ratio) | ||
69 | { | ||
70 | int cycles = timer2_cycles_per_tick; | ||
71 | |||
72 | /* | ||
73 | * Rather arbitrary limits, but since the CPU | ||
74 | * needs some to time in the interrupt handler | ||
75 | * there sure is some limit. | ||
76 | * More specifically, if the cycles needed to do | ||
77 | * the pwm handling are more than the reloaded counter needs | ||
78 | * to reach 0 again it will reload to the old value most | ||
79 | * likely leading to a (slight) slowdown in tick rate. | ||
80 | */ | ||
81 | |||
82 | if (ratio < 10) { | ||
83 | /* | ||
84 | * Permanent off, reduce interrupt rate to save power | ||
85 | */ | ||
86 | TIMER2_BGLOAD = cycles; | ||
87 | timer2_pwm_on = 0; | ||
88 | _backlight_pwm(0); | ||
89 | return; | ||
90 | } | ||
91 | |||
92 | if (ratio > 990) { | ||
93 | /* | ||
94 | * Permanent on, reduce interrupt rate to save power | ||
95 | */ | ||
96 | TIMER2_BGLOAD = cycles; | ||
97 | timer2_pwm_on = 0; | ||
98 | _backlight_pwm(1); | ||
99 | return; | ||
100 | } | ||
101 | |||
102 | timer2_cycles_pwmon = cycles*ratio/1000; | ||
103 | timer2_cycles_pwmoff = cycles*(1000-ratio)/1000; | ||
104 | |||
105 | if (timer2_pwm_on == 0) { | ||
106 | timer2_pwm_state = 0; | ||
107 | timer2_pwm_on = 1; | ||
108 | TIMER2_BGLOAD = timer2_cycles_pwmoff; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | static void set_timer2_cycles_per_tick(int cycles) | ||
113 | { | ||
114 | timer2_cycles_per_tick = cycles; | ||
115 | } | ||
116 | |||
117 | static inline void do_sw_pwm(void) | ||
118 | { | ||
119 | if (!timer2_pwm_on) { | ||
120 | do_scrollwheel(); /* Handle scrollwheel and tick tasks */ | ||
121 | TIMER2_INTCLR = 0; /* clear interrupt */ | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | timer2_pwm_state ^= 1; | ||
126 | if (timer2_pwm_state) { | ||
127 | TIMER2_BGLOAD = timer2_cycles_pwmoff; | ||
128 | _backlight_pwm(1); | ||
129 | /* | ||
130 | * Always do scrollwheel and tick tasks during the longer cycle for safety, | ||
131 | * since the short cycle can be quite short. | ||
132 | * (minimum: 1us if ratio is 10 or 990 or 0.5us with scrollwheel, | ||
133 | * or just about 6000 clock cycles at 60MHz) | ||
134 | */ | ||
135 | if (timer2_cycles_pwmon > timer2_cycles_pwmoff) | ||
136 | do_scrollwheel(); /* Handle scrollwheel and tick tasks */ | ||
137 | } else { | ||
138 | TIMER2_BGLOAD = timer2_cycles_pwmon; | ||
139 | _backlight_pwm(0); | ||
140 | if (!(timer2_cycles_pwmon > timer2_cycles_pwmoff)) | ||
141 | do_scrollwheel(); /* Handle scrollwheel and tick tasks */ | ||
142 | } | ||
143 | |||
51 | TIMER2_INTCLR = 0; /* clear interrupt */ | 144 | TIMER2_INTCLR = 0; /* clear interrupt */ |
52 | } | 145 | } |
53 | #else | 146 | #else |
147 | static inline void do_sw_pwm(void) | ||
148 | { | ||
149 | do_scrollwheel(); /* Handle scrollwheel and tick tasks */ | ||
150 | } | ||
151 | |||
152 | static void set_timer2_cycles_per_tick(int cycles) | ||
153 | { | ||
154 | (void)cycles; | ||
155 | } | ||
156 | #endif | ||
157 | |||
158 | |||
54 | void INT_TIMER2(void) | 159 | void INT_TIMER2(void) |
55 | { | 160 | { |
56 | call_tick_tasks(); /* Run through the list of tick tasks */ | 161 | /* |
162 | * Timer is stacked as follows: | ||
163 | * Lowest layer: Software PWM (if configured) | ||
164 | * Alternates timer2 reload value to implement | ||
165 | * software pwm at 100Hz (no scrollwheel) | ||
166 | * or 200Hz (scrollwheel) with variable pulse width 1% to 99% | ||
167 | * Middle layer: Scrollwheel handling (if configured, 200Hz) | ||
168 | * Alternate between polling scrollwheel and running tick | ||
169 | * tasks (includes scrollwheel polling). | ||
170 | * Top layer: Run tick tasks at 100Hz | ||
171 | */ | ||
172 | do_sw_pwm(); | ||
57 | 173 | ||
58 | TIMER2_INTCLR = 0; /* clear interrupt */ | 174 | TIMER2_INTCLR = 0; /* clear interrupt */ |
59 | } | 175 | } |
60 | #endif | ||
61 | 176 | ||
62 | void tick_start(unsigned int interval_in_ms) | 177 | void tick_start(unsigned int interval_in_ms) |
63 | { | 178 | { |
@@ -66,6 +181,7 @@ void tick_start(unsigned int interval_in_ms) | |||
66 | CGU_PERI |= CGU_TIMER2_CLOCK_ENABLE; /* enable peripheral */ | 181 | CGU_PERI |= CGU_TIMER2_CLOCK_ENABLE; /* enable peripheral */ |
67 | VIC_INT_ENABLE = INTERRUPT_TIMER2; /* enable interrupt */ | 182 | VIC_INT_ENABLE = INTERRUPT_TIMER2; /* enable interrupt */ |
68 | 183 | ||
184 | set_timer2_cycles_per_tick(cycles); | ||
69 | TIMER2_LOAD = TIMER2_BGLOAD = cycles; /* timer period */ | 185 | TIMER2_LOAD = TIMER2_BGLOAD = cycles; /* timer period */ |
70 | 186 | ||
71 | /* /!\ bit 4 (reserved) must not be modified | 187 | /* /!\ bit 4 (reserved) must not be modified |
diff --git a/firmware/target/arm/as3525/sansa-c200v2/backlight-c200v2.c b/firmware/target/arm/as3525/sansa-c200v2/backlight-c200v2.c index d38c068ca2..e094cca8fe 100644 --- a/firmware/target/arm/as3525/sansa-c200v2/backlight-c200v2.c +++ b/firmware/target/arm/as3525/sansa-c200v2/backlight-c200v2.c | |||
@@ -27,6 +27,32 @@ | |||
27 | #include "as3514.h" | 27 | #include "as3514.h" |
28 | 28 | ||
29 | int buttonlight_is_on = 0; | 29 | int buttonlight_is_on = 0; |
30 | int backlight_is_on = 0; | ||
31 | static int backlight_level = 0; | ||
32 | |||
33 | /* logarithmic lookup table for brightness s*/ | ||
34 | static const int brightness_table[MAX_BRIGHTNESS_SETTING+1] = { | ||
35 | 0, 21, 47, 78, 118, 165, 224, 296, 386, 495, 630, 796, 1000 | ||
36 | }; | ||
37 | |||
38 | static void _ll_backlight_on(void) | ||
39 | { | ||
40 | GPIOA_PIN(5) = 1<<5; | ||
41 | } | ||
42 | |||
43 | static void _ll_backlight_off(void) | ||
44 | { | ||
45 | GPIOA_PIN(5) = 0; | ||
46 | } | ||
47 | |||
48 | void _backlight_pwm(int on) | ||
49 | { | ||
50 | if (on) { | ||
51 | _ll_backlight_on(); | ||
52 | } else { | ||
53 | _ll_backlight_off(); | ||
54 | } | ||
55 | } | ||
30 | 56 | ||
31 | bool _backlight_init(void) | 57 | bool _backlight_init(void) |
32 | { | 58 | { |
@@ -36,6 +62,8 @@ bool _backlight_init(void) | |||
36 | 62 | ||
37 | void _backlight_set_brightness(int brightness) | 63 | void _backlight_set_brightness(int brightness) |
38 | { | 64 | { |
65 | backlight_level = brightness_table[brightness]; | ||
66 | |||
39 | if (brightness > 0) | 67 | if (brightness > 0) |
40 | _backlight_on(); | 68 | _backlight_on(); |
41 | else | 69 | else |
@@ -47,12 +75,17 @@ void _backlight_on(void) | |||
47 | #ifdef HAVE_LCD_ENABLE | 75 | #ifdef HAVE_LCD_ENABLE |
48 | lcd_enable(true); /* power on lcd + visible display */ | 76 | lcd_enable(true); /* power on lcd + visible display */ |
49 | #endif | 77 | #endif |
50 | GPIOA_PIN(5) = 1<<5; | 78 | if (!backlight_is_on) |
79 | _ll_backlight_on(); | ||
80 | _set_timer2_pwm_ratio(backlight_level); | ||
81 | backlight_is_on = 1; | ||
51 | } | 82 | } |
52 | 83 | ||
53 | void _backlight_off(void) | 84 | void _backlight_off(void) |
54 | { | 85 | { |
55 | GPIOA_PIN(5) = 0; | 86 | backlight_is_on = 0; |
87 | _set_timer2_pwm_ratio(0); | ||
88 | _ll_backlight_off(); | ||
56 | #ifdef HAVE_LCD_ENABLE | 89 | #ifdef HAVE_LCD_ENABLE |
57 | lcd_enable(false); /* power off visible display */ | 90 | lcd_enable(false); /* power off visible display */ |
58 | #endif | 91 | #endif |
diff --git a/firmware/target/arm/as3525/sansa-c200v2/backlight-target.h b/firmware/target/arm/as3525/sansa-c200v2/backlight-target.h index 84a6ea6179..c09e759138 100644 --- a/firmware/target/arm/as3525/sansa-c200v2/backlight-target.h +++ b/firmware/target/arm/as3525/sansa-c200v2/backlight-target.h | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <stdbool.h> | 24 | #include <stdbool.h> |
25 | 25 | ||
26 | bool _backlight_init(void); | 26 | bool _backlight_init(void); |
27 | void _backlight_pwm(int on); | ||
27 | void _backlight_on(void); | 28 | void _backlight_on(void); |
28 | void _backlight_off(void); | 29 | void _backlight_off(void); |
29 | void _backlight_set_brightness(int brightness); | 30 | void _backlight_set_brightness(int brightness); |
@@ -31,4 +32,10 @@ int __backlight_is_on(void); | |||
31 | 32 | ||
32 | void _buttonlight_on(void); | 33 | void _buttonlight_on(void); |
33 | void _buttonlight_off(void); | 34 | void _buttonlight_off(void); |
35 | |||
36 | /* | ||
37 | * FIXME: This may be better off in kernel.h, but... | ||
38 | */ | ||
39 | void _set_timer2_pwm_ratio(int ratio); | ||
40 | |||
34 | #endif | 41 | #endif |