aboutsummaryrefslogtreecommitdiffstats
path: root/src/samd21
diff options
context:
space:
mode:
Diffstat (limited to 'src/samd21')
-rw-r--r--src/samd21/Kconfig51
-rw-r--r--src/samd21/Makefile54
-rw-r--r--src/samd21/adc.c121
-rw-r--r--src/samd21/clock.c77
-rw-r--r--src/samd21/gpio.c141
-rw-r--r--src/samd21/gpio.h55
-rw-r--r--src/samd21/hard_pwm.c102
-rw-r--r--src/samd21/i2c.c114
-rw-r--r--src/samd21/internal.h14
-rw-r--r--src/samd21/main.c52
-rw-r--r--src/samd21/serial.c61
-rw-r--r--src/samd21/spi.c92
-rw-r--r--src/samd21/timer.c66
-rw-r--r--src/samd21/usbserial.c246
14 files changed, 0 insertions, 1246 deletions
diff --git a/src/samd21/Kconfig b/src/samd21/Kconfig
deleted file mode 100644
index 18bd7d81..00000000
--- a/src/samd21/Kconfig
+++ /dev/null
@@ -1,51 +0,0 @@
-# Kconfig settings for SAMD21 processors
-
-if MACH_SAMD21
-
-config SAMD_SELECT
- bool
- default y
- select HAVE_GPIO
- select HAVE_GPIO_ADC
- select HAVE_GPIO_I2C
- select HAVE_GPIO_SPI
- select HAVE_GPIO_HARD_PWM
- select HAVE_GPIO_BITBANGING
-
-config BOARD_DIRECTORY
- string
- default "samd21"
-
-config CLOCK_FREQ
- int
- default 48000000
-
-choice
- prompt "Bootloader offset"
- config FLASH_START_0000
- bool "No bootloader"
- config FLASH_START_2000
- bool "8KiB bootloader (Arduino Zero)"
- config FLASH_START_4000
- bool "16KiB bootloader (Arduino M0)"
-endchoice
-
-config FLASH_START
- hex
- default 0x4000 if FLASH_START_4000
- default 0x2000 if FLASH_START_2000
- default 0x0000
-
-config USBSERIAL
- bool "Use USB for communication (instead of serial)"
- default y
-config SERIAL
- depends on !USBSERIAL
- bool
- default y
-config SERIAL_BAUD
- depends on SERIAL
- int "Baud rate for serial port"
- default 250000
-
-endif
diff --git a/src/samd21/Makefile b/src/samd21/Makefile
deleted file mode 100644
index 24ef1e49..00000000
--- a/src/samd21/Makefile
+++ /dev/null
@@ -1,54 +0,0 @@
-# Additional samd21 build rules
-
-# Setup the toolchain
-CROSS_PREFIX=arm-none-eabi-
-
-dirs-y += src/samd21 src/generic
-dirs-y += lib/samd21/samd21a/gcc/gcc/
-
-CFLAGS += -mthumb -mcpu=cortex-m0plus
-CFLAGS += -Ilib/cmsis-core -Ilib/samd21/samd21a/include
-CFLAGS += -D__SAMD21G18A__
-
-CFLAGS_klipper.elf += -T $(OUT)samd21.ld
-CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs
-
-# Add source files
-src-y += samd21/main.c samd21/timer.c samd21/clock.c samd21/gpio.c
-src-y += generic/crc16_ccitt.c generic/alloc.c
-src-y += generic/armcm_irq.c generic/timer_irq.c
-src-y += ../lib/samd21/samd21a/gcc/gcc/startup_samd21.c
-src-$(CONFIG_USBSERIAL) += samd21/usbserial.c generic/usb_cdc.c
-src-$(CONFIG_SERIAL) += samd21/serial.c generic/serial_irq.c
-src-$(CONFIG_HAVE_GPIO_ADC) += samd21/adc.c
-src-$(CONFIG_HAVE_GPIO_I2C) += samd21/i2c.c
-src-$(CONFIG_HAVE_GPIO_SPI) += samd21/spi.c
-src-$(CONFIG_HAVE_GPIO_HARD_PWM) += samd21/hard_pwm.c
-
-# Support bootloader offset address
-target-y := $(OUT)samd21.ld $(target-y)
-
-$(OUT)samd21.ld: lib/samd21/samd21a/gcc/gcc/samd21g18a_flash.ld $(OUT)board-link
- @echo " Preprocessing $@"
- $(Q)$(CPP) -P -MD -MT $@ -DFLASH_START=$(CONFIG_FLASH_START) $< -o $@
-
-# Build the additional hex and bin output files
-target-y += $(OUT)klipper.bin $(OUT)klipper.elf.hex
-
-$(OUT)klipper.bin: $(OUT)klipper.elf
- @echo " Creating hex file $@"
- $(Q)$(OBJCOPY) -O binary $< $@
-
-$(OUT)klipper.elf.hex: $(OUT)klipper.elf
- @echo " Creating hex file $@"
- $(Q)$(OBJCOPY) -j .text -j .relocate -O ihex $< $@
-
-# Flash rules
-lib/bossac/bin/bossac:
- @echo " Building bossac"
- $(Q)make -C lib/bossac bin/bossac
-
-flash: $(OUT)klipper.bin lib/bossac/bin/bossac
- @echo " Flashing $^ to $(FLASH_DEVICE) via bossac"
- $(Q)if [ -z $(FLASH_DEVICE) ]; then echo "Please specify FLASH_DEVICE"; exit 1; fi
- $(Q)lib/bossac/bin/bossac -U -p "$(FLASH_DEVICE)" -a --offset=0x2000 -w $(OUT)klipper.bin -v -b -R
diff --git a/src/samd21/adc.c b/src/samd21/adc.c
deleted file mode 100644
index 38836592..00000000
--- a/src/samd21/adc.c
+++ /dev/null
@@ -1,121 +0,0 @@
-// Analog to Digital Converter support
-//
-// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU GPLv3 license.
-
-#include "command.h" // shutdown
-#include "gpio.h" // gpio_adc_read
-#include "internal.h" // GPIO
-#include "samd21.h" // ADC
-#include "sched.h" // sched_shutdown
-
-static const uint8_t adc_pins[] = {
- GPIO('A', 2), GPIO('A', 3), GPIO('B', 8), GPIO('B', 9), GPIO('A', 4),
- GPIO('A', 5), GPIO('A', 6), GPIO('A', 7), GPIO('B', 0), GPIO('B', 1),
- GPIO('B', 2), GPIO('B', 3), GPIO('B', 4), GPIO('B', 5), GPIO('B', 6),
- GPIO('B', 7), GPIO('A', 8), GPIO('A', 9), GPIO('A', 10), GPIO('A', 11)
-};
-
-DECL_CONSTANT(ADC_MAX, 4095);
-
-static void
-adc_init(void)
-{
- static uint8_t have_run_init;
- if (have_run_init)
- return;
- have_run_init = 1;
-
- // Enable adc clock
- enable_pclock(ADC_GCLK_ID, PM_APBCMASK_ADC);
-
- // Load calibraiton info
- uint32_t v = *((uint32_t*)ADC_FUSES_BIASCAL_ADDR);
- uint32_t bias = (v & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos;
- v = *((uint32_t*)ADC_FUSES_LINEARITY_0_ADDR);
- uint32_t li0 = (v & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos;
- v = *((uint32_t*)ADC_FUSES_LINEARITY_1_ADDR);
- uint32_t li5 = (v & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos;
- uint32_t lin = li0 | (li5 << 5);
- ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(bias) | ADC_CALIB_LINEARITY_CAL(lin);
-
- // Setup and enable adc
- ADC->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1;
- ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV128;
- ADC->SAMPCTRL.reg = 63;
- ADC->CTRLA.reg = ADC_CTRLA_ENABLE;
-}
-
-struct gpio_adc
-gpio_adc_setup(uint8_t pin)
-{
- // Find pin in adc_pins table
- uint8_t chan;
- for (chan=0; ; chan++) {
- if (chan >= ARRAY_SIZE(adc_pins))
- shutdown("Not a valid ADC pin");
- if (adc_pins[chan] == pin)
- break;
- }
-
- // Enable ADC
- adc_init();
-
- // Set pin in ADC mode
- gpio_peripheral(pin, 'B', 0);
-
- return (struct gpio_adc){ chan };
-}
-
-enum { ADC_DUMMY=0xff };
-static uint8_t last_analog_read = ADC_DUMMY;
-
-// Try to sample a value. Returns zero if sample ready, otherwise
-// returns the number of clock ticks the caller should wait before
-// retrying this function.
-uint32_t
-gpio_adc_sample(struct gpio_adc g)
-{
- if (last_analog_read == g.chan) {
- if (ADC->INTFLAG.reg & ADC_INTFLAG_RESRDY)
- // Sample now ready
- return 0;
- // ADC is still busy
- goto need_delay;
- }
- if (last_analog_read != ADC_DUMMY)
- // Sample on another channel in progress
- goto need_delay;
- last_analog_read = g.chan;
-
- // Set the channel to sample
- ADC->INPUTCTRL.reg = (ADC_INPUTCTRL_MUXPOS(g.chan)
- | ADC_INPUTCTRL_MUXNEG_GND | ADC_INPUTCTRL_GAIN_DIV2);
-
- // Start the sample
- ADC->SWTRIG.reg = ADC_SWTRIG_START;
-
- // Schedule next attempt after sample is likely to be complete
-need_delay:
- return 42 * 128 + 200; // 42 == 1 + (63+1)/2 + 1 + 12/2 + 1.5
-}
-
-// Read a value; use only after gpio_adc_sample() returns zero
-uint16_t
-gpio_adc_read(struct gpio_adc g)
-{
- last_analog_read = ADC_DUMMY;
- return ADC->RESULT.reg;
-}
-
-// Cancel a sample that may have been started with gpio_adc_sample()
-void
-gpio_adc_cancel_sample(struct gpio_adc g)
-{
- if (last_analog_read == g.chan) {
- ADC->SWTRIG.reg = ADC_SWTRIG_FLUSH;
- ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;
- last_analog_read = ADC_DUMMY;
- }
-}
diff --git a/src/samd21/clock.c b/src/samd21/clock.c
deleted file mode 100644
index ef0cd9bc..00000000
--- a/src/samd21/clock.c
+++ /dev/null
@@ -1,77 +0,0 @@
-// Code to setup peripheral clocks on the SAMD21
-//
-// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU GPLv3 license.
-
-#include "autoconf.h" // CONFIG_CLOCK_FREQ
-#include "compiler.h" // DIV_ROUND_CLOSEST
-#include "internal.h" // enable_pclock
-#include "samd21.h" // GCLK
-
-// The "generic clock generators" that are configured
-#define CLKGEN_MAIN 0
-#define CLKGEN_32K 1
-#define CLKGEN_ULP32K 2
-
-// Enable a peripheral clock and power to that peripheral
-void
-enable_pclock(uint32_t clock_id, uint32_t pmask)
-{
- GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_ID(clock_id)
- | GCLK_CLKCTRL_GEN(CLKGEN_MAIN) | GCLK_CLKCTRL_CLKEN);
- while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY)
- ;
- PM->APBCMASK.reg |= pmask;
-}
-
-#define FREQ_XOSC32K 32768
-
-void
-SystemInit(void)
-{
- // Setup flash to work with 48Mhz clock
- NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_RWS_HALF;
-
- // Enable external 32Khz crystal
- uint32_t val = (SYSCTRL_XOSC32K_STARTUP(6)
- | SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K);
- SYSCTRL->XOSC32K.reg = val;
- SYSCTRL->XOSC32K.reg = val | SYSCTRL_XOSC32K_ENABLE;
- while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY))
- ;
-
- // Reset GCLK
- GCLK->CTRL.reg = GCLK_CTRL_SWRST;
- while (GCLK->CTRL.reg & GCLK_CTRL_SWRST)
- ;
-
- // Route external 32Khz clock to DFLL48M (via CLKGEN_32K)
- GCLK->GENDIV.reg = GCLK_GENDIV_ID(CLKGEN_32K);
- GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(CLKGEN_32K)
- | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_GENEN);
- GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_ID(SYSCTRL_GCLK_ID_DFLL48)
- | GCLK_CLKCTRL_GEN(CLKGEN_32K) | GCLK_CLKCTRL_CLKEN);
- while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY)
- ;
-
- // Configure DFLL48M clock
- SYSCTRL->DFLLCTRL.reg = 0;
- uint32_t mul = DIV_ROUND_CLOSEST(CONFIG_CLOCK_FREQ, FREQ_XOSC32K);
- SYSCTRL->DFLLMUL.reg = (SYSCTRL_DFLLMUL_CSTEP(31)
- | SYSCTRL_DFLLMUL_FSTEP(511)
- | SYSCTRL_DFLLMUL_MUL(mul));
- SYSCTRL->DFLLCTRL.reg = (SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_WAITLOCK
- | SYSCTRL_DFLLCTRL_QLDIS
- | SYSCTRL_DFLLCTRL_ENABLE);
- uint32_t ready = (SYSCTRL_PCLKSR_DFLLRDY | SYSCTRL_PCLKSR_DFLLLCKC
- | SYSCTRL_PCLKSR_DFLLLCKF);
- while ((SYSCTRL->PCLKSR.reg & ready) != ready)
- ;
-
- // Switch main clock to DFLL48M clock
- GCLK->GENDIV.reg = GCLK_GENDIV_ID(CLKGEN_MAIN);
- GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(CLKGEN_MAIN)
- | GCLK_GENCTRL_SRC_DFLL48M
- | GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN);
-}
diff --git a/src/samd21/gpio.c b/src/samd21/gpio.c
deleted file mode 100644
index 045dc003..00000000
--- a/src/samd21/gpio.c
+++ /dev/null
@@ -1,141 +0,0 @@
-// samd21 gpio functions
-//
-// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU GPLv3 license.
-
-#include <string.h> // ffs
-#include "board/irq.h" // irq_save
-#include "command.h" // shutdown
-#include "gpio.h" // gpio_out_setup
-#include "internal.h" // gpio_peripheral
-#include "samd21.h" // PORT
-#include "sched.h" // sched_shutdown
-
-
-/****************************************************************
- * Pin multiplexing
- ****************************************************************/
-
-void
-gpio_peripheral(uint32_t gpio, char ptype, int32_t pull_up)
-{
- uint32_t bank = GPIO2PORT(gpio), bit = gpio % 32;
- PortGroup *pg = &PORT->Group[bank];
- if (ptype) {
- volatile uint8_t *pmux = &pg->PMUX[bit/2].reg;
- uint8_t shift = (bit & 1) ? 4 : 0, mask = ~(0xf << shift);
- *pmux = (*pmux & mask) | ((ptype - 'A') << shift);
- }
- if (pull_up) {
- if (pull_up > 0)
- pg->OUTSET.reg = (1<<bit);
- else
- pg->OUTCLR.reg = (1<<bit);
- }
-
- pg->PINCFG[bit].reg = ((ptype ? PORT_PINCFG_PMUXEN : 0)
- | (pull_up ? PORT_PINCFG_PULLEN : 0));
-}
-
-
-/****************************************************************
- * General Purpose Input Output (GPIO) pins
- ****************************************************************/
-
-#define NUM_PORT 2
-
-struct gpio_out
-gpio_out_setup(uint8_t pin, uint8_t val)
-{
- if (GPIO2PORT(pin) >= NUM_PORT)
- goto fail;
- PortGroup *pg = &PORT->Group[GPIO2PORT(pin)];
- struct gpio_out g = { .regs=pg, .bit=GPIO2BIT(pin) };
- gpio_out_reset(g, val);
- return g;
-fail:
- shutdown("Not an output pin");
-}
-
-static void
-set_pincfg(PortGroup *pg, uint32_t bit, uint8_t cfg)
-{
- pg->PINCFG[ffs(bit)-1].reg = cfg;
-}
-
-void
-gpio_out_reset(struct gpio_out g, uint8_t val)
-{
- PortGroup *pg = g.regs;
- irqstatus_t flag = irq_save();
- if (val)
- pg->OUTSET.reg = g.bit;
- else
- pg->OUTCLR.reg = g.bit;
- pg->DIRSET.reg = g.bit;
- set_pincfg(pg, g.bit, 0);
- irq_restore(flag);
-}
-
-void
-gpio_out_toggle_noirq(struct gpio_out g)
-{
- PortGroup *pg = g.regs;
- pg->OUTTGL.reg = g.bit;
-}
-
-void
-gpio_out_toggle(struct gpio_out g)
-{
- gpio_out_toggle_noirq(g);
-}
-
-void
-gpio_out_write(struct gpio_out g, uint8_t val)
-{
- PortGroup *pg = g.regs;
- if (val)
- pg->OUTSET.reg = g.bit;
- else
- pg->OUTCLR.reg = g.bit;
-}
-
-
-struct gpio_in
-gpio_in_setup(uint8_t pin, int8_t pull_up)
-{
- if (GPIO2PORT(pin) >= NUM_PORT)
- goto fail;
- PortGroup *pg = &PORT->Group[GPIO2PORT(pin)];
- struct gpio_in g = { .regs=pg, .bit=GPIO2BIT(pin) };
- gpio_in_reset(g, pull_up);
- return g;
-fail:
- shutdown("Not an input pin");
-}
-
-void
-gpio_in_reset(struct gpio_in g, int8_t pull_up)
-{
- PortGroup *pg = g.regs;
- irqstatus_t flag = irq_save();
- uint32_t cfg = PORT_PINCFG_INEN;
- if (pull_up) {
- cfg |= PORT_PINCFG_PULLEN;
- if (pull_up > 0)
- pg->OUTSET.reg = g.bit;
- else
- pg->OUTCLR.reg = g.bit;
- }
- set_pincfg(pg, g.bit, cfg);
- pg->DIRCLR.reg = g.bit;
- irq_restore(flag);
-}
-
-uint8_t
-gpio_in_read(struct gpio_in g)
-{
- PortGroup *pg = g.regs;
- return !!(pg->IN.reg & g.bit);
-}
diff --git a/src/samd21/gpio.h b/src/samd21/gpio.h
deleted file mode 100644
index 5bf44454..00000000
--- a/src/samd21/gpio.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef __SAM3X8E_GPIO_H
-#define __SAM3X8E_GPIO_H
-
-#include <stdint.h>
-
-struct gpio_out {
- void *regs;
- uint32_t bit;
-};
-struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val);
-void gpio_out_reset(struct gpio_out g, uint8_t val);
-void gpio_out_toggle_noirq(struct gpio_out g);
-void gpio_out_toggle(struct gpio_out g);
-void gpio_out_write(struct gpio_out g, uint8_t val);
-
-struct gpio_in {
- void *regs;
- uint32_t bit;
-};
-struct gpio_in gpio_in_setup(uint8_t pin, int8_t pull_up);
-void gpio_in_reset(struct gpio_in g, int8_t pull_up);
-uint8_t gpio_in_read(struct gpio_in g);
-
-struct gpio_pwm {
- void *reg;
-};
-struct gpio_pwm gpio_pwm_setup(uint8_t pin, uint32_t cycle_time, uint8_t val);
-void gpio_pwm_write(struct gpio_pwm g, uint8_t val);
-
-struct gpio_adc {
- uint32_t chan;
-};
-struct gpio_adc gpio_adc_setup(uint8_t pin);
-uint32_t gpio_adc_sample(struct gpio_adc g);
-uint16_t gpio_adc_read(struct gpio_adc g);
-void gpio_adc_cancel_sample(struct gpio_adc g);
-
-struct spi_config {
- uint32_t ctrla, baud;
-};
-struct spi_config spi_setup(uint32_t bus, uint8_t mode, uint32_t rate);
-void spi_prepare(struct spi_config config);
-void spi_transfer(struct spi_config config, uint8_t receive_data
- , uint8_t len, uint8_t *data);
-
-struct i2c_config {
- uint8_t addr;
-};
-
-struct i2c_config i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr);
-void i2c_write(struct i2c_config config, uint8_t write_len, uint8_t *write);
-void i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg
- , uint8_t read_len, uint8_t *read);
-
-#endif // gpio.h
diff --git a/src/samd21/hard_pwm.c b/src/samd21/hard_pwm.c
deleted file mode 100644
index 7deecfb9..00000000
--- a/src/samd21/hard_pwm.c
+++ /dev/null
@@ -1,102 +0,0 @@
-// Hardware PWM support on samd21
-//
-// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU GPLv3 license.
-
-#include "command.h" // shutdown
-#include "gpio.h" // gpio_pwm_write
-#include "internal.h" // GPIO
-#include "samd21.h" // TCC0
-#include "sched.h" // sched_shutdown
-
-struct gpio_pwm_info {
- uint32_t gpio;
- Tcc *tcc;
- uint32_t clock_id, power_id, channel;
- char ptype;
-};
-
-static const struct gpio_pwm_info pwm_regs[] = {
- { GPIO('A', 4), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 0, 'E' },
- { GPIO('A', 5), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 1, 'E' },
- { GPIO('A', 6), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 0, 'E' },
- { GPIO('A', 7), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 1, 'E' },
- { GPIO('A', 8), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 0, 'E' },
- { GPIO('A', 9), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 1, 'E' },
- { GPIO('A', 10), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 0, 'E' },
- { GPIO('A', 11), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 1, 'E' },
- { GPIO('A', 12), TCC2, TCC2_GCLK_ID, PM_APBCMASK_TCC2, 0, 'E' },
- { GPIO('A', 13), TCC2, TCC2_GCLK_ID, PM_APBCMASK_TCC2, 1, 'E' },
- { GPIO('A', 16), TCC2, TCC2_GCLK_ID, PM_APBCMASK_TCC2, 0, 'E' },
- { GPIO('A', 17), TCC2, TCC2_GCLK_ID, PM_APBCMASK_TCC2, 1, 'E' },
- { GPIO('A', 18), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 2, 'F' },
- { GPIO('A', 19), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 3, 'F' },
- { GPIO('A', 24), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 2, 'F' },
- { GPIO('A', 25), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 3, 'F' },
- { GPIO('A', 30), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 0, 'E' },
- { GPIO('A', 31), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 1, 'E' },
- { GPIO('B', 30), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 0, 'E' },
- { GPIO('B', 31), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 1, 'E' },
-};
-
-#define MAX_PWM 255
-
-DECL_CONSTANT(PWM_MAX, MAX_PWM);
-
-struct gpio_pwm
-gpio_pwm_setup(uint8_t pin, uint32_t cycle_time, uint8_t val)
-{
- // Find pin in pwm_regs table
- const struct gpio_pwm_info *p = pwm_regs;
- for (; ; p++) {
- if (p >= &pwm_regs[ARRAY_SIZE(pwm_regs)])
- shutdown("Not a valid PWM pin");
- if (p->gpio == pin)
- break;
- }
-
- // Enable timer clock
- enable_pclock(p->clock_id, p->power_id);
-
- // Map cycle_time to pwm clock divisor
- uint32_t cs;
- switch (cycle_time) {
- case 0 ... (1+2) * MAX_PWM / 2 - 1: cs = 0; break;
- case (1+2) * MAX_PWM / 2 ... (2+4) * MAX_PWM / 2 - 1: cs = 1; break;
- case (2+4) * MAX_PWM / 2 ... (4+8) * MAX_PWM / 2 - 1: cs = 2; break;
- case (4+8) * MAX_PWM / 2 ... (8+16) * MAX_PWM / 2 - 1: cs = 3; break;
- case (8+16) * MAX_PWM / 2 ... (16+64) * MAX_PWM / 2 - 1: cs = 4; break;
- case (16+64) * MAX_PWM / 2 ... (64+256) * MAX_PWM / 2 - 1: cs = 5; break;
- case (64+256) * MAX_PWM / 2 ... (256+1024) * MAX_PWM / 2 - 1: cs = 6; break;
- default: cs = 7; break;
- }
- uint32_t ctrla = TCC_CTRLA_ENABLE | TCC_CTRLA_PRESCALER(cs);
-
- // Enable timer
- Tcc *tcc = p->tcc;
- uint32_t old_ctrla = tcc->CTRLA.reg;
- if (old_ctrla != ctrla) {
- if (old_ctrla & TCC_CTRLA_ENABLE)
- shutdown("PWM already programmed at different speed");
- tcc->CTRLA.reg = ctrla & ~TCC_CTRLA_ENABLE;
- tcc->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM;
- tcc->PER.reg = MAX_PWM;
- tcc->CTRLA.reg = ctrla;
- }
-
- // Set initial value
- struct gpio_pwm g = (struct gpio_pwm) { (void*)&tcc->CCB[p->channel].reg };
- gpio_pwm_write(g, val);
-
- // Route output to pin
- gpio_peripheral(pin, p->ptype, 0);
-
- return g;
-}
-
-void
-gpio_pwm_write(struct gpio_pwm g, uint8_t val)
-{
- *(volatile uint32_t*)g.reg = val;
-}
diff --git a/src/samd21/i2c.c b/src/samd21/i2c.c
deleted file mode 100644
index 801c0e32..00000000
--- a/src/samd21/i2c.c
+++ /dev/null
@@ -1,114 +0,0 @@
-// i2c support on samd21
-//
-// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU GPLv3 license.
-
-#include "autoconf.h" // CONFIG_CLOCK_FREQ
-#include "internal.h" // enable_pclock
-#include "command.h" // shutdown
-#include "gpio.h" // i2c_setup
-#include "samd21.h" // SERCOM3
-#include "sched.h" // sched_shutdown
-
-#define TIME_RISE 125ULL // 125 nanoseconds
-#define I2C_FREQ 100000
-
-static void
-i2c_init(void)
-{
- static int have_run_init;
- if (have_run_init)
- return;
- have_run_init = 1;
-
- // Setup clock
- enable_pclock(SERCOM3_GCLK_ID_CORE, PM_APBCMASK_SERCOM3);
-
- // Configure SDA, SCL pins
- gpio_peripheral(GPIO('A', 22), 'C', 0);
- gpio_peripheral(GPIO('A', 23), 'C', 0);
-
- // Configure i2c
- SercomI2cm *si = &SERCOM3->I2CM;
- si->CTRLA.reg = 0;
- uint32_t areg = (SERCOM_I2CM_CTRLA_LOWTOUTEN
- | SERCOM_I2CM_CTRLA_INACTOUT(3)
- | SERCOM_I2CM_STATUS_SEXTTOUT
- | SERCOM_I2CM_STATUS_MEXTTOUT
- | SERCOM_I2CM_CTRLA_MODE_I2C_MASTER);
- si->CTRLA.reg = areg;
- uint32_t baud = (CONFIG_CLOCK_FREQ / I2C_FREQ
- - 10 - CONFIG_CLOCK_FREQ*TIME_RISE/1000000000) / 2;
- si->BAUD.reg = baud;
- si->CTRLA.reg = areg | SERCOM_I2CM_CTRLA_ENABLE;
- while (si->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_ENABLE)
- ;
-
- // Go into idle mode
- si->STATUS.reg = SERCOM_I2CM_STATUS_BUSSTATE(1);
- while (si->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_SYSOP)
- ;
-}
-
-struct i2c_config
-i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr)
-{
- if (bus)
- shutdown("Unsupported i2c bus");
- i2c_init();
- return (struct i2c_config){ .addr=addr<<1 };
-}
-
-static void
-i2c_wait(SercomI2cm *si)
-{
- for (;;) {
- uint32_t intflag = si->INTFLAG.reg;
- if (!(intflag & SERCOM_I2CM_INTFLAG_MB)) {
- if (si->STATUS.reg & SERCOM_I2CM_STATUS_BUSERR)
- shutdown("i2c buserror");
- continue;
- }
- if (intflag & SERCOM_I2CM_INTFLAG_ERROR)
- shutdown("i2c error");
- break;
- }
-}
-
-static void
-i2c_start(SercomI2cm *si, uint8_t addr)
-{
- si->ADDR.reg = addr;
- i2c_wait(si);
-}
-
-static void
-i2c_send_byte(SercomI2cm *si, uint8_t b)
-{
- si->DATA.reg = b;
- i2c_wait(si);
-}
-
-static void
-i2c_stop(SercomI2cm *si)
-{
- si->CTRLB.reg = SERCOM_I2CM_CTRLB_CMD(3);
-}
-
-void
-i2c_write(struct i2c_config config, uint8_t write_len, uint8_t *write)
-{
- SercomI2cm *si = &SERCOM3->I2CM;
- i2c_start(si, config.addr);
- while (write_len--)
- i2c_send_byte(si, *write++);
- i2c_stop(si);
-}
-
-void
-i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg
- , uint8_t read_len, uint8_t *read)
-{
- shutdown("i2c_read not supported on samd21");
-}
diff --git a/src/samd21/internal.h b/src/samd21/internal.h
deleted file mode 100644
index 7043007f..00000000
--- a/src/samd21/internal.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __SAMD21_INTERNAL_H
-#define __SAMD21_INTERNAL_H
-// Local definitions for samd21 code
-
-#include <stdint.h> // uint32_t
-
-#define GPIO(PORT, NUM) (((PORT)-'A') * 32 + (NUM))
-#define GPIO2PORT(PIN) ((PIN) / 32)
-#define GPIO2BIT(PIN) (1<<((PIN) % 32))
-
-void enable_pclock(uint32_t clock_id, uint32_t pmask);
-void gpio_peripheral(uint32_t gpio, char ptype, int32_t pull_up);
-
-#endif // internal.h
diff --git a/src/samd21/main.c b/src/samd21/main.c
deleted file mode 100644
index 4687fc34..00000000
--- a/src/samd21/main.c
+++ /dev/null
@@ -1,52 +0,0 @@
-// Main starting point for SAMD21 boards
-//
-// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU GPLv3 license.
-
-#include "command.h" // DECL_CONSTANT
-#include "samd21.h" // SystemInit
-#include "sched.h" // sched_main
-
-DECL_CONSTANT(MCU, "samd21g");
-
-
-/****************************************************************
- * watchdog handler
- ****************************************************************/
-
-void
-watchdog_reset(void)
-{
- WDT->CLEAR.reg = 0xa5;
-}
-DECL_TASK(watchdog_reset);
-
-void
-watchdog_init(void)
-{
- WDT->CONFIG.reg = WDT_CONFIG_PER_16K; // 500ms timeout
- WDT->CTRL.reg = WDT_CTRL_ENABLE;
-}
-DECL_INIT(watchdog_init);
-
-
-/****************************************************************
- * misc functions
- ****************************************************************/
-
-void
-command_reset(uint32_t *args)
-{
- NVIC_SystemReset();
-}
-DECL_COMMAND_FLAGS(command_reset, HF_IN_SHUTDOWN, "reset");
-
-// Main entry point
-int
-main(void)
-{
- SystemInit();
- sched_main();
- return 0;
-}
diff --git a/src/samd21/serial.c b/src/samd21/serial.c
deleted file mode 100644
index 895ffb27..00000000
--- a/src/samd21/serial.c
+++ /dev/null
@@ -1,61 +0,0 @@
-// samd21 serial port
-//
-// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU GPLv3 license.
-
-#include "autoconf.h" // CONFIG_SERIAL_BAUD
-#include "board/serial_irq.h" // serial_rx_data
-#include "internal.h" // enable_pclock
-#include "samd21.h" // SERCOM0
-#include "sched.h" // DECL_INIT
-
-void
-serial_init(void)
-{
- // Enable serial clock
- enable_pclock(SERCOM0_GCLK_ID_CORE, PM_APBCMASK_SERCOM0);
- // Enable pins
- gpio_peripheral(GPIO('A', 10), 'C', 0);
- gpio_peripheral(GPIO('A', 11), 'C', 0);
- // Configure serial
- SercomUsart *su = &SERCOM0->USART;
- su->CTRLA.reg = 0;
- uint32_t areg = (SERCOM_USART_CTRLA_MODE_USART_INT_CLK
- | SERCOM_USART_CTRLA_DORD
- | SERCOM_USART_CTRLA_SAMPR(1)
- | SERCOM_USART_CTRLA_TXPO(1)
- | SERCOM_USART_CTRLA_RXPO(3));
- su->CTRLA.reg = areg;
- su->CTRLB.reg = SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN;
- uint32_t baud8 = CONFIG_CLOCK_FREQ / (2 * CONFIG_SERIAL_BAUD);
- su->BAUD.reg = (SERCOM_USART_BAUD_FRAC_BAUD(baud8 / 8)
- | SERCOM_USART_BAUD_FRAC_FP(baud8 % 8));
- NVIC_SetPriority(SERCOM0_IRQn, 0);
- NVIC_EnableIRQ(SERCOM0_IRQn);
- su->INTENSET.reg = SERCOM_USART_INTENSET_RXC;
- su->CTRLA.reg = areg | SERCOM_USART_CTRLA_ENABLE;
-}
-DECL_INIT(serial_init);
-
-void __visible
-SERCOM0_Handler(void)
-{
- uint32_t status = SERCOM0->USART.INTFLAG.reg;
- if (status & SERCOM_USART_INTFLAG_RXC)
- serial_rx_byte(SERCOM0->USART.DATA.reg);
- if (status & SERCOM_USART_INTFLAG_DRE) {
- uint8_t data;
- int ret = serial_get_tx_byte(&data);
- if (ret)
- SERCOM0->USART.INTENCLR.reg = SERCOM_USART_INTENSET_DRE;
- else
- SERCOM0->USART.DATA.reg = data;
- }
-}
-
-void
-serial_enable_tx_irq(void)
-{
- SERCOM0->USART.INTENSET.reg = SERCOM_USART_INTENSET_DRE;
-}
diff --git a/src/samd21/spi.c b/src/samd21/spi.c
deleted file mode 100644
index 12c7d680..00000000
--- a/src/samd21/spi.c
+++ /dev/null
@@ -1,92 +0,0 @@
-// spi support on samd21
-//
-// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU GPLv3 license.
-
-#include "autoconf.h" // CONFIG_CLOCK_FREQ
-#include "internal.h" // enable_pclock
-#include "command.h" // shutdown
-#include "gpio.h" // spi_setup
-#include "samd21.h" // SERCOM4
-#include "sched.h" // sched_shutdown
-
-static void
-spi_init(uint32_t ctrla, uint32_t baud)
-{
- static int have_run_init;
- if (have_run_init)
- return;
- have_run_init = 1;
-
- // Setup clock
- enable_pclock(SERCOM4_GCLK_ID_CORE, PM_APBCMASK_SERCOM4);
-
- // Configure MISO, MOSI, SCK pins
- gpio_peripheral(GPIO('A', 12), 'D', 0);
- gpio_peripheral(GPIO('B', 10), 'D', 0);
- gpio_peripheral(GPIO('B', 11), 'D', 0);
-
- // Configure spi
- SercomSpi *ss = &SERCOM4->SPI;
- ss->CTRLA.reg = 0;
- ss->CTRLA.reg = ctrla & ~SERCOM_SPI_CTRLA_ENABLE;
- ss->CTRLB.reg = SERCOM_SPI_CTRLB_RXEN;
- ss->BAUD.reg = baud;
- ss->CTRLA.reg = ctrla;
-}
-
-struct spi_config
-spi_setup(uint32_t bus, uint8_t mode, uint32_t rate)
-{
- if (bus)
- shutdown("Invalid spi bus");
-
- uint32_t ctrla = (SERCOM_SPI_CTRLA_MODE_SPI_MASTER
- | (mode << SERCOM_SPI_CTRLA_CPHA_Pos)
- | SERCOM_SPI_CTRLA_DIPO(0)
- | SERCOM_SPI_CTRLA_DOPO(1)
- | SERCOM_SPI_CTRLA_ENABLE);
- uint32_t baud = CONFIG_CLOCK_FREQ / (2 * rate) - 1;
- spi_init(ctrla, baud);
- return (struct spi_config){ .ctrla = ctrla, .baud = baud };
-}
-
-void
-spi_prepare(struct spi_config config)
-{
- uint32_t ctrla = config.ctrla, baud = config.baud;
- SercomSpi *ss = &SERCOM4->SPI;
- if (ctrla == ss->CTRLA.reg && baud == ss->BAUD.reg)
- return;
- ss->CTRLA.reg = ctrla & ~SERCOM_SPI_CTRLA_ENABLE;
- ss->CTRLA.reg = ctrla & ~SERCOM_SPI_CTRLA_ENABLE;
- ss->BAUD.reg = baud;
- ss->CTRLA.reg = ctrla;
-}
-
-void
-spi_transfer(struct spi_config config, uint8_t receive_data
- , uint8_t len, uint8_t *data)
-{
- SercomSpi *ss = &SERCOM4->SPI;
- if (receive_data) {
- while (len--) {
- ss->DATA.reg = *data;
- // wait for receive register
- while (!(ss->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC))
- ;
- // get data
- *data++ = ss->DATA.reg;
- }
- } else {
- while (len--) {
- ss->DATA.reg = *data++;
- // wait for receive register
- while (!(ss->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC))
- ;
- // read data (to clear RXC)
- ss->DATA.reg;
- }
- }
-}
diff --git a/src/samd21/timer.c b/src/samd21/timer.c
deleted file mode 100644
index 882b4c10..00000000
--- a/src/samd21/timer.c
+++ /dev/null
@@ -1,66 +0,0 @@
-// SAMD21 timer interrupt scheduling
-//
-// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU GPLv3 license.
-
-#include "board/irq.h" // irq_disable
-#include "board/misc.h" // timer_read_time
-#include "board/timer_irq.h" // timer_dispatch_many
-#include "internal.h" // enable_pclock
-#include "samd21.h" // TC4
-#include "sched.h" // DECL_INIT
-
-// Set the next irq time
-static void
-timer_set(uint32_t value)
-{
- TC4->COUNT32.CC[0].reg = value;
- TC4->COUNT32.INTFLAG.reg = TC_INTFLAG_MC0;
-}
-
-// Return the current time (in absolute clock ticks).
-uint32_t
-timer_read_time(void)
-{
- return TC4->COUNT32.COUNT.reg;
-}
-
-// Activate timer dispatch as soon as possible
-void
-timer_kick(void)
-{
- timer_set(timer_read_time() + 50);
-}
-
-void
-timer_init(void)
-{
- // Supply power and clock to the timer
- enable_pclock(TC3_GCLK_ID, PM_APBCMASK_TC3);
- enable_pclock(TC4_GCLK_ID, PM_APBCMASK_TC4);
-
- // Configure the timer
- TcCount32 *tc = &TC4->COUNT32;
- irqstatus_t flag = irq_save();
- tc->CTRLA.reg = 0;
- tc->CTRLA.reg = TC_CTRLA_MODE_COUNT32;
- NVIC_SetPriority(TC4_IRQn, 2);
- NVIC_EnableIRQ(TC4_IRQn);
- tc->INTENSET.reg = TC_INTENSET_MC0;
- tc->COUNT.reg = 0;
- timer_kick();
- tc->CTRLA.reg = TC_CTRLA_MODE_COUNT32 | TC_CTRLA_ENABLE;
- irq_restore(flag);
-}
-DECL_INIT(timer_init);
-
-// IRQ handler
-void __visible __aligned(16) // aligning helps stabilize perf benchmarks
-TC4_Handler(void)
-{
- irq_disable();
- uint32_t next = timer_dispatch_many();
- timer_set(next);
- irq_enable();
-}
diff --git a/src/samd21/usbserial.c b/src/samd21/usbserial.c
deleted file mode 100644
index 0864a4c5..00000000
--- a/src/samd21/usbserial.c
+++ /dev/null
@@ -1,246 +0,0 @@
-// Hardware interface to USB on samd21
-//
-// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU GPLv3 license.
-
-#include <string.h> // memcpy
-#include "autoconf.h" // CONFIG_FLASH_START
-#include "board/io.h" // readl
-#include "board/irq.h" // irq_disable
-#include "board/usb_cdc.h" // usb_notify_ep0
-#include "board/usb_cdc_ep.h" // USB_CDC_EP_BULK_IN
-#include "internal.h" // enable_pclock
-#include "samd21.h" // USB
-#include "sched.h" // DECL_INIT
-
-
-/****************************************************************
- * USB transfer memory
- ****************************************************************/
-
-static uint8_t __aligned(4) ep0out[USB_CDC_EP0_SIZE];
-static uint8_t __aligned(4) ep0in[USB_CDC_EP0_SIZE];
-static uint8_t __aligned(4) acmin[USB_CDC_EP_ACM_SIZE];
-static uint8_t __aligned(4) bulkout[USB_CDC_EP_BULK_OUT_SIZE];
-static uint8_t __aligned(4) bulkin[USB_CDC_EP_BULK_IN_SIZE];
-
-static UsbDeviceDescriptor usb_desc[USB_CDC_EP_BULK_IN + 1] = {
- [0] = { {
- {
- .ADDR.reg = (uint32_t)ep0out,
- .PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(ep0out) >> 4),
- }, {
- .ADDR.reg = (uint32_t)ep0in,
- .PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(ep0in) >> 4),
- },
- } },
- [USB_CDC_EP_ACM] = { {
- {
- }, {
- .ADDR.reg = (uint32_t)acmin,
- .PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(acmin) >> 4),
- },
- } },
- [USB_CDC_EP_BULK_OUT] = { {
- {
- .ADDR.reg = (uint32_t)bulkout,
- .PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(bulkout) >> 4),
- }, {
- },
- } },
- [USB_CDC_EP_BULK_IN] = { {
- {
- }, {
- .ADDR.reg = (uint32_t)bulkin,
- .PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(bulkin) >> 4),
- },
- } },
-};
-
-
-/****************************************************************
- * Interface
- ****************************************************************/
-
-#define EP0 USB->DEVICE.DeviceEndpoint[0]
-#define EP_ACM USB->DEVICE.DeviceEndpoint[USB_CDC_EP_ACM]
-#define EP_BULKOUT USB->DEVICE.DeviceEndpoint[USB_CDC_EP_BULK_OUT]
-#define EP_BULKIN USB->DEVICE.DeviceEndpoint[USB_CDC_EP_BULK_IN]
-
-static int_fast8_t
-usb_write_packet(uint32_t ep, uint32_t bank, const void *data, uint_fast8_t len)
-{
- // Check if there is room for this packet
- UsbDeviceEndpoint *ude = &USB->DEVICE.DeviceEndpoint[ep];
- uint8_t sts = ude->EPSTATUS.reg;
- uint8_t bkrdy = (bank ? USB_DEVICE_EPSTATUS_BK1RDY
- : USB_DEVICE_EPSTATUS_BK0RDY);
- if (sts & bkrdy)
- return -1;
- // Copy the packet to the given buffer
- UsbDeviceDescBank *uddb = &usb_desc[ep].DeviceDescBank[bank];
- memcpy((void*)uddb->ADDR.reg, data, len);
- // Inform the USB hardware of the available packet
- uint32_t pcksize = uddb->PCKSIZE.reg;
- uint32_t c = pcksize & ~USB_DEVICE_PCKSIZE_BYTE_COUNT_Msk;
- uddb->PCKSIZE.reg = c | USB_DEVICE_PCKSIZE_BYTE_COUNT(len);
- ude->EPSTATUSSET.reg = bkrdy;
- return len;
-}
-
-static int_fast8_t
-usb_read_packet(uint32_t ep, uint32_t bank, void *data, uint_fast8_t max_len)
-{
- // Check if there is a packet ready
- UsbDeviceEndpoint *ude = &USB->DEVICE.DeviceEndpoint[ep];
- uint8_t sts = ude->EPSTATUS.reg;
- uint8_t bkrdy = (bank ? USB_DEVICE_EPSTATUS_BK1RDY
- : USB_DEVICE_EPSTATUS_BK0RDY);
- if (!(sts & bkrdy))
- return -1;
- // Copy the packet to the given buffer
- UsbDeviceDescBank *uddb = &usb_desc[ep].DeviceDescBank[bank];
- uint32_t pcksize = uddb->PCKSIZE.reg;
- uint32_t c = pcksize & USB_DEVICE_PCKSIZE_BYTE_COUNT_Msk;
- if (c > max_len)
- c = max_len;
- memcpy(data, (void*)uddb->ADDR.reg, c);
- // Notify the USB hardware that the space is now available
- ude->EPSTATUSCLR.reg = bkrdy;
- return c;
-}
-
-int_fast8_t
-usb_read_bulk_out(void *data, uint_fast8_t max_len)
-{
- return usb_read_packet(USB_CDC_EP_BULK_OUT, 0, data, max_len);
-}
-
-int_fast8_t
-usb_send_bulk_in(void *data, uint_fast8_t len)
-{
- return usb_write_packet(USB_CDC_EP_BULK_IN, 1, data, len);
-}
-
-int_fast8_t
-usb_read_ep0(void *data, uint_fast8_t max_len)
-{
- return usb_read_packet(0, 0, data, max_len);
-}
-
-int_fast8_t
-usb_read_ep0_setup(void *data, uint_fast8_t max_len)
-{
- return usb_read_ep0(data, max_len);
-}
-
-int_fast8_t
-usb_send_ep0(const void *data, uint_fast8_t len)
-{
- return usb_write_packet(0, 1, data, len);
-}
-
-void
-usb_stall_ep0(void)
-{
- EP0.EPSTATUSSET.reg = USB_DEVICE_EPSTATUS_STALLRQ(3);
-}
-
-static uint8_t set_address;
-
-void
-usb_set_address(uint_fast8_t addr)
-{
- writeb(&set_address, addr | USB_DEVICE_DADD_ADDEN);
- usb_send_ep0(NULL, 0);
-}
-
-void
-usb_set_configure(void)
-{
- EP_ACM.EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(4);
-
- EP_BULKOUT.EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(3);
- EP_BULKOUT.EPINTENSET.reg = (
- USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1);
-
- EP_BULKIN.EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(3);
- EP_BULKIN.EPINTENSET.reg = (
- USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1);
-}
-
-void
-usb_request_bootloader(void)
-{
- if (CONFIG_FLASH_START) {
- // Arduino Zero bootloader hack
- irq_disable();
- writel((void*)0x20007FFC, 0x07738135);
- NVIC_SystemReset();
- }
-}
-
-void
-usbserial_init(void)
-{
- // configure usb clock
- enable_pclock(USB_GCLK_ID, 0);
- // configure USBD+ and USBD- pins
- gpio_peripheral(GPIO('A', 24), 'G', 0);
- gpio_peripheral(GPIO('A', 25), 'G', 0);
- uint16_t trim = (readl((void*)USB_FUSES_TRIM_ADDR)
- & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos;
- uint16_t transp = (readl((void*)USB_FUSES_TRANSP_ADDR)
- & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
- uint16_t transn = (readl((void*)USB_FUSES_TRANSN_ADDR)
- & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
- USB->DEVICE.PADCAL.reg = (USB_PADCAL_TRIM(trim) | USB_PADCAL_TRANSP(transp)
- | USB_PADCAL_TRANSN(transn));
- // Enable USB in device mode
- USB->DEVICE.CTRLA.reg = USB_CTRLA_ENABLE;
- USB->DEVICE.DESCADD.reg = (uint32_t)usb_desc;
- EP0.EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(1) | USB_DEVICE_EPCFG_EPTYPE1(1);
- EP_ACM.EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(4);
- USB->DEVICE.CTRLB.reg = 0;
- // enable irqs
- USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_EORST;
- NVIC_SetPriority(USB_IRQn, 1);
- NVIC_EnableIRQ(USB_IRQn);
-}
-DECL_INIT(usbserial_init);
-
-void __visible
-USB_Handler(void)
-{
- uint8_t s = USB->DEVICE.INTFLAG.reg;
- if (s & USB_DEVICE_INTFLAG_EORST) {
- USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST;
- // Enable endpoint 0 irqs
- EP0.EPINTENSET.reg = (
- USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1
- | USB_DEVICE_EPINTENSET_RXSTP);
- }
-
- uint16_t ep = USB->DEVICE.EPINTSMRY.reg;
- if (ep & (1<<0)) {
- uint8_t sts = EP0.EPINTFLAG.reg;
- EP0.EPINTFLAG.reg = sts;
- if (set_address && sts & USB_DEVICE_EPINTFLAG_TRCPT1) {
- // Apply address after last "in" message transmitted
- USB->DEVICE.DADD.reg = set_address;
- set_address = 0;
- }
- usb_notify_ep0();
- }
- if (ep & (1<<USB_CDC_EP_BULK_OUT)) {
- uint8_t sts = EP_BULKOUT.EPINTFLAG.reg;
- EP_BULKOUT.EPINTFLAG.reg = sts;
- usb_notify_bulk_out();
- }
- if (ep & (1<<USB_CDC_EP_BULK_IN)) {
- uint8_t sts = EP_BULKIN.EPINTFLAG.reg;
- EP_BULKIN.EPINTFLAG.reg = sts;
- usb_notify_bulk_in();
- }
-}