blob: 436c71105a90c0bf23d718546ee693bb8a517a48 [file] [log] [blame]
Linus Nielsen Feltzingf7256412002-06-30 20:22:25 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "config.h"
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +000020#include "cpu.h"
Linus Nielsen Feltzing192a6042005-07-12 07:25:01 +000021#include "system.h"
Linus Nielsen Feltzingf7256412002-06-30 20:22:25 +000022#include "kernel.h"
23#include "thread.h"
Brandon Lowa9157712006-03-06 15:25:26 +000024#include "string.h"
Linus Nielsen Feltzingf7256412002-06-30 20:22:25 +000025#include "adc.h"
Brandon Low63c0d1d2006-03-05 18:06:06 +000026#include "pcf50605.h"
Linus Nielsen Feltzing91c48732005-11-16 13:28:10 +000027#include "pcf50606.h"
Linus Nielsen Feltzingf7256412002-06-30 20:22:25 +000028
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +000029#if CONFIG_CPU == SH7034
Linus Nielsen Feltzingddb63332004-09-21 08:59:36 +000030/**************************************************************************
31 ** The A/D conversion is done every tick, in three steps:
32 **
33 ** 1) On the tick interrupt, the conversion of channels 0-3 is started, and
34 ** the A/D interrupt is enabled.
35 **
36 ** 2) After the conversion is done (approx. 256*4 cycles later), an interrupt
37 ** is generated at level 1, which is the same level as the tick interrupt
38 ** itself. This interrupt will be pending until the tick interrupt is
39 ** finished.
40 ** When the A/D interrupt is finally served, it will read the results
41 ** from the first conversion and start the conversion of channels 4-7.
42 **
43 ** 3) When the conversion of channels 4-7 is finished, the interrupt is
44 ** triggered again, and the results are read. This time, no new
45 ** conversion is started, it will be done in the next tick interrupt.
46 **
47 ** Thus, each channel will be updated HZ times per second.
48 **
49 *************************************************************************/
50
Linus Nielsen Feltzing26f42602004-01-20 11:57:50 +000051static int current_channel;
Linus Nielsen Feltzingf7256412002-06-30 20:22:25 +000052static unsigned short adcdata[NUM_ADC_CHANNELS];
Linus Nielsen Feltzingf7256412002-06-30 20:22:25 +000053
54static void adc_tick(void)
55{
Linus Nielsen Feltzingddb63332004-09-21 08:59:36 +000056 /* Start a conversion of channel group 0. This will trigger an interrupt,
57 and the interrupt handler will take care of group 1. */
Linus Nielsen Feltzingf7256412002-06-30 20:22:25 +000058
Linus Nielsen Feltzingddb63332004-09-21 08:59:36 +000059 current_channel = 0;
60 ADCSR = ADCSR_ADST | ADCSR_ADIE | ADCSR_SCAN | 3;
61}
62
Jens Arnolda7c20ac2006-04-26 20:22:27 +000063void ADITI(void) __attribute__((interrupt_handler));
Linus Nielsen Feltzingddb63332004-09-21 08:59:36 +000064void ADITI(void)
65{
66 if(ADCSR & ADCSR_ADF)
67 {
68 ADCSR = 0;
69
70 if(current_channel == 0)
71 {
72 adcdata[0] = ADDRA >> 6;
73 adcdata[1] = ADDRB >> 6;
74 adcdata[2] = ADDRC >> 6;
75 adcdata[3] = ADDRD >> 6;
76 current_channel = 4;
77
78 /* Convert the next group */
79 ADCSR = ADCSR_ADST | ADCSR_ADIE | ADCSR_SCAN | 7;
80 }
81 else
82 {
83 adcdata[4] = ADDRA >> 6;
84 adcdata[5] = ADDRB >> 6;
85 adcdata[6] = ADDRC >> 6;
86 adcdata[7] = ADDRD >> 6;
87 }
88 }
Linus Nielsen Feltzingf7256412002-06-30 20:22:25 +000089}
90
91unsigned short adc_read(int channel)
92{
93 return adcdata[channel];
94}
95
Linus Nielsen Feltzing26f42602004-01-20 11:57:50 +000096void adc_init(void)
97{
Linus Nielsen Feltzingddb63332004-09-21 08:59:36 +000098 ADCR = 0x7f; /* No external trigger; other bits should be 1 according
99 to the manual... */
Linus Nielsen Feltzing26f42602004-01-20 11:57:50 +0000100
Linus Nielsen Feltzingddb63332004-09-21 08:59:36 +0000101 ADCSR = 0;
102
Linus Nielsen Feltzing26f42602004-01-20 11:57:50 +0000103 current_channel = 0;
104
Linus Nielsen Feltzingddb63332004-09-21 08:59:36 +0000105 /* Enable the A/D IRQ on level 1 */
106 IPRE = (IPRE & 0xf0ff) | 0x0100;
Jörg Hohensohnd8a4bf32003-07-16 21:07:53 +0000107
Linus Nielsen Feltzingf7256412002-06-30 20:22:25 +0000108 tick_add_task(adc_tick);
Jens Arnoldaf33f252004-09-24 22:26:16 +0000109
Linus Nielsen Feltzinge29e91e2004-10-01 06:05:22 +0000110 sleep(2); /* Ensure valid readings when adc_init returns */
Linus Nielsen Feltzingf7256412002-06-30 20:22:25 +0000111}
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +0000112#elif CONFIG_CPU == MCF5249
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +0000113static unsigned char adcdata[NUM_ADC_CHANNELS];
114
Linus Nielsen Feltzing91c48732005-11-16 13:28:10 +0000115#ifdef IRIVER_H300_SERIES
116static int channelnum[] =
117{
Linus Nielsen Feltzing00811842006-02-17 22:38:38 +0000118 5, /* ADC_BUTTONS (ADCIN2) */
119 6, /* ADC_REMOTE (ADCIN3) */
120 0, /* ADC_BATTERY (BATVOLT, resistive divider) */
121 2, /* ADC_REMOTEDETECT (ADCIN1, resistive divider) */
Linus Nielsen Feltzing91c48732005-11-16 13:28:10 +0000122};
123
Brandon Low63c0d1d2006-03-05 18:06:06 +0000124unsigned short adc_scan(int channel)
Linus Nielsen Feltzing91c48732005-11-16 13:28:10 +0000125{
126 unsigned char data;
127
128 pcf50606_write(0x2f, 0x80 | (channelnum[channel] << 1) | 1);
129 data = pcf50606_read(0x30);
130
131 adcdata[channel] = data;
132
133 return data;
134}
135#else
136
Linus Nielsen Feltzingb3437ec2005-07-12 12:16:17 +0000137#define CS_LO and_l(~0x80, &GPIO_OUT)
138#define CS_HI or_l(0x80, &GPIO_OUT)
Linus Nielsen Feltzing192a6042005-07-12 07:25:01 +0000139#define CLK_LO and_l(~0x00400000, &GPIO_OUT)
140#define CLK_HI or_l(0x00400000, &GPIO_OUT)
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +0000141#define DO (GPIO_READ & 0x80000000)
Linus Nielsen Feltzing192a6042005-07-12 07:25:01 +0000142#define DI_LO and_l(~0x00200000, &GPIO_OUT)
143#define DI_HI or_l(0x00200000, &GPIO_OUT)
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +0000144
145/* delay loop */
146#define DELAY do { int _x; for(_x=0;_x<10;_x++);} while (0)
147
Brandon Low63c0d1d2006-03-05 18:06:06 +0000148unsigned short adc_scan(int channel)
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +0000149{
150 unsigned char data = 0;
151 int i;
152
153 CS_LO;
154
155 DI_HI; /* Start bit */
156 DELAY;
157 CLK_HI;
158 DELAY;
159 CLK_LO;
160
161 DI_HI; /* Single channel */
162 DELAY;
163 CLK_HI;
164 DELAY;
165 CLK_LO;
166
167 if(channel & 1) /* LSB of channel number */
168 DI_HI;
169 else
170 DI_LO;
171 DELAY;
172 CLK_HI;
173 DELAY;
174 CLK_LO;
175
176 if(channel & 2) /* MSB of channel number */
177 DI_HI;
178 else
179 DI_LO;
180 DELAY;
181 CLK_HI;
182 DELAY;
183 CLK_LO;
184
185 DELAY;
186
187 for(i = 0;i < 8;i++) /* 8 bits of data */
188 {
189 CLK_HI;
190 DELAY;
191 CLK_LO;
192 DELAY;
193 data <<= 1;
194 data |= DO?1:0;
195 }
196
197 CS_HI;
198
Linus Nielsen Feltzingf48ec1f2005-02-11 13:13:36 +0000199 adcdata[channel] = data;
200
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +0000201 return data;
202}
Linus Nielsen Feltzing91c48732005-11-16 13:28:10 +0000203#endif
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +0000204
205unsigned short adc_read(int channel)
206{
207 return adcdata[channel];
208}
209
Linus Nielsen Feltzing003247e2004-11-18 23:23:47 +0000210static int adc_counter;
211
212static void adc_tick(void)
213{
214 if(++adc_counter == HZ)
215 {
216 adc_counter = 0;
Linus Nielsen Feltzingf48ec1f2005-02-11 13:13:36 +0000217 adc_scan(ADC_BATTERY);
Linus Nielsen Feltzing00811842006-02-17 22:38:38 +0000218 adc_scan(ADC_REMOTEDETECT); /* Temporary. Remove when the remote
219 detection feels stable. */
Linus Nielsen Feltzing003247e2004-11-18 23:23:47 +0000220 }
221}
222
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +0000223void adc_init(void)
224{
Brandon Low63c0d1d2006-03-05 18:06:06 +0000225#ifndef IRIVER_H300_SERIES
Linus Nielsen Feltzing192a6042005-07-12 07:25:01 +0000226 or_l(0x80600080, &GPIO_FUNCTION); /* GPIO7: CS
227 GPIO21: Data In (to the ADC)
228 GPIO22: CLK
229 GPIO31: Data Out (from the ADC) */
230 or_l(0x00600080, &GPIO_ENABLE);
231 or_l(0x80, &GPIO_OUT); /* CS high */
232 and_l(~0x00400000, &GPIO_OUT); /* CLK low */
Linus Nielsen Feltzing91c48732005-11-16 13:28:10 +0000233#endif
Linus Nielsen Feltzing003247e2004-11-18 23:23:47 +0000234
Linus Nielsen Feltzing43bf39e2005-04-06 23:53:19 +0000235 adc_scan(ADC_BATTERY);
236
Linus Nielsen Feltzing003247e2004-11-18 23:23:47 +0000237 tick_add_task(adc_tick);
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +0000238}
239
Daniel Stenberg00328982005-01-09 23:26:39 +0000240#elif CONFIG_CPU == TCC730
241
242
243/**************************************************************************
244 **
245 ** Each channel will be updated HZ/CHANNEL_ORDER_SIZE times per second.
246 **
247 *************************************************************************/
248
249static int current_channel;
250static int current_channel_idx;
251static unsigned short adcdata[NUM_ADC_CHANNELS];
252
253#define CHANNEL_ORDER_SIZE 2
254static int channel_order[CHANNEL_ORDER_SIZE] = {6,7};
255
256static void adc_tick(void)
257{
258 if (ADCON & (1 << 3)) {
259 /* previous conversion finished? */
260 adcdata[current_channel] = ADDATA >> 6;
Daniel Stenberg00328982005-01-09 23:26:39 +0000261 if (++current_channel_idx >= CHANNEL_ORDER_SIZE)
262 current_channel_idx = 0;
263 current_channel = channel_order[current_channel_idx];
264 int adcon = (current_channel << 4) | 1;
265 ADCON = adcon;
266 }
267}
268
269unsigned short adc_read(int channel)
270{
271 return adcdata[channel];
272}
273
274void adc_init(void)
275{
276 current_channel_idx = 0;
277 current_channel = channel_order[current_channel_idx];
278
279 ADCON = (current_channel << 4) | 1;
280
281 tick_add_task(adc_tick);
282
283 sleep(2); /* Ensure valid readings when adc_init returns */
284}
285
Brandon Lowb4d495c2006-03-23 03:48:48 +0000286#elif (CONFIG_CPU == PP5020) || (CONFIG_CPU == PP5002)
Dave Chapman77372d12005-11-07 23:07:19 +0000287
Brandon Low63c0d1d2006-03-05 18:06:06 +0000288struct adc_struct {
Brandon Low19f4c2a2006-03-09 19:47:12 +0000289 long timeout;
290 void (*conversion)(unsigned short *data);
Brandon Lowa9157712006-03-06 15:25:26 +0000291 short channelnum;
Brandon Low63c0d1d2006-03-05 18:06:06 +0000292 unsigned short data;
293};
294
Brandon Lowa9157712006-03-06 15:25:26 +0000295static struct adc_struct adcdata[NUM_ADC_CHANNELS] IDATA_ATTR;
Brandon Low63c0d1d2006-03-05 18:06:06 +0000296
Brandon Low19f4c2a2006-03-09 19:47:12 +0000297static unsigned short _adc_read(struct adc_struct *adc)
Brandon Low63c0d1d2006-03-05 18:06:06 +0000298{
Brandon Low19f4c2a2006-03-09 19:47:12 +0000299 if (adc->timeout < current_tick) {
300 unsigned char data[2];
301 unsigned short value;
302 /* 5x per 2 seconds */
303 adc->timeout = current_tick + (HZ * 2 / 5);
Brandon Lowca9e8b62006-03-09 01:36:22 +0000304
Brandon Low19f4c2a2006-03-09 19:47:12 +0000305 /* ADCC1, 10 bit, start */
306 pcf50605_write(0x2f, (adc->channelnum << 1) | 0x1);
307 pcf50605_read_multiple(0x30, data, 2); /* ADCS1, ADCS2 */
308 value = data[0];
309 value <<= 2;
310 value |= data[1] & 0x3;
Brandon Lowca9e8b62006-03-09 01:36:22 +0000311
Brandon Low19f4c2a2006-03-09 19:47:12 +0000312 if (adc->conversion) {
313 adc->conversion(&value);
314 }
315 adc->data = value;
316 return value;
Brandon Low63c0d1d2006-03-05 18:06:06 +0000317 } else {
Brandon Lowa9157712006-03-06 15:25:26 +0000318 return adc->data;
Brandon Low63c0d1d2006-03-05 18:06:06 +0000319 }
Dave Chapman77372d12005-11-07 23:07:19 +0000320}
321
Brandon Low19f4c2a2006-03-09 19:47:12 +0000322/* Force an ADC scan _now_ */
323unsigned short adc_scan(int channel) {
324 struct adc_struct *adc = &adcdata[channel];
325 adc->timeout = 0;
326 return _adc_read(adc);
327}
328
329/* Retrieve the ADC value, only does a scan periodically */
330unsigned short adc_read(int channel) {
331 return _adc_read(&adcdata[channel]);
332}
333
Dave Chapman77372d12005-11-07 23:07:19 +0000334void adc_init(void)
335{
Brandon Low63c0d1d2006-03-05 18:06:06 +0000336 struct adc_struct *adc_battery = &adcdata[ADC_BATTERY];
Brandon Low19f4c2a2006-03-09 19:47:12 +0000337 adc_battery->channelnum = 0x2; /* ADCVIN1, resistive divider */
338 adc_battery->timeout = 0;
339 _adc_read(adc_battery);
Dave Chapman77372d12005-11-07 23:07:19 +0000340}
341
Dave Chapmand83e9292006-01-12 00:35:50 +0000342#elif CONFIG_CPU == PNX0101
343
344static unsigned short adcdata[NUM_ADC_CHANNELS];
345
346unsigned short adc_read(int channel)
347{
348 return adcdata[channel];
349}
350
351static void adc_tick(void)
352{
353 if (ADCST & 0x10) {
354 adcdata[0] = ADCCH0 & 0x3ff;
355 adcdata[1] = ADCCH1 & 0x3ff;
356 adcdata[2] = ADCCH2 & 0x3ff;
357 adcdata[3] = ADCCH3 & 0x3ff;
358 adcdata[4] = ADCCH4 & 0x3ff;
359 ADCST = 0xa;
360 }
361}
362
363void adc_init(void)
364{
365 ADCR24 = 0xaaaaa;
366 ADCR28 = 0;
367 ADCST = 2;
368 ADCST = 0xa;
369
370 while (!(ADCST & 0x10));
371 adc_tick();
372
373 tick_add_task(adc_tick);
374}
375
Linus Nielsen Feltzing8d68eb62004-11-03 00:39:30 +0000376#endif