]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/gpio.c
Detect ZRESET polarity
[z180-stamp.git] / avr / gpio.c
CommitLineData
35edb766
L
1/*
2 * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
41d36f28
L
7#include "common.h"
8#include <util/atomic.h>
9#include <limits.h>
10#include "debug.h"
05994bd9 11#include "gpio.h"
41d36f28 12
41d36f28
L
13/*
14
15e476bc
L
15Pin Name Port Timer Mode max div max div min f [Hz]
16--------------------------------------------------------------------------------
170 PG5 OC0B PWM (2**8)*1024 262144 70.31
181 PG4
192 CLK2 PB4 OC2A Toggle (2**8)*1024*2 524288 35.16
203 ZCLK PB5 OC1A PWM (2**16)*1024 67108864 0.2746
214 PB6 OC1B PWM (2**16)*1024 67108864 0.2746
225 PB7 OC0A Toggle (2**8)*1024*2 524288 35.16
236 PG3
247 PG2
258 PG1
269 PG0
2710 CLKO PE7
28--------------------------------------------------------------------------------
29
30
31pre Timer0 Timer1 Timer2
41d36f28 32--------------------------------------------------
15e476bc
L
330 0 0 0
341 1 1 1
352 8 x8 8 x8 8 x8
363 64 x8 64 x8 32 x4
374 256 x4 256 x4 64 x2
385 1024 x4 1024 x4 128 x2
396 256 x2
407 1024 x4
05994bd9 41--------------------------------------------------
41d36f28
L
42*/
43
41d36f28
L
44#define PWMTOGGLE 0b01
45#define PWMPOS 0b10
46#define PWMNEG 0b11
47
48
05994bd9 49const FLASH uint8_t prescale_factors_01[] =
41d36f28
L
50 { 8, 8, 4, 4, 0 };
51
05994bd9 52const FLASH uint8_t prescale_factors_2[] =
41d36f28
L
53 { 8, 4, 2, 2, 2, 4, 0 };
54
55typedef volatile struct {
56 uint8_t pin;
57 uint8_t ddr;
58 uint8_t pout;
59} port_t ;
60
61struct pindef_s {
62 port_t * const adr;
63 const uint8_t mask;
64#define NO_TIMER 0
65#define TIMER0 (1 << 0)
66#define TIMER1 (2 << 0)
67#define TIMER2 (3 << 0)
68#define TIMER (3 << 0)
69#define T_16BIT (1 << 3)
70#define CHANA (1 << 4)
71#define CHANB (0 << 4)
72 const uint8_t timer;
73};
74
75
05994bd9 76const FLASH struct pindef_s pinlist[GPIO_MAX] = {
41d36f28
L
77 { (port_t *) &PING, _BV(5), TIMER0 | CHANB },
78 { (port_t *) &PING, _BV(4), NO_TIMER },
79 { (port_t *) &PINB, _BV(4), TIMER2 | CHANA },
80 { (port_t *) &PINB, _BV(5), TIMER1 | CHANA | T_16BIT },
81 { (port_t *) &PINB, _BV(6), TIMER1 | CHANB | T_16BIT },
82 { (port_t *) &PINB, _BV(7), TIMER0 | CHANA },
83 { (port_t *) &PING, _BV(3), NO_TIMER },
84 { (port_t *) &PING, _BV(2), NO_TIMER },
85 { (port_t *) &PING, _BV(1), NO_TIMER },
86 { (port_t *) &PING, _BV(0), NO_TIMER },
87 { (port_t *) &PINE, _BV(7), NO_TIMER },
88};
05994bd9
L
89
90void gpio_timer_off(uint8_t timertype)
41d36f28
L
91{
92 uint8_t chan_mask;
05994bd9 93
41d36f28
L
94 if (timertype & CHANA)
95 chan_mask = 0xc0;
96 else
97 chan_mask = 0x30;
98
99 switch (timertype & TIMER) {
100 case TIMER0:
101 if (TCCR0A & chan_mask) {
102 TCCR0B = 0;
103 TCCR0A = 0;
104 PRR0 |= _BV(PRTIM0);
105 }
106 break;
107 case TIMER1:
108 if (TCCR1A & chan_mask) {
109 TCCR1B = 0;
110 TCCR1A = 0;
111 PRR0 |= _BV(PRTIM1);
112 }
113 break;
114 case TIMER2:
115 if (TCCR2A & chan_mask) {
116 TCCR2B = 0;
117 TCCR2A = 0;
118 PRR0 |= _BV(PRTIM2);
119 }
120 break;
121 }
122}
123
05994bd9 124int gpio_config(int pin, gpiomode_t mode)
41d36f28
L
125{
126 if ((unsigned) pin >= ARRAY_SIZE(pinlist)) {
127 /* Invalid pin number */
128 return -1;
129 } else {
130
131 port_t *p = pinlist[pin].adr;
132 uint8_t bit = pinlist[pin].mask;
05994bd9 133
41d36f28
L
134 switch (mode) {
135 case INPUT:
05994bd9 136 gpio_timer_off(pinlist[pin].timer);
8a7decea 137 ATOMIC_BLOCK(ATOMIC_FORCEON) {
41d36f28
L
138 p->ddr &= ~bit;
139 p->pout &= ~bit;
140 }
141 break;
142 case INPUT_PULLUP:
05994bd9 143 gpio_timer_off(pinlist[pin].timer);
8a7decea 144 ATOMIC_BLOCK(ATOMIC_FORCEON) {
41d36f28
L
145 p->ddr &= ~bit;
146 p->pout |= bit;
147 }
148 break;
149 case OUTPUT:
05994bd9 150 gpio_timer_off(pinlist[pin].timer);
41d36f28 151 case OUTPUT_TIMER:
8a7decea 152 ATOMIC_BLOCK(ATOMIC_FORCEON) {
41d36f28
L
153 p->ddr |= bit;
154 }
155 break;
156 default:
157 /* Invalid pin mode */
158 return -1;
159 }
160 }
161 return 0;
162}
163
05994bd9 164void gpio_write(int pin, uint8_t val)
41d36f28
L
165{
166 port_t *p = pinlist[pin].adr;
167 uint8_t bit = pinlist[pin].mask;
05994bd9 168
8a7decea 169 ATOMIC_BLOCK(ATOMIC_FORCEON) {
41d36f28
L
170 if (val)
171 p->pout |= bit;
172 else
173 p->pout &= ~bit;
174 }
175}
176
05994bd9 177int gpio_read(int pin)
41d36f28
L
178{
179 port_t *p = pinlist[pin].adr;
180 uint8_t bit = pinlist[pin].mask;
05994bd9 181
41d36f28
L
182 return (p->pin & bit) != 0;
183}
184
05994bd9 185gpiomode_t gpio_config_get(int pin)
41d36f28
L
186{
187 uint8_t timertype = pinlist[pin].timer;
188
189 if (timertype & TIMER) {
05994bd9 190
41d36f28
L
191 uint8_t chan_mask;
192 if (timertype & CHANA)
193 chan_mask = 0xc0;
194 else
195 chan_mask = 0x30;
196
197 switch (timertype & TIMER) {
198 case TIMER0:
199 if (TCCR0A & chan_mask)
200 return OUTPUT_TIMER;
201 break;
202 case TIMER1:
203 if (TCCR1A & chan_mask)
204 return OUTPUT_TIMER;
205 break;
206 case TIMER2:
207 if (TCCR2A & chan_mask)
208 return OUTPUT_TIMER;
209 break;
210 }
211 }
05994bd9 212
41d36f28
L
213 port_t *p = pinlist[pin].adr;
214 uint8_t bit = pinlist[pin].mask;
215
216 if (p->ddr & bit)
217 return OUTPUT;
05994bd9 218
41d36f28
L
219 if (p->pout & bit)
220 return INPUT_PULLUP;
05994bd9 221
41d36f28
L
222 return INPUT;
223}
05994bd9 224
41d36f28
L
225/*
226 * return -1: pin has no timer output
227 * 0: pin is not configured for timer output
228 * > 0: divider
229 */
05994bd9
L
230
231long gpio_clockdiv_get(int pin)
41d36f28
L
232{
233 long divider;
234 uint8_t prescale;
235 const FLASH uint8_t *pstab;
236
237 uint8_t timertype = pinlist[pin].timer;
238 if ((timertype & TIMER) == 0)
239 return -1;
240
05994bd9 241 if (gpio_config_get(pin) != OUTPUT_TIMER)
41d36f28 242 return 0;
05994bd9 243
41d36f28
L
244 switch (timertype & TIMER) {
245 case TIMER0:
246 prescale = TCCR0B;
247 divider = OCR0A;
248 break;
249
250 case TIMER1:
251 prescale = TCCR1B;
252 divider = ICR1;
253 break;
254
255 case TIMER2:
256 prescale = TCCR2B;
257 divider = OCR2A;
258 break;
259 }
260
261 prescale = (prescale & 0x07) - 1;
262 divider += 1;
263
05994bd9 264 pstab = (timertype & TIMER) == TIMER2 ?
41d36f28 265 prescale_factors_2 : prescale_factors_01;
05994bd9 266
41d36f28
L
267 while (prescale--)
268 divider *= pstab[prescale];
05994bd9 269
41d36f28
L
270 if ((timertype & (CHANA|T_16BIT)) == CHANA)
271 divider *= 2;
05994bd9 272
41d36f28
L
273 return divider;
274}
275
05994bd9 276int gpio_clockdiv_set(int pin, unsigned long divider)
41d36f28
L
277{
278 unsigned long ltop;
279 uint16_t top;
280 uint8_t prescale;
281 const FLASH uint8_t *pstab;
282
283 uint8_t timertype = pinlist[pin].timer;
284 if ((timertype & TIMER) == 0)
285 return 0;
286
287 if (divider < 2)
288 return -1;
05994bd9 289
41d36f28
L
290 ltop = divider;
291 if ((timertype & (CHANA|T_16BIT)) == CHANA)
292 ltop /= 2;
05994bd9 293
41d36f28
L
294 if (ltop > 1024 * ((timertype & T_16BIT) ? (1L<<16) : (1L<<8)))
295 return -1;
296
297 prescale = 1;
05994bd9 298 pstab = (timertype & TIMER) == TIMER2 ?
41d36f28 299 prescale_factors_2 : prescale_factors_01;
05994bd9 300
41d36f28
L
301// debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d\n",
302// pin, ltop, prescale);
303
304 while (ltop > ((timertype & T_16BIT) ? (1L<<16) : (1L<<8))) {
305// debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d, *pstab %d\n",
306// pin, ltop, prescale, *pstab);
307
308 if (*pstab == 0)
309 return -1;
310 ltop /= *pstab++;
311 prescale++;
312 }
313
314 if (ltop == 0)
315 return -1;
316
317 top = ltop - 1;
318
15e476bc 319// PING |= _BV(0); /* Debug */
41d36f28
L
320
321 switch (timertype & TIMER) {
322 case TIMER0:
323 PRR0 &= ~_BV(PRTIM0);
324 TCCR0B = (1 << WGM02);
325 TCNT0 = 0;
326 OCR0A = top;
327 if (timertype & CHANA) {
328 TCCR0A = (PWMTOGGLE << COM0A0) | (0b11 << WGM00);
329 } else {
330 OCR0B = top/2;
331 TCCR0A = (PWMPOS << COM0B0) | (0b11 << WGM10);
332 }
333 TCCR0B = (1 << WGM02) | (prescale << CS10);
334 break;
335
336 case TIMER1:
337 PRR0 &= ~_BV(PRTIM1);
338 TCCR1B = (0b11 << WGM12);
339 TCNT1 = 0;
340 ICR1 = top;
341 if (timertype & CHANA) {
342 OCR1A = top/2;
343 TCCR1A = (PWMPOS << COM1A0) | (0b10 << WGM10);
344 } else {
345 OCR1B = top/2;
346 TCCR1A = (PWMPOS << COM1B0) | (0b10 << WGM10);
347 }
348// debug("pin: %d, top: %u,"
349// " ICR1: %u, OCR1A: %u, OCR1B: %u\n",
350// pin, top, ICR1, OCR1A, OCR1B);
351
352 TCCR1B = (0b11 << WGM12) | (prescale << CS10);
353 break;
354
355 case TIMER2:
356 PRR0 &= ~_BV(PRTIM2);
357 TCCR2B = (1 << WGM22);
358 TCNT2 = 0;
359 OCR2A = top;
360 if (timertype & CHANA) {
361 TCCR2A = (PWMTOGGLE << COM2A0) | (0b11 << WGM20);
362 } else {
363 OCR2B = top/2;
364 TCCR2A = (PWMPOS << COM2B0) | (0b11 << WGM10);
365 }
366 TCCR2B = (1 << WGM22) | (prescale << CS10);
367 break;
368 }
369
15e476bc 370// PING |= _BV(0); /* Debug */
41d36f28 371
05994bd9 372 gpio_config(pin, OUTPUT_TIMER);
41d36f28
L
373
374 return 0;
375}