From 1487aa267e3164cb851d07fd04a48c3906e072bc Mon Sep 17 00:00:00 2001 From: xiao <407652334@qq.com> Date: Sat, 16 Sep 2023 18:11:01 +0800 Subject: [PATCH] add Artery at32 check nxstyle check nxstyle --- arch/arm/Kconfig | 19 + arch/arm/include/at32/at32f43xxx_irq.h | 184 + arch/arm/include/at32/chip.h | 560 ++ arch/arm/include/at32/irq.h | 106 + arch/arm/src/at32/Kconfig | 7683 +++++++++++++++++ arch/arm/src/at32/Make.defs | 181 + arch/arm/src/at32/at32.h | 57 + arch/arm/src/at32/at32_adc.c | 4433 ++++++++++ arch/arm/src/at32/at32_adc.h | 1368 +++ arch/arm/src/at32/at32_allocateheap.c | 309 + arch/arm/src/at32/at32_can.c | 2535 ++++++ arch/arm/src/at32/at32_can.h | 152 + arch/arm/src/at32/at32_can_sock.c | 2484 ++++++ arch/arm/src/at32/at32_dbgmcu.h | 49 + arch/arm/src/at32/at32_dma.c | 47 + arch/arm/src/at32/at32_dma.h | 315 + arch/arm/src/at32/at32_dma_v1mux.c | 1464 ++++ arch/arm/src/at32/at32_dumpgpio.c | 138 + arch/arm/src/at32/at32_eth.c | 4030 +++++++++ arch/arm/src/at32/at32_eth.h | 107 + arch/arm/src/at32/at32_exti.h | 142 + arch/arm/src/at32/at32_exti_alarm.c | 138 + arch/arm/src/at32/at32_exti_gpio.c | 385 + arch/arm/src/at32/at32_exti_pwr.c | 145 + arch/arm/src/at32/at32_exti_pwr.h | 56 + arch/arm/src/at32/at32_exti_wakeup.c | 137 + arch/arm/src/at32/at32_flash.c | 41 + arch/arm/src/at32/at32_flash.h | 90 + arch/arm/src/at32/at32_gpio.c | 506 ++ arch/arm/src/at32/at32_gpio.h | 392 + arch/arm/src/at32/at32_i2c.c | 2700 ++++++ arch/arm/src/at32/at32_i2c.h | 89 + arch/arm/src/at32/at32_idle.c | 189 + arch/arm/src/at32/at32_irq.c | 501 ++ arch/arm/src/at32/at32_iwdg.c | 696 ++ arch/arm/src/at32/at32_lowputc.c | 403 + arch/arm/src/at32/at32_lowputc.h | 64 + arch/arm/src/at32/at32_lse.c | 72 + arch/arm/src/at32/at32_lsi.c | 84 + arch/arm/src/at32/at32_mpuinit.c | 101 + arch/arm/src/at32/at32_mpuinit.h | 75 + arch/arm/src/at32/at32_otgfs.h | 104 + arch/arm/src/at32/at32_otgfsdev.c | 5875 +++++++++++++ arch/arm/src/at32/at32_otgfshost.c | 5467 ++++++++++++ arch/arm/src/at32/at32_pm.h | 125 + arch/arm/src/at32/at32_pminitialize.c | 62 + arch/arm/src/at32/at32_pmsleep.c | 97 + arch/arm/src/at32/at32_pmstandby.c | 96 + arch/arm/src/at32/at32_pmstop.c | 107 + arch/arm/src/at32/at32_pwm.c | 4505 ++++++++++ arch/arm/src/at32/at32_pwm.h | 1147 +++ arch/arm/src/at32/at32_pwr.c | 345 + arch/arm/src/at32/at32_pwr.h | 195 + arch/arm/src/at32/at32_rcc.c | 228 + arch/arm/src/at32/at32_rcc.h | 233 + arch/arm/src/at32/at32_rtc.c | 42 + arch/arm/src/at32/at32_rtc.h | 188 + arch/arm/src/at32/at32_rtc_lowerhalf.c | 915 ++ arch/arm/src/at32/at32_sdio.c | 3177 +++++++ arch/arm/src/at32/at32_sdio.h | 134 + arch/arm/src/at32/at32_serial.c | 3049 +++++++ arch/arm/src/at32/at32_spi.c | 1949 +++++ arch/arm/src/at32/at32_spi.h | 184 + arch/arm/src/at32/at32_start.c | 201 + arch/arm/src/at32/at32_start.h | 47 + arch/arm/src/at32/at32_syscfg.h | 39 + arch/arm/src/at32/at32_tim.c | 1819 ++++ arch/arm/src/at32/at32_tim.h | 219 + arch/arm/src/at32/at32_tim_lowerhalf.c | 581 ++ arch/arm/src/at32/at32_timerisr.c | 153 + arch/arm/src/at32/at32_uart.h | 592 ++ arch/arm/src/at32/at32_uid.c | 46 + arch/arm/src/at32/at32_uid.h | 36 + arch/arm/src/at32/at32_usbhost.c | 415 + arch/arm/src/at32/at32_usbhost.h | 280 + arch/arm/src/at32/at32_userspace.c | 103 + arch/arm/src/at32/at32_userspace.h | 61 + arch/arm/src/at32/at32_waste.c | 42 + arch/arm/src/at32/at32_waste.h | 64 + arch/arm/src/at32/at32_wdg.h | 104 + arch/arm/src/at32/at32_wwdg.c | 794 ++ arch/arm/src/at32/at32f43xx_flash.c | 410 + arch/arm/src/at32/at32f43xxx_alarm.h | 122 + arch/arm/src/at32/at32f43xxx_rcc.c | 755 ++ arch/arm/src/at32/at32f43xxx_rtcc.c | 1626 ++++ arch/arm/src/at32/chip.h | 57 + arch/arm/src/at32/hardware/at32_adc.h | 39 + arch/arm/src/at32/hardware/at32_adc_v1.h | 633 ++ arch/arm/src/at32/hardware/at32_can.h | 469 + arch/arm/src/at32/hardware/at32_dbgmcu.h | 109 + arch/arm/src/at32/hardware/at32_dma.h | 324 + arch/arm/src/at32/hardware/at32_dmamux.h | 139 + arch/arm/src/at32/hardware/at32_eth.h | 738 ++ arch/arm/src/at32/hardware/at32_exti.h | 113 + arch/arm/src/at32/hardware/at32_flash.h | 226 + arch/arm/src/at32/hardware/at32_i2c.h | 237 + arch/arm/src/at32/hardware/at32_memorymap.h | 37 + arch/arm/src/at32/hardware/at32_pinmap.h | 36 + arch/arm/src/at32/hardware/at32_pwr.h | 87 + arch/arm/src/at32/hardware/at32_rtcc.h | 365 + arch/arm/src/at32/hardware/at32_sdio.h | 274 + arch/arm/src/at32/hardware/at32_spi.h | 181 + arch/arm/src/at32/hardware/at32_tim.h | 1057 +++ arch/arm/src/at32/hardware/at32_wdg.h | 140 + .../arm/src/at32/hardware/at32f43xxx_dmamux.h | 132 + arch/arm/src/at32/hardware/at32f43xxx_gpio.h | 356 + .../src/at32/hardware/at32f43xxx_memorymap.h | 217 + .../arm/src/at32/hardware/at32f43xxx_pinmap.h | 897 ++ arch/arm/src/at32/hardware/at32f43xxx_rcc.h | 568 ++ .../arm/src/at32/hardware/at32f43xxx_syscfg.h | 288 + arch/arm/src/at32/hardware/at32f43xxx_uart.h | 250 + arch/arm/src/at32/hardware/at32fxxxxx_otgfs.h | 1221 +++ boards/Kconfig | 11 + boards/arm/at32/at32f437-mini/Kconfig | 13 + boards/arm/at32/at32f437-mini/README.txt | 94 + .../at32/at32f437-mini/configs/adc/defconfig | 52 + .../at32f437-mini/configs/can_char/defconfig | 50 + .../configs/can_socket/defconfig | 62 + .../at32/at32f437-mini/configs/eth/defconfig | 70 + .../at32/at32f437-mini/configs/msc/defconfig | 57 + .../at32/at32f437-mini/configs/nsh/defconfig | 48 + .../at32/at32f437-mini/configs/pwm/defconfig | 53 + .../at32/at32f437-mini/configs/rtc/defconfig | 51 + .../at32f437-mini/configs/sdcard/defconfig | 59 + .../configs/systemview/defconfig | 57 + .../at32f437-mini/configs/usbnsh/defconfig | 53 + .../at32f437-mini/configs/usbserial/defconfig | 53 + boards/arm/at32/at32f437-mini/include/board.h | 271 + .../at32/at32f437-mini/include/nsh_romfsimg.h | 111 + boards/arm/at32/at32f437-mini/kernel/Makefile | 92 + .../at32f437-mini/kernel/at32_userspace.c | 100 + .../at32f437-mini/romfs/init.d/rc.sysinit | 15 + .../arm/at32/at32f437-mini/romfs/init.d/rcS | 2 + .../sysconfig/network-scripts/ipcfg-eth0 | 5 + .../arm/at32/at32f437-mini/scripts/Make.defs | 54 + .../at32f437-mini/scripts/kernel-space.ld | 96 + .../arm/at32/at32f437-mini/scripts/ld.script | 126 + .../arm/at32/at32f437-mini/scripts/memory.ld | 86 + .../at32/at32f437-mini/scripts/user-space.ld | 98 + boards/arm/at32/at32f437-mini/src/Makefile | 83 + boards/arm/at32/at32f437-mini/src/at32_adc.c | 235 + .../arm/at32/at32f437-mini/src/at32_appinit.c | 76 + boards/arm/at32/at32f437-mini/src/at32_at24.c | 128 + .../at32/at32f437-mini/src/at32_autoleds.c | 122 + boards/arm/at32/at32f437-mini/src/at32_boot.c | 115 + .../arm/at32/at32f437-mini/src/at32_bringup.c | 231 + boards/arm/at32/at32f437-mini/src/at32_can.c | 102 + .../arm/at32/at32f437-mini/src/at32_cansock.c | 58 + .../at32/at32f437-mini/src/at32_ethernet.c | 240 + boards/arm/at32/at32f437-mini/src/at32_gpio.c | 322 + .../arm/at32/at32f437-mini/src/at32_mmcsd.c | 109 + boards/arm/at32/at32f437-mini/src/at32_pwm.c | 107 + boards/arm/at32/at32f437-mini/src/at32_spi.c | 188 + .../arm/at32/at32f437-mini/src/at32_timer.c | 65 + boards/arm/at32/at32f437-mini/src/at32_usb.c | 347 + .../at32/at32f437-mini/src/at32_userleds.c | 215 + boards/arm/at32/at32f437-mini/src/at32_w25.c | 281 + .../at32/at32f437-mini/src/at32f437-mini.h | 458 + boards/arm/at32/at32f437-mini/tool/mkromfs.sh | 11 + 159 files changed, 84482 insertions(+) create mode 100644 arch/arm/include/at32/at32f43xxx_irq.h create mode 100644 arch/arm/include/at32/chip.h create mode 100644 arch/arm/include/at32/irq.h create mode 100644 arch/arm/src/at32/Kconfig create mode 100644 arch/arm/src/at32/Make.defs create mode 100644 arch/arm/src/at32/at32.h create mode 100644 arch/arm/src/at32/at32_adc.c create mode 100644 arch/arm/src/at32/at32_adc.h create mode 100644 arch/arm/src/at32/at32_allocateheap.c create mode 100644 arch/arm/src/at32/at32_can.c create mode 100644 arch/arm/src/at32/at32_can.h create mode 100644 arch/arm/src/at32/at32_can_sock.c create mode 100644 arch/arm/src/at32/at32_dbgmcu.h create mode 100644 arch/arm/src/at32/at32_dma.c create mode 100644 arch/arm/src/at32/at32_dma.h create mode 100644 arch/arm/src/at32/at32_dma_v1mux.c create mode 100644 arch/arm/src/at32/at32_dumpgpio.c create mode 100644 arch/arm/src/at32/at32_eth.c create mode 100644 arch/arm/src/at32/at32_eth.h create mode 100644 arch/arm/src/at32/at32_exti.h create mode 100644 arch/arm/src/at32/at32_exti_alarm.c create mode 100644 arch/arm/src/at32/at32_exti_gpio.c create mode 100644 arch/arm/src/at32/at32_exti_pwr.c create mode 100644 arch/arm/src/at32/at32_exti_pwr.h create mode 100644 arch/arm/src/at32/at32_exti_wakeup.c create mode 100644 arch/arm/src/at32/at32_flash.c create mode 100644 arch/arm/src/at32/at32_flash.h create mode 100644 arch/arm/src/at32/at32_gpio.c create mode 100644 arch/arm/src/at32/at32_gpio.h create mode 100644 arch/arm/src/at32/at32_i2c.c create mode 100644 arch/arm/src/at32/at32_i2c.h create mode 100644 arch/arm/src/at32/at32_idle.c create mode 100644 arch/arm/src/at32/at32_irq.c create mode 100644 arch/arm/src/at32/at32_iwdg.c create mode 100644 arch/arm/src/at32/at32_lowputc.c create mode 100644 arch/arm/src/at32/at32_lowputc.h create mode 100644 arch/arm/src/at32/at32_lse.c create mode 100644 arch/arm/src/at32/at32_lsi.c create mode 100644 arch/arm/src/at32/at32_mpuinit.c create mode 100644 arch/arm/src/at32/at32_mpuinit.h create mode 100644 arch/arm/src/at32/at32_otgfs.h create mode 100644 arch/arm/src/at32/at32_otgfsdev.c create mode 100644 arch/arm/src/at32/at32_otgfshost.c create mode 100644 arch/arm/src/at32/at32_pm.h create mode 100644 arch/arm/src/at32/at32_pminitialize.c create mode 100644 arch/arm/src/at32/at32_pmsleep.c create mode 100644 arch/arm/src/at32/at32_pmstandby.c create mode 100644 arch/arm/src/at32/at32_pmstop.c create mode 100644 arch/arm/src/at32/at32_pwm.c create mode 100644 arch/arm/src/at32/at32_pwm.h create mode 100644 arch/arm/src/at32/at32_pwr.c create mode 100644 arch/arm/src/at32/at32_pwr.h create mode 100644 arch/arm/src/at32/at32_rcc.c create mode 100644 arch/arm/src/at32/at32_rcc.h create mode 100644 arch/arm/src/at32/at32_rtc.c create mode 100644 arch/arm/src/at32/at32_rtc.h create mode 100644 arch/arm/src/at32/at32_rtc_lowerhalf.c create mode 100644 arch/arm/src/at32/at32_sdio.c create mode 100644 arch/arm/src/at32/at32_sdio.h create mode 100644 arch/arm/src/at32/at32_serial.c create mode 100644 arch/arm/src/at32/at32_spi.c create mode 100644 arch/arm/src/at32/at32_spi.h create mode 100644 arch/arm/src/at32/at32_start.c create mode 100644 arch/arm/src/at32/at32_start.h create mode 100644 arch/arm/src/at32/at32_syscfg.h create mode 100644 arch/arm/src/at32/at32_tim.c create mode 100644 arch/arm/src/at32/at32_tim.h create mode 100644 arch/arm/src/at32/at32_tim_lowerhalf.c create mode 100644 arch/arm/src/at32/at32_timerisr.c create mode 100644 arch/arm/src/at32/at32_uart.h create mode 100644 arch/arm/src/at32/at32_uid.c create mode 100644 arch/arm/src/at32/at32_uid.h create mode 100644 arch/arm/src/at32/at32_usbhost.c create mode 100644 arch/arm/src/at32/at32_usbhost.h create mode 100644 arch/arm/src/at32/at32_userspace.c create mode 100644 arch/arm/src/at32/at32_userspace.h create mode 100644 arch/arm/src/at32/at32_waste.c create mode 100644 arch/arm/src/at32/at32_waste.h create mode 100644 arch/arm/src/at32/at32_wdg.h create mode 100644 arch/arm/src/at32/at32_wwdg.c create mode 100644 arch/arm/src/at32/at32f43xx_flash.c create mode 100644 arch/arm/src/at32/at32f43xxx_alarm.h create mode 100644 arch/arm/src/at32/at32f43xxx_rcc.c create mode 100644 arch/arm/src/at32/at32f43xxx_rtcc.c create mode 100644 arch/arm/src/at32/chip.h create mode 100644 arch/arm/src/at32/hardware/at32_adc.h create mode 100644 arch/arm/src/at32/hardware/at32_adc_v1.h create mode 100644 arch/arm/src/at32/hardware/at32_can.h create mode 100644 arch/arm/src/at32/hardware/at32_dbgmcu.h create mode 100644 arch/arm/src/at32/hardware/at32_dma.h create mode 100644 arch/arm/src/at32/hardware/at32_dmamux.h create mode 100644 arch/arm/src/at32/hardware/at32_eth.h create mode 100644 arch/arm/src/at32/hardware/at32_exti.h create mode 100644 arch/arm/src/at32/hardware/at32_flash.h create mode 100644 arch/arm/src/at32/hardware/at32_i2c.h create mode 100644 arch/arm/src/at32/hardware/at32_memorymap.h create mode 100644 arch/arm/src/at32/hardware/at32_pinmap.h create mode 100644 arch/arm/src/at32/hardware/at32_pwr.h create mode 100644 arch/arm/src/at32/hardware/at32_rtcc.h create mode 100644 arch/arm/src/at32/hardware/at32_sdio.h create mode 100644 arch/arm/src/at32/hardware/at32_spi.h create mode 100644 arch/arm/src/at32/hardware/at32_tim.h create mode 100644 arch/arm/src/at32/hardware/at32_wdg.h create mode 100644 arch/arm/src/at32/hardware/at32f43xxx_dmamux.h create mode 100644 arch/arm/src/at32/hardware/at32f43xxx_gpio.h create mode 100644 arch/arm/src/at32/hardware/at32f43xxx_memorymap.h create mode 100644 arch/arm/src/at32/hardware/at32f43xxx_pinmap.h create mode 100644 arch/arm/src/at32/hardware/at32f43xxx_rcc.h create mode 100644 arch/arm/src/at32/hardware/at32f43xxx_syscfg.h create mode 100644 arch/arm/src/at32/hardware/at32f43xxx_uart.h create mode 100644 arch/arm/src/at32/hardware/at32fxxxxx_otgfs.h create mode 100644 boards/arm/at32/at32f437-mini/Kconfig create mode 100644 boards/arm/at32/at32f437-mini/README.txt create mode 100644 boards/arm/at32/at32f437-mini/configs/adc/defconfig create mode 100644 boards/arm/at32/at32f437-mini/configs/can_char/defconfig create mode 100644 boards/arm/at32/at32f437-mini/configs/can_socket/defconfig create mode 100644 boards/arm/at32/at32f437-mini/configs/eth/defconfig create mode 100644 boards/arm/at32/at32f437-mini/configs/msc/defconfig create mode 100644 boards/arm/at32/at32f437-mini/configs/nsh/defconfig create mode 100644 boards/arm/at32/at32f437-mini/configs/pwm/defconfig create mode 100644 boards/arm/at32/at32f437-mini/configs/rtc/defconfig create mode 100644 boards/arm/at32/at32f437-mini/configs/sdcard/defconfig create mode 100644 boards/arm/at32/at32f437-mini/configs/systemview/defconfig create mode 100644 boards/arm/at32/at32f437-mini/configs/usbnsh/defconfig create mode 100644 boards/arm/at32/at32f437-mini/configs/usbserial/defconfig create mode 100644 boards/arm/at32/at32f437-mini/include/board.h create mode 100644 boards/arm/at32/at32f437-mini/include/nsh_romfsimg.h create mode 100644 boards/arm/at32/at32f437-mini/kernel/Makefile create mode 100644 boards/arm/at32/at32f437-mini/kernel/at32_userspace.c create mode 100644 boards/arm/at32/at32f437-mini/romfs/init.d/rc.sysinit create mode 100644 boards/arm/at32/at32f437-mini/romfs/init.d/rcS create mode 100644 boards/arm/at32/at32f437-mini/romfs/sysconfig/network-scripts/ipcfg-eth0 create mode 100644 boards/arm/at32/at32f437-mini/scripts/Make.defs create mode 100644 boards/arm/at32/at32f437-mini/scripts/kernel-space.ld create mode 100644 boards/arm/at32/at32f437-mini/scripts/ld.script create mode 100644 boards/arm/at32/at32f437-mini/scripts/memory.ld create mode 100644 boards/arm/at32/at32f437-mini/scripts/user-space.ld create mode 100644 boards/arm/at32/at32f437-mini/src/Makefile create mode 100644 boards/arm/at32/at32f437-mini/src/at32_adc.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_appinit.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_at24.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_autoleds.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_boot.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_bringup.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_can.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_cansock.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_ethernet.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_gpio.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_mmcsd.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_pwm.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_spi.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_timer.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_usb.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_userleds.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32_w25.c create mode 100644 boards/arm/at32/at32f437-mini/src/at32f437-mini.h create mode 100644 boards/arm/at32/at32f437-mini/tool/mkromfs.sh diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e3384b26ad..f9495b6f35 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -659,6 +659,21 @@ config ARCH_CHIP_GOLDFISH_ARM ---help--- GOLDFISH virt platform (ARMv7a) +config ARCH_CHIP_AT32 + bool "Artery AT32 F4" + select ARCH_HAVE_MPU + select ARCH_HAVE_FETCHADD + select ARCH_HAVE_I2CRESET + select ARCH_HAVE_HEAPCHECK + select ARCH_HAVE_PROGMEM + select ARCH_HAVE_SPI_BITORDER + select ARCH_HAVE_TICKLESS + select ARCH_HAVE_TIMEKEEPING + select ARM_HAVE_MPU_UNIFIED + select ARMV7M_HAVE_STACKCHECK + ---help--- + Artery AT32 architectures (ARM Cortex-M4) + config ARCH_CHIP_ARM_CUSTOM bool "Custom ARM chip" select ARCH_CHIP_CUSTOM @@ -1065,6 +1080,7 @@ config ARCH_CHIP default "tlsr82" if ARCH_CHIP_TLSR82 default "qemu" if ARCH_CHIP_QEMU_ARM default "goldfish" if ARCH_CHIP_GOLDFISH_ARM + default "at32" if ARCH_CHIP_AT32 config ARM_THUMB bool "Thumb Mode" @@ -1543,4 +1559,7 @@ endif if ARCH_CHIP_GOLDFISH_ARM source "arch/arm/src/goldfish/Kconfig" endif +if ARCH_CHIP_AT32 +source "arch/arm/src/at32/Kconfig" +endif endif # ARCH_ARM diff --git a/arch/arm/include/at32/at32f43xxx_irq.h b/arch/arm/include/at32/at32f43xxx_irq.h new file mode 100644 index 0000000000..aadf5c38e5 --- /dev/null +++ b/arch/arm/include/at32/at32f43xxx_irq.h @@ -0,0 +1,184 @@ +/**************************************************************************** + * arch/arm/include/at32/at32f43xxx_irq.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This file should never be included directly but, rather, + * only indirectly through nuttx/irq.h + */ + +#ifndef __ARCH_ARM_INCLUDE_AT32_AT32F43XXX_IRQ_H +#define __ARCH_ARM_INCLUDE_AT32_AT32F43XXX_IRQ_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Prototypes + ****************************************************************************/ + +/* IRQ numbers. + * The IRQ number corresponds vector number and hence map directly to + * bits in the NVIC. This does, however, waste several words of memory in + * the IRQ to handle mapping tables. + * + * Processor Exceptions (vectors 0-15). These common definitions can + * be found in nuttx/arch/arm/include/at32/irq.h + * + * External interrupts (vectors >= 16) + */ + +#define AT32_IRQ_WWDG (AT32_IRQ_FIRST+0) /* 0: Window Watchdog interrupt */ +#define AT32_IRQ_PVD (AT32_IRQ_FIRST+1) /* 1: PVD through EXTI Line detection interrupt */ +#define AT32_IRQ_TAMPER (AT32_IRQ_FIRST+2) /* 2: Tamper and time stamp interrupts */ +#define AT32_IRQ_TIMESTAMP (AT32_IRQ_FIRST+2) /* 2: Tamper and time stamp interrupts */ +#define AT32_IRQ_RTC_WKUP (AT32_IRQ_FIRST+3) /* 3: RTC global interrupt */ +#define AT32_IRQ_FLASH (AT32_IRQ_FIRST+4) /* 4: Flash global interrupt */ +#define AT32_IRQ_RCC (AT32_IRQ_FIRST+5) /* 5: RCC global interrupt */ +#define AT32_IRQ_EXTI0 (AT32_IRQ_FIRST+6) /* 6: EXTI Line 0 interrupt */ +#define AT32_IRQ_EXTI1 (AT32_IRQ_FIRST+7) /* 7: EXTI Line 1 interrupt */ +#define AT32_IRQ_EXTI2 (AT32_IRQ_FIRST+8) /* 8: EXTI Line 2 interrupt */ +#define AT32_IRQ_EXTI3 (AT32_IRQ_FIRST+9) /* 9: EXTI Line 3 interrupt */ +#define AT32_IRQ_EXTI4 (AT32_IRQ_FIRST+10) /* 10: EXTI Line 4 interrupt */ +#define AT32_IRQ_EDMAS1 (AT32_IRQ_FIRST+11) /* 11: EDMA Stream 1 global interrupt */ +#define AT32_IRQ_EDMAS2 (AT32_IRQ_FIRST+12) /* 12: EDMA Stream 2 global interrupt */ +#define AT32_IRQ_EDMAS3 (AT32_IRQ_FIRST+13) /* 13: EDMA Stream 3 global interrupt */ +#define AT32_IRQ_EDMAS4 (AT32_IRQ_FIRST+14) /* 14: EDMA Stream 4 global interrupt */ +#define AT32_IRQ_EDMAS5 (AT32_IRQ_FIRST+15) /* 15: EDMA Stream 5 global interrupt */ +#define AT32_IRQ_EDMAS6 (AT32_IRQ_FIRST+16) /* 16: EDMA Stream 6 global interrupt */ +#define AT32_IRQ_EDMAS7 (AT32_IRQ_FIRST+17) /* 17: EDMA Stream 7 global interrupt */ +#define AT32_IRQ_ADC (AT32_IRQ_FIRST+18) /* 18: ADC1, ADC2, and ADC3 global interrupt */ +#define AT32_IRQ_CAN1TX (AT32_IRQ_FIRST+19) /* 19: CAN1 TX interrupts */ +#define AT32_IRQ_CAN1RX0 (AT32_IRQ_FIRST+20) /* 20: CAN1 RX0 interrupts */ +#define AT32_IRQ_CAN1RX1 (AT32_IRQ_FIRST+21) /* 21: CAN1 RX1 interrupt */ +#define AT32_IRQ_CAN1SCE (AT32_IRQ_FIRST+22) /* 22: CAN1 SCE interrupt */ +#define AT32_IRQ_EXTI95 (AT32_IRQ_FIRST+23) /* 23: EXTI Line[9:5] interrupts */ +#define AT32_IRQ_TIM1BRK (AT32_IRQ_FIRST+24) /* 24: TIM1 Break interrupt */ +#define AT32_IRQ_TIM9 (AT32_IRQ_FIRST+24) /* 24: TIM9 global interrupt */ +#define AT32_IRQ_TIM1UP (AT32_IRQ_FIRST+25) /* 25: TIM1 Update interrupt */ +#define AT32_IRQ_TIM10 (AT32_IRQ_FIRST+25) /* 25: TIM10 global interrupt */ +#define AT32_IRQ_TIM1TRGCOM (AT32_IRQ_FIRST+26) /* 26: TIM1 Trigger and Commutation interrupts */ +#define AT32_IRQ_TIM11 (AT32_IRQ_FIRST+26) /* 26: TIM11 global interrupt */ +#define AT32_IRQ_TIM1CC (AT32_IRQ_FIRST+27) /* 27: TIM1 Capture Compare interrupt */ +#define AT32_IRQ_TIM2 (AT32_IRQ_FIRST+28) /* 28: TIM2 global interrupt */ +#define AT32_IRQ_TIM3 (AT32_IRQ_FIRST+29) /* 29: TIM3 global interrupt */ +#define AT32_IRQ_TIM4 (AT32_IRQ_FIRST+30) /* 30: TIM4 global interrupt */ +#define AT32_IRQ_I2C1EV (AT32_IRQ_FIRST+31) /* 31: I2C1 event interrupt */ +#define AT32_IRQ_I2C1ER (AT32_IRQ_FIRST+32) /* 32: I2C1 error interrupt */ +#define AT32_IRQ_I2C2EV (AT32_IRQ_FIRST+33) /* 33: I2C2 event interrupt */ +#define AT32_IRQ_I2C2ER (AT32_IRQ_FIRST+34) /* 34: I2C2 error interrupt */ +#define AT32_IRQ_SPI1 (AT32_IRQ_FIRST+35) /* 35: SPI1 global interrupt */ +#define AT32_IRQ_SPI2 (AT32_IRQ_FIRST+36) /* 36: SPI2 global interrupt */ +#define AT32_IRQ_USART1 (AT32_IRQ_FIRST+37) /* 37: USART1 global interrupt */ +#define AT32_IRQ_USART2 (AT32_IRQ_FIRST+38) /* 38: USART2 global interrupt */ +#define AT32_IRQ_USART3 (AT32_IRQ_FIRST+39) /* 39: USART3 global interrupt */ +#define AT32_IRQ_EXTI1510 (AT32_IRQ_FIRST+40) /* 40: EXTI Line[15:10] interrupts */ +#define AT32_IRQ_RTCALRM (AT32_IRQ_FIRST+41) /* 41: RTC alarm through EXTI line interrupt */ +#define AT32_IRQ_OTGFSWKUP (AT32_IRQ_FIRST+42) /* 42: USB On-The-Go FS1 Wakeup through EXTI line interrupt */ +#define AT32_IRQ_TIM8BRK (AT32_IRQ_FIRST+43) /* 43: TIM8 Break interrupt */ +#define AT32_IRQ_TIM12 (AT32_IRQ_FIRST+43) /* 43: TIM12 global interrupt */ +#define AT32_IRQ_TIM8UP (AT32_IRQ_FIRST+44) /* 44: TIM8 Update interrupt */ +#define AT32_IRQ_TIM13 (AT32_IRQ_FIRST+44) /* 44: TIM13 global interrupt */ +#define AT32_IRQ_TIM8TRGCOM (AT32_IRQ_FIRST+45) /* 45: TIM8 Trigger and Commutation interrupts */ +#define AT32_IRQ_TIM14 (AT32_IRQ_FIRST+45) /* 45: TIM14 global interrupt */ +#define AT32_IRQ_TIM8CC (AT32_IRQ_FIRST+46) /* 46: TIM8 Capture Compare interrupt */ +#define AT32_IRQ_EDMAS8 (AT32_IRQ_FIRST+47) /* 47: EDMA Stream 8 global interrupt */ +#define AT32_IRQ_XSMC (AT32_IRQ_FIRST+48) /* 48: XSMC global interrupt */ +#define AT32_IRQ_SDIO (AT32_IRQ_FIRST+49) /* 49: SDIO global interrupt */ +#define AT32_IRQ_TIM5 (AT32_IRQ_FIRST+50) /* 50: TIM5 global interrupt */ +#define AT32_IRQ_SPI3 (AT32_IRQ_FIRST+51) /* 51: SPI3 global interrupt */ +#define AT32_IRQ_UART4 (AT32_IRQ_FIRST+52) /* 52: UART4 global interrupt */ +#define AT32_IRQ_UART5 (AT32_IRQ_FIRST+53) /* 53: UART5 global interrupt */ +#define AT32_IRQ_TIM6 (AT32_IRQ_FIRST+54) /* 54: TIM6 global interrupt */ +#define AT32_IRQ_DAC (AT32_IRQ_FIRST+54) /* 54: DAC1 and DAC2 underrun error interrupts */ +#define AT32_IRQ_TIM7 (AT32_IRQ_FIRST+55) /* 55: TIM7 global interrupt */ +#define AT32_IRQ_DMA1CH1 (AT32_IRQ_FIRST+56) /* 56: DMA1 Stream 1 global interrupt */ +#define AT32_IRQ_DMA1CH2 (AT32_IRQ_FIRST+57) /* 57: DMA1 Stream 2 global interrupt */ +#define AT32_IRQ_DMA1CH3 (AT32_IRQ_FIRST+58) /* 58: DMA1 Stream 3 global interrupt */ +#define AT32_IRQ_DMA1CH4 (AT32_IRQ_FIRST+59) /* 59: DMA1 Stream 4 global interrupt */ +#define AT32_IRQ_DMA1CH5 (AT32_IRQ_FIRST+60) /* 60: DMA1 Stream 5 global interrupt */ +#if defined(CONFIG_AT32_AT32F437) +# define AT32_IRQ_ETH (AT32_IRQ_FIRST+61) /* 61: Ethernet global interrupt */ +# define AT32_IRQ_ETHWKUP (AT32_IRQ_FIRST+62) /* 62: Ethernet Wakeup through EXTI line interrupt */ +#endif +#define AT32_IRQ_CAN2TX (AT32_IRQ_FIRST+63) /* 63: CAN2 TX interrupts */ +#define AT32_IRQ_CAN2RX0 (AT32_IRQ_FIRST+64) /* 64: CAN2 RX0 interrupts */ +#define AT32_IRQ_CAN2RX1 (AT32_IRQ_FIRST+65) /* 65: CAN2 RX1 interrupt */ +#define AT32_IRQ_CAN2SCE (AT32_IRQ_FIRST+66) /* 66: CAN2 SCE interrupt */ +#define AT32_IRQ_OTGFS (AT32_IRQ_FIRST+67) /* 67: USB On The Go FS global interrupt */ +#define AT32_IRQ_DMA1CH6 (AT32_IRQ_FIRST+68) /* 68: DMA1 Stream 6 global interrupt */ +#define AT32_IRQ_DMA1CH7 (AT32_IRQ_FIRST+69) /* 69: DMA1 Stream 7 global interrupt */ +#define AT32_IRQ_USART6 (AT32_IRQ_FIRST+71) /* 71: USART6 global interrupt */ +#define AT32_IRQ_I2C3EV (AT32_IRQ_FIRST+72) /* 72: I2C3 event interrupt */ +#define AT32_IRQ_I2C3ER (AT32_IRQ_FIRST+73) /* 73: I2C3 error interrupt */ +#define AT32_IRQ_OTGFS2 (AT32_IRQ_FIRST+77) /* 77: USB On The Go FS2 global interrupt */ +#define AT32_IRQ_DVP (AT32_IRQ_FIRST+78) /* 78: DVP global interrupt */ +#define AT32_IRQ_FPU (AT32_IRQ_FIRST+81) /* 81: FPU global interrupt */ +#define AT32_IRQ_UART7 (AT32_IRQ_FIRST+82) /* 82: UART7 interrupt */ +#define AT32_IRQ_UART8 (AT32_IRQ_FIRST+83) /* 83: UART8 interrupt */ +#define AT32_IRQ_SPI4 (AT32_IRQ_FIRST+84) /* 84: SPI4 interrupt */ +#define AT32_IRQ_QUADSPI2 (AT32_IRQ_FIRST+91) /* 91: SAI2 Global interrupt */ +#define AT32_IRQ_QUADSPI1 (AT32_IRQ_FIRST+92) /* 92: QuadSPI Global interrupt */ +#define AT32_IRQ_DMAMUX (AT32_IRQ_FIRST+94) /* DMAMUX over interrupt */ +#define AT32_IRQ_SDIO2 (AT32_IRQ_FIRST+102) /* SDIO2 interrupt */ +#define AT32_IRQ_ACC (AT32_IRQ_FIRST+103) /* ACC interrupt */ +#define AT32_IRQ_TIM20BRK (AT32_IRQ_FIRST+104) /* TIM20 break up interrupt */ +#define AT32_IRQ_TIM20UP (AT32_IRQ_FIRST+105) /* TIM20 over interrupt */ +#define AT32_IRQ_TIM20 (AT32_IRQ_FIRST+106) /* TIM20 global interrupt */ +#define AT32_IRQ_TIM20CC (AT32_IRQ_FIRST+107) /* TIM20 Capture Compare interrupt */ +#define AT32_IRQ_DMA2CH1 (AT32_IRQ_FIRST+108) /* DMA2 Stream 1 global interrupt */ +#define AT32_IRQ_DMA2CH2 (AT32_IRQ_FIRST+109) /* DMA2 Stream 2 global interrupt */ +#define AT32_IRQ_DMA2CH3 (AT32_IRQ_FIRST+110) /* DMA2 Stream 3 global interrupt */ +#define AT32_IRQ_DMA2CH4 (AT32_IRQ_FIRST+111) /* DMA2 Stream 4 global interrupt */ +#define AT32_IRQ_DMA2CH5 (AT32_IRQ_FIRST+112) /* DMA2 Stream 5 global interrupt */ +#define AT32_IRQ_DMA2CH6 (AT32_IRQ_FIRST+113) /* DMA2 Stream 6 global interrupt */ +#define AT32_IRQ_DMA2CH7 (AT32_IRQ_FIRST+114) /* DMA2 Stream 7 global interrupt */ + +#if defined(CONFIG_AT32_AT32F435) || defined(CONFIG_AT32_AT32F437) +# define AT32_IRQ_NEXTINT (115) +# define NR_IRQS (AT32_IRQ_FIRST+115) +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif + +#endif /* __ARCH_ARM_INCLUDE_AT32_AT32F43XXX_IRQ_H */ \ No newline at end of file diff --git a/arch/arm/include/at32/chip.h b/arch/arm/include/at32/chip.h new file mode 100644 index 0000000000..46dc1093fa --- /dev/null +++ b/arch/arm/include/at32/chip.h @@ -0,0 +1,560 @@ +/**************************************************************************** + * arch/arm/include/at32/chip.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_INCLUDE_AT32_CHIP_H +#define __ARCH_ARM_INCLUDE_AT32_CHIP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Prototypes + ****************************************************************************/ + +/* Check the AT32 family configuration. + * It must be done in arch/arm/src/at32/Kconfig ! + */ + +#ifdef CONFIG_AT32_AT32F43XX +# define __HAVE_F4 1 +#else +# define __HAVE_F4 0 +#endif + +#if ((__HAVE_F1 + __HAVE_F2 + __HAVE_F30 + __HAVE_F33 + __HAVE_F37 + __HAVE_F4 + \ + __HAVE_G4 + __HAVE_L1) != 1) +# error "Only one AT32 family must be selected !" +#endif + +#ifdef CONFIG_AT32_LOWDENSITY +# define __HAVE_LD 1 +#else +# define __HAVE_LD 0 +#endif +#ifdef CONFIG_AT32_MEDIUMDENSITY +# define __HAVE_MD 1 +#else +# define __HAVE_MD 0 +#endif +#ifdef CONFIG_AT32_MEDIUMPLUSDENSITY +# define __HAVE_MPD 1 +#else +# define __HAVE_MPD 0 +#endif +#ifdef CONFIG_AT32_HIGHDENSITY +# define __HAVE_HD 1 +#else +# define __HAVE_HD 0 +#endif + +#if (__HAVE_LD +__HAVE_MD + __HAVE_MPD + __HAVE_HD) > 1 +# error "Up to one density configuration must be selected" +#endif + +/* Get customizations for each supported chip and provide alternate function + * pin-mapping + * + * NOTE: Each GPIO pin may serve either for general purpose I/O or for a + * special alternate function (such as USART, CAN, USB, SDIO, etc.). That + * particular pin-mapping will depend on the package and AT32 family. If + * you are incorporating a new AT32 chip into NuttX, you will need to add + * the pin-mapping to a header file and to include that header file below. + * The chip-specific pin-mapping is defined in the chip datasheet. + */ + +/* AT32 F4 Family ***********************************************************/ +#if defined(CONFIG_ARCH_CHIP_AT32F435RC) /* LQFP 64 10x10x1.4 256Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 0 /* No FSMC */ +# define AT32_NATIM 3 /* 3 advanced timers TIM1 and 8 */ +# define AT32_NGTIM 2 /* 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 8 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* 2 basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 4 /* SPI1-4 */ +# define AT32_NI2S 4 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 8 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 2 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 2 /* USB OTG FS/HS */ +# define AT32_NGPIO 53 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 0 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F435RG) /* LQFP 64 10x10x1.4 1024Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 0 /* No FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 53 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F435RM) /* LQFP 64 10x10x1.4 4032Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 0 /* No FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 53 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F435VC) /* LQFP 100 14x14x1.4 256Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 84 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F435VG) /* LQFP 100 14x14x1.4 1024Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 84 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F435VM) /* LQFP 100 14x14x1.4 4032Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 84 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F435ZC) /* LQFP 144 20x20x1.4 256Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 116 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 24 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F435ZG) /* LQFP 144 20x20x1.4 1024Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 116 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 24 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F435ZM) /* LQFP 144 20x20x1.4 4032Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 116 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 24 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F437RC) /* LQFP 64 10x10x1.4 256Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 0 /* No FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 53 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F437RG) /* LQFP 64 10x10x1.4 1024Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 0 /* No FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 53 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F437RM) /* LQFP 64 10x10x1.4 4032Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 0 /* No FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 53 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 0 /* No Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 0 /* No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F437VC) /* LQFP-100 256Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 84 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 1 /* 100/100 Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 1 /* Digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F437VG) /* LQFP-100 14x14x1.4 1024Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 3 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 2 /* 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 8 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 4 /* SPI1-3 */ +# define AT32_NI2S 4 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 8 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 2 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 2 /* USB OTG FS/HS */ +# define AT32_NGPIO 84 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 1 /* 12-bit DAC1, 1 channel */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 1 /* 100/100 Ethernet MAC */ +# define AT32_NRNG 0 /* Random number generator (RNG) */ +# define AT32_NDCMI 1 /* Digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F437VM) /* LQFP-100 14x14x1.4 4032Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 3 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 2 /* 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 8 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 4 /* SPI1-3 */ +# define AT32_NI2S 4 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 8 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 2 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 2 /* USB OTG FS/HS */ +# define AT32_NGPIO 84 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 16 channels */ +# define AT32_NDAC 1 /* 12-bit DAC1, 1 channel */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 1 /* 100/100 Ethernet MAC */ +# define AT32_NRNG 0 /* Random number generator (RNG) */ +# define AT32_NDCMI 1 /* Digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F437ZC) /* LQFP-144 256Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 116 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 24 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 1 /* 100/100 Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 1 /* Digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F437ZG) /* LQFP 144 20x20x1.4 1024Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 116 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 24 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 1 /* 100/100 Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 1 /* Digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_AT32F437ZM) /* LQFP 144 20x20x1.4 4032Kb FLASH 384Kb SRAM */ +# define AT32_NFSMC 1 /* FSMC */ +# define AT32_NATIM 2 /* Two advanced timers TIM1 and 8 */ +# define AT32_NGTIM 4 /* 16-bit general timers TIM3 and 4 with DMA + * 32-bit general timers TIM2 and 5 with DMA */ +# define AT32_NGTIMNDMA 6 /* 16-bit general timers TIM9-14 without DMA */ +# define AT32_NBTIM 2 /* Two basic timers, TIM6-7 */ +# define AT32_NDMA 2 /* DMA1-2 */ +# define AT32_NSPI 3 /* SPI1-3 */ +# define AT32_NI2S 2 /* I2S1-2 (multiplexed with SPI2-3) */ +# define AT32_NUSART 6 /* USART1-3 and 6, UART 4-5 */ +# define AT32_NI2C 3 /* I2C1-3 */ +# define AT32_NCAN 2 /* CAN1-2 */ +# define AT32_NSDIO 1 /* SDIO */ +# define AT32_NLCD 0 /* No LCD */ +# define AT32_NUSBOTG 1 /* USB OTG FS/HS */ +# define AT32_NGPIO 116 /* GPIOA-I */ +# define AT32_NADC 3 /* 12-bit ADC1-3, 24 channels */ +# define AT32_NDAC 2 /* 12-bit DAC1, 2 channels */ +# define AT32_NCAPSENSE 0 /* No capacitive sensing channels */ +# define AT32_NCRC 1 /* CRC */ +# define AT32_NETHERNET 1 /* 100/100 Ethernet MAC */ +# define AT32_NRNG 1 /* Random number generator (RNG) */ +# define AT32_NDCMI 1 /* Digital camera interface (DCMI) */ + +#else +# error "Unsupported AT32 chip" +#endif + +/* Peripheral IP versions ***************************************************/ + +/* Peripheral IP versions are invariant and should be decided here, not in + * Kconfig. + * + * REVISIT: Currently only SPI IP version is handled here, with others being + * handled in Kconfig. Those others need to be gradually refactored + * and resolved here. + */ + +#if defined(CONFIG_AT32_AT32F43XX) +# define AT32_HAVE_IP_SPI_V2 +#else +# error "Did not resolve peripheral IP versions!" +#endif + +/* NVIC priority levels *****************************************************/ + +#define NVIC_SYSH_PRIORITY_MIN 0xf0 /* All bits set in minimum priority */ +#define NVIC_SYSH_PRIORITY_DEFAULT 0x80 /* Midpoint is the default */ +#define NVIC_SYSH_PRIORITY_MAX 0x00 /* Zero is maximum priority */ +#define NVIC_SYSH_PRIORITY_STEP 0x10 /* Four bits of interrupt priority used */ + +#endif /* __ARCH_ARM_INCLUDE_AT32_CHIP_H */ diff --git a/arch/arm/include/at32/irq.h b/arch/arm/include/at32/irq.h new file mode 100644 index 0000000000..adad8facf4 --- /dev/null +++ b/arch/arm/include/at32/irq.h @@ -0,0 +1,106 @@ +/**************************************************************************** + * arch/arm/include/at32/irq.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This file should never be included directly but, rather, + * only indirectly through nuttx/irq.h + */ + +#ifndef __ARCH_ARM_INCLUDE_AT32_IRQ_H +#define __ARCH_ARM_INCLUDE_AT32_IRQ_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Prototypes + ****************************************************************************/ + +/* IRQ numbers. + * The IRQ number corresponds vector number and hence map directly to + * bits in the NVIC. This does, however, waste several words of memory in + * the IRQ to handle mapping tables. + */ + +/* Processor Exceptions (vectors 0-15) */ + +#define AT32_IRQ_RESERVED (0) /* Reserved vector (only used with CONFIG_DEBUG_FEATURES) */ + /* Vector 0: Reset stack pointer value */ + /* Vector 1: Reset (not handler as an IRQ) */ +#define AT32_IRQ_NMI (2) /* Vector 2: Non-Maskable Interrupt (NMI) */ +#define AT32_IRQ_HARDFAULT (3) /* Vector 3: Hard fault */ +#define AT32_IRQ_MEMFAULT (4) /* Vector 4: Memory management (MPU) */ +#define AT32_IRQ_BUSFAULT (5) /* Vector 5: Bus fault */ +#define AT32_IRQ_USAGEFAULT (6) /* Vector 6: Usage fault */ +#define AT32_IRQ_SVCALL (11) /* Vector 11: SVC call */ +#define AT32_IRQ_DBGMONITOR (12) /* Vector 12: Debug Monitor */ + /* Vector 13: Reserved */ +#define AT32_IRQ_PENDSV (14) /* Vector 14: Pendable system service request */ +#define AT32_IRQ_SYSTICK (15) /* Vector 15: System tick */ + +/* External interrupts (vectors >= 16). + * These definitions are chip-specific + */ + +#define AT32_IRQ_FIRST (16) /* Vector number of the first external interrupt */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#if defined(CONFIG_AT32_AT32F43XX) +# include + +#else +# error "Unsupported AT32 chip" +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif + +#endif /* __ARCH_ARM_INCLUDE_AT32_IRQ_H */ diff --git a/arch/arm/src/at32/Kconfig b/arch/arm/src/at32/Kconfig new file mode 100644 index 0000000000..9fd431b77e --- /dev/null +++ b/arch/arm/src/at32/Kconfig @@ -0,0 +1,7683 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +comment "AT32 Configuration Options" + +choice + prompt "AT32 Chip Selection" + default ARCH_CHIP_AT32F437VM + depends on ARCH_CHIP_AT32 + + +config ARCH_CHIP_AT32F437VM + bool "AT32F437VM" + select AT32_AT32F43XX + select AT32_AT32F437 + ---help--- + AT32F43X 100-pin , 4032KB FLASH, 384KB SRAM + +config ARCH_CHIP_AT32F437RM + bool "AT32F437RM" + select AT32_AT32F43XX + select AT32_AT32F437 + ---help--- + AT32F43X 64-pin , 4032KB FLASH, 384KB SRAM + +config ARCH_CHIP_AT32F437VG + bool "AT32F437VG" + select AT32_AT32F43XX + select AT32_AT32F437 + ---help--- + AT32F43X 100-pin , 1024KB FLASH, 384KB SRAM + +config ARCH_CHIP_AT32F437RG + bool "AT32F437RG" + select AT32_AT32F43XX + select AT32_AT32F437 + ---help--- + AT32F43X 64-pin , 1024KB FLASH, 384KB SRAM + +config ARCH_CHIP_AT32F435VM + bool "AT32F435VM" + select AT32_AT32F43XX + select AT32_AT32F435 + ---help--- + AT32F43X 100-pin , 4032KB FLASH, 384KB SRAM + +config ARCH_CHIP_AT32F435RM + bool "AT32F435RM" + select AT32_AT32F43XX + select AT32_AT32F435 + ---help--- + AT32F43X 64-pin , 4032KB FLASH, 384KB SRAM + +config ARCH_CHIP_AT32F435VG + bool "AT32F435VG" + select AT32_AT32F43XX + select AT32_AT32F435 + ---help--- + AT32F43X 100-pin , 1024KB FLASH, 384KB SRAM + +config ARCH_CHIP_AT32F435RG + bool "AT32F435RG" + select AT32_AT32F43XX + select AT32_AT32F435 + ---help--- + AT32F43X 64-pin , 1024KB FLASH, 384KB SRAM + +endchoice + +choice + prompt "Override Flash Size Designator" + default AT32_FLASH_CONFIG_DEFAULT + depends on ARCH_CHIP_AT32 + ---help--- + AT32F series parts numbering (sans the package type) + ends with a number or letter that designates the FLASH size. + + Designator Size in KiB + 8 64 + B 128 + C 256 + E 512 + G 1024 + I 2048 + M 4032 + + This configuration option defaults to using the configuration based + on that designator or the default smaller size if there is no last + character designator is present in the AT32 Chip Selection. + + Examples: + If the AT32F437VM is chosen, the Flash configuration would be + 'M', if a variant of the part with a 4032 KiB Flash is released + in the future one could simply select the 'M' designator here. + + + +config AT32_FLASH_CONFIG_DEFAULT + bool "Default" + +config AT32_FLASH_CONFIG_8 + bool "8 64KiB" + +config AT32_FLASH_CONFIG_B + bool "B 128KiB" + +config AT32_FLASH_CONFIG_C + bool "C 256KiB" + +config AT32_FLASH_CONFIG_E + bool "E 512KiB" + +config AT32_FLASH_CONFIG_G + bool "G 1024KiB" + +config AT32_FLASH_CONFIG_I + bool "I 2048KiB" + +config AT32_FLASH_CONFIG_M + bool "M 4032KiB" + +endchoice + +config AT32_AT32F43XX + bool + default n + select ARCH_CORTEXM4 + select ARCH_HAVE_FPU + select AT32_HAVE_FLASH_ICACHE + select AT32_HAVE_FLASH_DCACHE + select AT32_HAVE_SPI2 + select AT32_HAVE_I2C2 + select AT32_HAVE_IOCOMPENSATION + select AT32_HAVE_IP_DBGMCU_V2 + select AT32_HAVE_IP_TIMERS_V1 + select AT32_HAVE_IP_ADC_V1 + select AT32_HAVE_IP_DAC_V1 + select AT32_HAVE_IP_DMA_V1 + select AT32_HAVE_DMAMUX + + +config AT32_AT32F435 + bool + default n + select AT32_HAVE_FSMC + select AT32_HAVE_USART3 + select AT32_HAVE_UART4 + select AT32_HAVE_UART5 + select AT32_HAVE_UART7 + select AT32_HAVE_UART8 + select AT32_HAVE_USART6 + select AT32_HAVE_TIM1 + select AT32_HAVE_TIM3 + select AT32_HAVE_TIM4 + select AT32_HAVE_TIM5 + select AT32_HAVE_TIM6 + select AT32_HAVE_TIM7 + select AT32_HAVE_TIM8 + select AT32_HAVE_TIM9 + select AT32_HAVE_TIM10 + select AT32_HAVE_TIM11 + select AT32_HAVE_TIM12 + select AT32_HAVE_TIM13 + select AT32_HAVE_TIM14 + select AT32_HAVE_TIM20 + select AT32_HAVE_ADC2 + select AT32_HAVE_ADC3 + select AT32_HAVE_CAN1 + select AT32_HAVE_CAN2 + select AT32_HAVE_DAC1 + select AT32_HAVE_DAC2 + select AT32_HAVE_SPI3 + select AT32_HAVE_I2S3 + select AT32_HAVE_I2C3 + select AT32_HAVE_OTGFS + select AT32_HAVE_OTGFS2 + +config AT32_AT32F437 + bool + default n + select AT32_HAVE_FSMC + select AT32_HAVE_USART3 + select AT32_HAVE_UART4 + select AT32_HAVE_UART5 + select AT32_HAVE_USART6 + select AT32_HAVE_UART7 + select AT32_HAVE_UART8 + select AT32_HAVE_TIM1 + select AT32_HAVE_TIM2 + select AT32_HAVE_TIM3 + select AT32_HAVE_TIM4 + select AT32_HAVE_TIM5 + select AT32_HAVE_TIM6 + select AT32_HAVE_TIM7 + select AT32_HAVE_TIM8 + select AT32_HAVE_TIM9 + select AT32_HAVE_TIM10 + select AT32_HAVE_TIM11 + select AT32_HAVE_TIM12 + select AT32_HAVE_TIM13 + select AT32_HAVE_TIM14 + select AT32_HAVE_TIM20 + select AT32_HAVE_ADC2 + select AT32_HAVE_ADC3 + select AT32_HAVE_CAN1 + select AT32_HAVE_CAN2 + select AT32_HAVE_DAC1 + select AT32_HAVE_SPI3 + select AT32_HAVE_I2S3 + select AT32_HAVE_I2C3 + select AT32_HAVE_ETHMAC + select AT32_HAVE_OTGFS + select AT32_HAVE_OTGFS2 + select AT32_HAVE_SDIO + select AT32_HAVE_SDIO2 + +menu "AT32 Peripheral Support" + +# These "hidden" settings determine whether a peripheral option is available +# for the selected MCU + + +config AT32_HAVE_OVERDRIVE + bool + default n + +config AT32_HAVE_AES + bool + default n + +config AT32_HAVE_DMA1_CHAN8 + bool + default n + +config AT32_HAVE_DMA2_CHAN678 + bool + default n + +config AT32_HAVE_DMAMUX + bool + default n + +config AT32_HAVE_USBDEV + bool + default n + +config AT32_HAVE_USBFS + bool + default n + +config AT32_HAVE_OTGFS + bool + default n + +config AT32_HAVE_OTGFS2 + bool + default n + +config AT32_HAVE_FMC + bool + default n + +config AT32_HAVE_FMAC + bool + default n + +config AT32_HAVE_FSMC + bool + default n + +config AT32_HAVE_USART3 + bool + default n + +config AT32_HAVE_UART4 + bool + default n + +config AT32_HAVE_UART5 + bool + default n + +config AT32_HAVE_USART6 + bool + default n + +config AT32_HAVE_UART7 + bool + default n + +config AT32_HAVE_UART8 + bool + default n + +config AT32_HAVE_TIM1 + bool + default n + +config AT32_HAVE_TIM2 + bool + default n + +config AT32_HAVE_TIM3 + bool + default n + +config AT32_HAVE_TIM4 + bool + default n + +config AT32_HAVE_TIM5 + bool + default n + +config AT32_HAVE_TIM6 + bool + default n + +config AT32_HAVE_TIM7 + bool + default n + +config AT32_HAVE_TIM8 + bool + default n + +config AT32_HAVE_TIM9 + bool + default n + +config AT32_HAVE_TIM10 + bool + default n + +config AT32_HAVE_TIM11 + bool + default n + +config AT32_HAVE_TIM12 + bool + default n + +config AT32_HAVE_TIM13 + bool + default n + +config AT32_HAVE_TIM14 + bool + default n + +config AT32_HAVE_TIM15 + bool + default n + +config AT32_HAVE_TIM16 + bool + default n + +config AT32_HAVE_TIM17 + bool + default n + +config AT32_HAVE_TIM18 + bool + default n + +config AT32_HAVE_TIM19 + bool + default n + +config AT32_HAVE_TIM20 + bool + default n + +config AT32_HAVE_ADC1 + bool + default y + +config AT32_HAVE_ADC2 + bool + default n + +config AT32_HAVE_ADC3 + bool + default n + +config AT32_HAVE_ADC4 + bool + default n + +config AT32_HAVE_ADC5 + bool + default n + +config AT32_HAVE_ADC1_DMA + bool + default n + +config AT32_HAVE_ADC2_DMA + bool + default n + +config AT32_HAVE_ADC3_DMA + bool + default n + +config AT32_HAVE_ADC4_DMA + bool + default n + +config AT32_HAVE_ADC5_DMA + bool + default n + +config AT32_HAVE_CAN1 + bool + default n + +config AT32_HAVE_CAN2 + bool + default n + +config AT32_HAVE_DAC1 + bool + default n + +config AT32_HAVE_DAC2 + bool + default n + +config AT32_HAVE_DAC3 + bool + default n + +config AT32_HAVE_DAC4 + bool + default n + +config AT32_HAVE_QSPI + bool + default n + +config AT32_HAVE_ETHMAC + bool + default n + +config AT32_HAVE_I2C2 + bool + default n + +config AT32_HAVE_I2C3 + bool + default n + +config AT32_HAVE_SPI2 + bool + default n + +config AT32_HAVE_SPI3 + bool + default n + +config AT32_HAVE_I2S3 + bool + default n + +config AT32_HAVE_SPI4 + bool + default n + +config AT32_HAVE_I2SPLL + bool + default n + +# These are AT32 peripherals IP blocks + +config AT32_HAVE_IP_DBGMCU_V1 + bool + default n + +config AT32_HAVE_IP_DBGMCU_V2 + bool + default n + +config AT32_HAVE_IP_DBGMCU_V3 + bool + default n + +config AT32_HAVE_IP_DMA_V1 + bool + default n + +config AT32_HAVE_IP_DMA_V2 + bool + default n + +config AT32_HAVE_IP_TIMERS_V1 + bool + default n + +config AT32_HAVE_IP_TIMERS_V2 + bool + default n + +config AT32_HAVE_IP_TIMERS_V3 + bool + default n + +config AT32_HAVE_IP_ADC_V1 + bool + default n + +config AT32_HAVE_IP_ADC_V1_BASIC + bool + default n + select AT32_HAVE_IP_ADC_V1 + +config AT32_HAVE_IP_ADC_V2 + bool + default n + +config AT32_HAVE_IP_ADC_V2_BASIC + bool + default n + select AT32_HAVE_IP_ADC_V2 + +config AT32_HAVE_IP_DAC_V1 + bool + default n + +config AT32_HAVE_IP_DAC_V2 + bool + default n + +# These are the peripheral selections proper + +config AT32_ADC1 + bool "ADC1" + default n + select AT32_ADC + select AT32_HAVE_ADC1_DMA if AT32_DMAMUX && (AT32_DMA1 || AT32_DMA2) + +config AT32_ADC2 + bool "ADC2" + default n + select AT32_ADC + depends on AT32_HAVE_ADC2 + select AT32_HAVE_ADC2_DMA if AT32_DMA2 + select AT32_HAVE_ADC2_DMA if AT32_DMAMUX + +config AT32_ADC3 + bool "ADC3" + default n + select AT32_ADC + depends on AT32_HAVE_ADC3 + select AT32_HAVE_ADC3_DMA if AT32_DMA2 + select AT32_HAVE_ADC3_DMA if AT32_DMAMUX + +config AT32_ADC4 + bool "ADC4" + default n + select AT32_ADC + depends on AT32_HAVE_ADC4 + select AT32_HAVE_ADC4_DMA if AT32_DMA2 + select AT32_HAVE_ADC4_DMA if AT32_DMAMUX + +config AT32_ADC5 + bool "ADC5" + default n + select AT32_ADC + depends on AT32_HAVE_ADC5 + select AT32_HAVE_ADC5_DMA if AT32_DMA2 + select AT32_HAVE_ADC5_DMA if AT32_DMAMUX + +config AT32_CAN1 + bool "CAN1" + default n + select AT32_CAN + depends on AT32_HAVE_CAN1 + +config AT32_CAN2 + bool "CAN2" + default n + select AT32_CAN + depends on AT32_HAVE_CAN2 + +config AT32_CCMDATARAM + bool "CMD/DATA RAM" + default n + depends on AT32_AT32F43XX + +config AT32_AES + bool "128-bit AES" + default n + depends on AT32_HAVE_AES + select CRYPTO_AES192_DISABLE if CRYPTO_ALGTEST + select CRYPTO_AES256_DISABLE if CRYPTO_ALGTEST + +config AT32_CEC + bool "CEC" + default n + depends on AT32_VALUELINE + +config AT32_CRC + bool "CRC" + default n + +config AT32_CRS + bool "CRS (Clock Recovery System)" + default n + depends on AT32_HAVE_CRS + +config AT32_DMA1 + bool "DMA1" + default n + select AT32_DMA + select ARCH_DMA + +config AT32_DMA2 + bool "DMA2" + default n + select AT32_DMA + select ARCH_DMA + depends on !AT32_VALUELINE || (AT32_VALUELINE && AT32_HIGHDENSITY) + +config AT32_DMAMUX1 + bool "DMAMUX1" + default n + depends on AT32_HAVE_DMAMUX + select AT32_DMAMUX + +config AT32_DMAMUX2 + bool "DMAMUX2" + default n + depends on AT32_HAVE_DMAMUX + select AT32_DMAMUX + +config AT32_DAC1 + bool "DAC1" + default n + depends on AT32_HAVE_DAC1 + select AT32_DAC + +if AT32_DAC1 + +config AT32_DAC1CH1 + bool "DAC1CH1" + default n + +config AT32_DAC1CH2 + bool "DAC1CH2" + default n + +endif #AT32_DAC1 + +config AT32_DAC2 + bool "DAC2" + default n + depends on AT32_HAVE_DAC2 + select AT32_DAC + +if AT32_DAC2 + +config AT32_DAC2CH1 + bool "DAC2CH1" + default n + +endif #AT32_DAC2 + +config AT32_DAC3 + bool "DAC3" + default n + depends on AT32_HAVE_DAC3 + select AT32_DAC + +if AT32_DAC3 + +config AT32_DAC3CH1 + bool "DAC3CH1 Internal" + default n + +config AT32_DAC3CH2 + bool "DAC3CH2 Internal" + default n + +endif #AT32_DAC3 + +config AT32_DAC4 + bool "DAC4" + default n + depends on AT32_HAVE_DAC4 + select AT32_DAC + +if AT32_DAC4 + +config AT32_DAC4CH1 + bool "DAC4CH1 Internal" + default n + +config AT32_DAC4CH2 + bool "DAC4CH2 Internal" + default n + +endif #AT32_DAC4 + +config AT32_DCMI + bool "DCMI" + default n + depends on AT32_AT32F43XX + +config AT32_ETHMAC + bool "Ethernet MAC" + default n + depends on AT32_HAVE_ETHMAC + select NETDEVICES + select ARCH_HAVE_PHY + +config AT32_FSMC + bool "FSMC" + default n + depends on AT32_HAVE_FSMC + +config AT32_FMC + bool "FMC" + default n + depends on AT32_HAVE_FMC + +config AT32_FMAC + bool "FMAC (Filter Math Accelerator)" + default n + depends on AT32_HAVE_FMAC + +config AT32_I2C1 + bool "I2C1" + default n + select AT32_I2C + +config AT32_I2C2 + bool "I2C2" + default n + depends on AT32_HAVE_I2C2 + select AT32_I2C + +config AT32_I2C3 + bool "I2C3" + default n + depends on AT32_HAVE_I2C3 + select AT32_I2C + +config AT32_RTC + bool "RTC" + default n + select RTC + +config AT32_OTGFS + bool "OTG FS" + default n + depends on AT32_HAVE_OTGFS + select USBHOST_HAVE_ASYNCH if AT32_USBHOST + +config AT32_OTGFS2 + bool "OTG FS2" + default n + depends on AT32_AT32F43XX + select USBHOST_HAVE_ASYNCH if AT32_USBHOST + +config AT32_PWR + bool "PWR" + default n + +config AT32_QSPI + bool "QSPI (QUADSPI)" + depends on AT32_HAVE_QSPI + default n + +config AT32_SDIO + bool "SDIO" + default n + depends on !AT32_CONNECTIVITYLINE && !AT32_VALUELINE + select ARCH_HAVE_SDIO + select ARCH_HAVE_SDIOWAIT_WRCOMPLETE + select ARCH_HAVE_SDIO_PREFLIGHT + +config AT32_SDIO2 + bool "SDIO2" + default n + depends on !AT32_CONNECTIVITYLINE && !AT32_VALUELINE + select ARCH_HAVE_SDIO + select ARCH_HAVE_SDIOWAIT_WRCOMPLETE + select ARCH_HAVE_SDIO_PREFLIGHT + +config AT32_SPI1 + bool "SPI1" + default n + select SPI + select AT32_SPI + +config AT32_SPI2 + bool "SPI2" + default n + depends on AT32_HAVE_SPI2 + select SPI + select AT32_SPI + +config AT32_SPI3 + bool "SPI3" + default n + depends on AT32_HAVE_SPI3 + select SPI + select AT32_SPI + +config AT32_I2S3 + bool "I2S3" + default n + depends on AT32_HAVE_I2S3 + select I2S + select AT32_I2S + +config AT32_SPI4 + bool "SPI4" + default n + depends on AT32_HAVE_SPI4 + select SPI + select AT32_SPI + +config AT32_SYSCFG + bool "SYSCFG" + default y + depends on AT32_AT32F43XX || AT32_CONNECTIVITYLINE + +config AT32_TIM1 + bool "TIM1" + default n + depends on AT32_HAVE_TIM1 + select AT32_TIM + +config AT32_TIM2 + bool "TIM2" + default n + select AT32_TIM + +config AT32_TIM3 + bool "TIM3" + default n + depends on AT32_HAVE_TIM3 + select AT32_TIM + +config AT32_TIM4 + bool "TIM4" + default n + depends on AT32_HAVE_TIM4 + select AT32_TIM + +config AT32_TIM5 + bool "TIM5" + default n + depends on AT32_HAVE_TIM5 + select AT32_TIM + +config AT32_TIM6 + bool "TIM6" + default n + depends on AT32_HAVE_TIM6 + select AT32_TIM + +config AT32_TIM7 + bool "TIM7" + default n + depends on AT32_HAVE_TIM7 + select AT32_TIM + +config AT32_TIM8 + bool "TIM8" + default n + depends on AT32_HAVE_TIM8 + select AT32_TIM + +config AT32_TIM9 + bool "TIM9" + default n + depends on AT32_HAVE_TIM9 + select AT32_TIM + +config AT32_TIM10 + bool "TIM10" + default n + depends on AT32_HAVE_TIM10 + select AT32_TIM + +config AT32_TIM11 + bool "TIM11" + default n + depends on AT32_HAVE_TIM11 + select AT32_TIM + +config AT32_TIM12 + bool "TIM12" + default n + depends on AT32_HAVE_TIM12 + select AT32_TIM + +config AT32_TIM13 + bool "TIM13" + default n + depends on AT32_HAVE_TIM13 + select AT32_TIM + +config AT32_TIM14 + bool "TIM14" + default n + depends on AT32_HAVE_TIM14 + select AT32_TIM + +config AT32_TIM15 + bool "TIM15" + default n + depends on AT32_HAVE_TIM15 + select AT32_TIM + +config AT32_TIM16 + bool "TIM16" + default n + depends on AT32_HAVE_TIM16 + select AT32_TIM + +config AT32_TIM17 + bool "TIM17" + default n + depends on AT32_HAVE_TIM17 + select AT32_TIM + +config AT32_TIM20 + bool "TIM20" + default n + depends on AT32_HAVE_TIM20 + select AT32_TIM + +config AT32_USART1 + bool "USART1" + default n + select AT32_USART + +config AT32_USART2 + bool "USART2" + default n + select AT32_USART + +config AT32_USART3 + bool "USART3" + default n + depends on AT32_HAVE_USART3 + select AT32_USART + +config AT32_UART4 + bool "UART4" + default n + depends on AT32_HAVE_UART4 + select AT32_USART + +config AT32_UART5 + bool "UART5" + default n + depends on AT32_HAVE_UART5 + select AT32_USART + +config AT32_USART6 + bool "USART6" + default n + depends on AT32_HAVE_USART6 + select AT32_USART + +config AT32_UART7 + bool "UART7" + default n + depends on AT32_HAVE_UART7 + select AT32_USART + +config AT32_UART8 + bool "UART8" + default n + depends on AT32_HAVE_UART8 + select AT32_USART + +config AT32_USB + bool "USB Device" + default n + depends on AT32_HAVE_USBDEV + select USBDEV + +config AT32_USBFS + bool "USB Full Speed Device" + default n + depends on AT32_HAVE_USBFS + select USBDEV + +config AT32_UCPD + bool "UCPD (USB Type C Power Delivery)" + default n + depends on AT32_HAVE_UCPD + select USBDEV + +config AT32_IWDG + bool "IWDG" + default n + select WATCHDOG + +config AT32_WWDG + bool "WWDG" + default n + select WATCHDOG + +endmenu + +config AT32_ADC + bool + default n + +config AT32_DAC + bool + default n + +config AT32_DMA + bool + default n + +config AT32_DMAMUX + bool + default n + +config AT32_SPI + bool + default n + +config AT32_SPI_DMA + bool + default n + +config AT32_I2S + bool + default n + select AT32_SPI_DMA + +config AT32_I2C + bool + default n + +config AT32_CAN + bool + default n + +config AT32_TIM + bool + default n + +config AT32_PWM + bool + default n + select ARCH_HAVE_PWM_PULSECOUNT + +config AT32_CAP + bool + default n + +config AT32_NOEXT_VECTORS + bool "Disable the ARMv7-M EXT vectors" + default n + ---help--- + Sometimes you may not need any Vector support beyond SysTick + and wish to save memory. This applies only to ARMv7-M architectures. + + +choice + prompt "JTAG Configuration" + default AT32_JTAG_DISABLE + ---help--- + JTAG Enable settings (by default JTAG-DP and SW-DP are disabled) + +config AT32_JTAG_DISABLE + bool "Disable all JTAG clocking" + +config AT32_JTAG_FULL_ENABLE + bool "Enable full SWJ (JTAG-DP + SW-DP)" + +config AT32_JTAG_NOJNTRST_ENABLE + bool "Enable full SWJ (JTAG-DP + SW-DP) but without JNTRST" + +config AT32_JTAG_SW_ENABLE + bool "Set JTAG-DP disabled and SW-DP enabled" + +endchoice + +config AT32_DISABLE_IDLE_SLEEP_DURING_DEBUG + bool "Disable IDLE Sleep (WFI) in debug mode" + default n + ---help--- + In debug configuration, disables the WFI instruction in the IDLE loop + to prevent the JTAG from disconnecting. With some JTAG debuggers, such + as the ST-LINK2 with OpenOCD, if the ARM is put to sleep via the WFI + instruction, the debugger will disconnect, terminating the debug session. + +config AT32_FORCEPOWER + bool "Force power" + default n + ---help--- + Timer and I2C devices may need to the following to force power to be applied + unconditionally at power up. (Otherwise, the device is powered when it is + initialized). + +config ARCH_BOARD_AT32_CUSTOM_CLOCKCONFIG + bool "Custom clock configuration" + default n + ---help--- + Enables special, board-specific AT32 clock configuration. + + +config AT32_DMACAPABLE + bool "Workaround non-DMA capable memory" + depends on ARCH_DMA + default y if AT32_AT32F43XX && !AT32_CCMEXCLUDE + ---help--- + This option enables the DMA interface at32_dmacapable that can be + used to check if it is possible to do DMA from the selected address. + Drivers then may use this information to determine if they should + attempt the DMA or fall back to a different transfer method. + +config AT32_EXTERNAL_RAM + bool "External RAM on FSMC/FMC" + default n + depends on AT32_FSMC || AT32_FMC + select ARCH_HAVE_HEAP2 + ---help--- + In addition to internal SRAM, external RAM may be available through the FSMC/FMC. + +config AT32_TICKLESS_SYSTICK + bool "Tickless via SysTick" + default n + depends on SCHED_TICKLESS + ---help--- + Use SysTick as Tickless clock. + +menu "Timer Configuration" + depends on AT32_TIM + +if SCHED_TICKLESS + +config AT32_TICKLESS_TIMER + int "Tickless hardware timer" + default 2 + range 1 14 + depends on !AT32_TICKLESS_SYSTICK + ---help--- + If the Tickless OS feature is enabled, then one clock must be + assigned to provided the timer needed by the OS. + +config AT32_TICKLESS_CHANNEL + int "Tickless timer channel" + default 1 + range 1 4 + ---help--- + If the Tickless OS feature is enabled, the one clock must be + assigned to provided the free-running timer needed by the OS + and one channel on that clock is needed to handle intervals. + +endif # SCHED_TICKLESS + +config AT32_ONESHOT + bool "TIM one-shot wrapper" + default n + ---help--- + Enable a wrapper around the low level timer/counter functions to + support one-shot timer. + +config AT32_FREERUN + bool "TIM free-running wrapper" + default n + ---help--- + Enable a wrapper around the low level timer/counter functions to + support a free-running timer. + +config AT32_ONESHOT_MAXTIMERS + int "Maximum number of oneshot timers" + default 1 + range 1 8 + depends on AT32_ONESHOT + ---help--- + Determines the maximum number of oneshot timers that can be + supported. This setting pre-allocates some minimal support for each + of the timers and places an upper limit on the number of oneshot + timers that you can use. + +config AT32_PWM_LL_OPS + bool "PWM low-level operations" + default n + ---help--- + Enable low-level PWM ops. + +config AT32_TIM1_PWM + bool "TIM1 PWM" + default n + depends on AT32_TIM1 + select AT32_PWM + ---help--- + Reserve timer 1 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM1 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM1_PWM + +config AT32_TIM1_MODE + int "TIM1 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +config AT32_TIM1_LOCK + int "TIM1 Lock Level Configuration" + default 0 + range 0 3 + ---help--- + Timer 1 lock level configuration + +config AT32_TIM1_TDTS + int "TIM1 t_DTS Division" + default 0 + range 0 2 + ---help--- + Timer 1 dead-time and sampling clock (t_DTS) division + +config AT32_TIM1_DEADTIME + int "TIM1 Initial Dead-time" + default 0 + range 0 255 + ---help--- + Timer 1 initial dead-time + +if AT32_PWM_MULTICHAN + +config AT32_TIM1_CHANNEL1 + bool "TIM1 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM1_CHANNEL1 + +config AT32_TIM1_CH1MODE + int "TIM1 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM1_CH1OUT + bool "TIM1 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +config AT32_TIM1_CH1NOUT + bool "TIM1 Channel 1 Complementary Output" + default n + ---help--- + Enables channel 1 Complementary Output. + +endif # AT32_TIM1_CHANNEL1 + +config AT32_TIM1_CHANNEL2 + bool "TIM1 Channel 2" + default n + ---help--- + Enables channel 2. + +if AT32_TIM1_CHANNEL2 + +config AT32_TIM1_CH2MODE + int "TIM1 Channel 2 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM1_CH2OUT + bool "TIM1 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +config AT32_TIM1_CH2NOUT + bool "TIM1 Channel 2 Complementary Output" + default n + ---help--- + Enables channel 2 Complementary Output. + +endif # AT32_TIM1_CHANNEL2 + +config AT32_TIM1_CHANNEL3 + bool "TIM1 Channel 3" + default n + ---help--- + Enables channel 3. + +if AT32_TIM1_CHANNEL3 + +config AT32_TIM1_CH3MODE + int "TIM1 Channel 3 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM1_CH3OUT + bool "TIM1 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +config AT32_TIM1_CH3NOUT + bool "TIM1 Channel 3 Complementary Output" + default n + ---help--- + Enables channel 3 Complementary Output. + +endif # AT32_TIM1_CHANNEL3 + +config AT32_TIM1_CHANNEL4 + bool "TIM1 Channel 4" + default n + ---help--- + Enables channel 4. + +if AT32_TIM1_CHANNEL4 + +config AT32_TIM1_CH4MODE + int "TIM1 Channel 4 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM1_CH4OUT + bool "TIM1 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM1_CHANNEL4 + +config AT32_TIM1_CHANNEL5 + bool "TIM1 Channel 5 (internal)" + default n + depends on AT32_HAVE_IP_TIMERS_V2 + ---help--- + Enables channel 5 (not available externally) + +if AT32_TIM1_CHANNEL5 + +config AT32_TIM1_CH5MODE + int "TIM1 Channel 5 Mode" + default 6 + range 0 11 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM1_CH5OUT + bool "TIM1 Channel 5 Output" + default n + ---help--- + Enables channel 5 output. + +endif # AT32_TIM1_CHANNEL5 + +config AT32_TIM1_CHANNEL6 + bool "TIM1 Channel 6 (internal)" + default n + depends on AT32_HAVE_IP_TIMERS_V2 + ---help--- + Enables channel 6 (not available externally) + +if AT32_TIM1_CHANNEL6 + +config AT32_TIM1_CH6MODE + int "TIM1 Channel 6 Mode" + default 6 + range 0 11 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM1_CH6OUT + bool "TIM1 Channel 6 Output" + default n + ---help--- + Enables channel 6 output. + +endif # AT32_TIM1_CHANNEL6 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM1_CHANNEL + int "TIM1 PWM Output Channel" + default 1 + range 1 4 + ---help--- + If TIM1 is enabled for PWM usage, you also need specifies the timer output + channel {1,..,4} + +if AT32_TIM1_CHANNEL = 1 + +config AT32_TIM1_CH1OUT + bool "TIM1 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +config AT32_TIM1_CH1NOUT + bool "TIM1 Channel 1 Complementary Output" + default n + ---help--- + Enables channel 1 Complementary Output. + +endif # AT32_TIM1_CHANNEL = 1 + +if AT32_TIM1_CHANNEL = 2 + +config AT32_TIM1_CH2OUT + bool "TIM1 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +config AT32_TIM1_CH2NOUT + bool "TIM1 Channel 2 Complementary Output" + default n + ---help--- + Enables channel 2 Complementary Output. + +endif # AT32_TIM1_CHANNEL = 2 + +if AT32_TIM1_CHANNEL = 3 + +config AT32_TIM1_CH3OUT + bool "TIM1 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +config AT32_TIM1_CH3NOUT + bool "TIM1 Channel 3 Complementary Output" + default n + ---help--- + Enables channel 3 Complementary Output. + +endif # AT32_TIM1_CHANNEL = 3 + +if AT32_TIM1_CHANNEL = 4 + +config AT32_TIM1_CH4OUT + bool "TIM1 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM1_CHANNEL = 4 + +config AT32_TIM1_CHMODE + int "TIM1 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM1_PWM + +config AT32_TIM2_PWM + bool "TIM2 PWM" + default n + depends on AT32_TIM2 + select AT32_PWM + ---help--- + Reserve timer 2 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM2 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM2_PWM + +config AT32_TIM2_MODE + int "TIM2 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +if AT32_PWM_MULTICHAN + +config AT32_TIM2_CHANNEL1 + bool "TIM2 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM2_CHANNEL1 + +config AT32_TIM2_CH1MODE + int "TIM2 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM2_CH1OUT + bool "TIM2 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM2_CHANNEL1 + +config AT32_TIM2_CHANNEL2 + bool "TIM2 Channel 2" + default n + ---help--- + Enables channel 2. + +if AT32_TIM2_CHANNEL2 + +config AT32_TIM2_CH2MODE + int "TIM2 Channel 2 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM2_CH2OUT + bool "TIM2 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM2_CHANNEL2 + +config AT32_TIM2_CHANNEL3 + bool "TIM2 Channel 3" + default n + ---help--- + Enables channel 3. + +if AT32_TIM2_CHANNEL3 + +config AT32_TIM2_CH3MODE + int "TIM2 Channel 3 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM2_CH3OUT + bool "TIM2 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +endif # AT32_TIM2_CHANNEL3 + +config AT32_TIM2_CHANNEL4 + bool "TIM2 Channel 4" + default n + ---help--- + Enables channel 4. + +if AT32_TIM2_CHANNEL4 + +config AT32_TIM2_CH4MODE + int "TIM2 Channel 4 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM2_CH4OUT + bool "TIM2 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM2_CHANNEL4 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM2_CHANNEL + int "TIM2 PWM Output Channel" + default 1 + range 1 4 + ---help--- + If TIM2 is enabled for PWM usage, you also need specifies the timer output + channel {1,..,4} + +if AT32_TIM2_CHANNEL = 1 + +config AT32_TIM2_CH1OUT + bool "TIM2 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM2_CHANNEL = 1 + +if AT32_TIM2_CHANNEL = 2 + +config AT32_TIM2_CH2OUT + bool "TIM2 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM2_CHANNEL = 2 + +if AT32_TIM2_CHANNEL = 3 + +config AT32_TIM2_CH3OUT + bool "TIM2 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +endif # AT32_TIM2_CHANNEL = 3 + +if AT32_TIM2_CHANNEL = 4 + +config AT32_TIM2_CH4OUT + bool "TIM2 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM2_CHANNEL = 4 + +config AT32_TIM2_CHMODE + int "TIM2 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM2_PWM + +config AT32_TIM3_PWM + bool "TIM3 PWM" + default n + depends on AT32_TIM3 + select AT32_PWM + ---help--- + Reserve timer 3 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM3 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM3_PWM + +config AT32_TIM3_MODE + int "TIM3 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +if AT32_PWM_MULTICHAN + +config AT32_TIM3_CHANNEL1 + bool "TIM3 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM3_CHANNEL1 + +config AT32_TIM3_CH1MODE + int "TIM3 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM3_CH1OUT + bool "TIM3 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM3_CHANNEL1 + +config AT32_TIM3_CHANNEL2 + bool "TIM3 Channel 2" + default n + ---help--- + Enables channel 2. + +if AT32_TIM3_CHANNEL2 + +config AT32_TIM3_CH2MODE + int "TIM3 Channel 2 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM3_CH2OUT + bool "TIM3 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM3_CHANNEL2 + +config AT32_TIM3_CHANNEL3 + bool "TIM3 Channel 3" + default n + ---help--- + Enables channel 3. + +if AT32_TIM3_CHANNEL3 + +config AT32_TIM3_CH3MODE + int "TIM3 Channel 3 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM3_CH3OUT + bool "TIM3 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +endif # AT32_TIM3_CHANNEL3 + +config AT32_TIM3_CHANNEL4 + bool "TIM3 Channel 4" + default n + ---help--- + Enables channel 4. + +if AT32_TIM3_CHANNEL4 + +config AT32_TIM3_CH4MODE + int "TIM3 Channel 4 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM3_CH4OUT + bool "TIM3 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM3_CHANNEL4 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM3_CHANNEL + int "TIM3 PWM Output Channel" + default 1 + range 1 4 + ---help--- + If TIM3 is enabled for PWM usage, you also need specifies the timer output + channel {1,..,4} + +if AT32_TIM3_CHANNEL = 1 + +config AT32_TIM3_CH1OUT + bool "TIM3 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM3_CHANNEL = 1 + +if AT32_TIM3_CHANNEL = 2 + +config AT32_TIM3_CH2OUT + bool "TIM3 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM3_CHANNEL = 2 + +if AT32_TIM3_CHANNEL = 3 + +config AT32_TIM3_CH3OUT + bool "TIM3 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +endif # AT32_TIM3_CHANNEL = 3 + +if AT32_TIM3_CHANNEL = 4 + +config AT32_TIM3_CH4OUT + bool "TIM3 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM3_CHANNEL = 4 + +config AT32_TIM3_CHMODE + int "TIM3 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM3_PWM + +config AT32_TIM4_PWM + bool "TIM4 PWM" + default n + depends on AT32_TIM4 + select AT32_PWM + ---help--- + Reserve timer 4 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM4 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM4_PWM + +config AT32_TIM4_MODE + int "TIM4 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +if AT32_PWM_MULTICHAN + +config AT32_TIM4_CHANNEL1 + bool "TIM4 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM4_CHANNEL1 + +config AT32_TIM4_CH1MODE + int "TIM4 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM4_CH1OUT + bool "TIM4 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM4_CHANNEL1 + +config AT32_TIM4_CHANNEL2 + bool "TIM4 Channel 2" + default n + ---help--- + Enables channel 2. + +if AT32_TIM4_CHANNEL2 + +config AT32_TIM4_CH2MODE + int "TIM4 Channel 2 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM4_CH2OUT + bool "TIM4 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM4_CHANNEL2 + +config AT32_TIM4_CHANNEL3 + bool "TIM4 Channel 3" + default n + ---help--- + Enables channel 3. + +if AT32_TIM4_CHANNEL3 + +config AT32_TIM4_CH3MODE + int "TIM4 Channel 3 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM4_CH3OUT + bool "TIM4 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +endif # AT32_TIM4_CHANNEL3 + +config AT32_TIM4_CHANNEL4 + bool "TIM4 Channel 4" + default n + ---help--- + Enables channel 4. + +if AT32_TIM4_CHANNEL4 + +config AT32_TIM4_CH4MODE + int "TIM4 Channel 4 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM4_CH4OUT + bool "TIM4 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM4_CHANNEL4 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM4_CHANNEL + int "TIM4 PWM Output Channel" + default 1 + range 1 4 + ---help--- + If TIM4 is enabled for PWM usage, you also need specifies the timer output + channel {1,..,4} + +if AT32_TIM4_CHANNEL = 1 + +config AT32_TIM4_CH1OUT + bool "TIM4 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM4_CHANNEL = 1 + +if AT32_TIM4_CHANNEL = 2 + +config AT32_TIM4_CH2OUT + bool "TIM4 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM4_CHANNEL = 2 + +if AT32_TIM4_CHANNEL = 3 + +config AT32_TIM4_CH3OUT + bool "TIM4 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +endif # AT32_TIM4_CHANNEL = 3 + +if AT32_TIM4_CHANNEL = 4 + +config AT32_TIM4_CH4OUT + bool "TIM4 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM4_CHANNEL = 4 + +config AT32_TIM4_CHMODE + int "TIM4 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM4_PWM + +config AT32_TIM5_PWM + bool "TIM5 PWM" + default n + depends on AT32_TIM5 + select AT32_PWM + ---help--- + Reserve timer 5 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM5 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM5_PWM + +config AT32_TIM5_MODE + int "TIM5 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +if AT32_PWM_MULTICHAN + +config AT32_TIM5_CHANNEL1 + bool "TIM5 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM5_CHANNEL1 + +config AT32_TIM5_CH1MODE + int "TIM5 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM5_CH1OUT + bool "TIM5 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM5_CHANNEL1 + +config AT32_TIM5_CHANNEL2 + bool "TIM5 Channel 2" + default n + ---help--- + Enables channel 2. + +if AT32_TIM5_CHANNEL2 + +config AT32_TIM5_CH2MODE + int "TIM5 Channel 2 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM5_CH2OUT + bool "TIM5 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM5_CHANNEL2 + +config AT32_TIM5_CHANNEL3 + bool "TIM5 Channel 3" + default n + ---help--- + Enables channel 3. + +if AT32_TIM5_CHANNEL3 + +config AT32_TIM5_CH3MODE + int "TIM5 Channel 3 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM5_CH3OUT + bool "TIM5 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +endif # AT32_TIM5_CHANNEL3 + +config AT32_TIM5_CHANNEL4 + bool "TIM5 Channel 4" + default n + ---help--- + Enables channel 4. + +if AT32_TIM5_CHANNEL4 + +config AT32_TIM5_CH4MODE + int "TIM5 Channel 4 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM5_CH4OUT + bool "TIM5 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM5_CHANNEL4 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM5_CHANNEL + int "TIM5 PWM Output Channel" + default 1 + range 1 4 + ---help--- + If TIM5 is enabled for PWM usage, you also need specifies the timer output + channel {1,..,4} + +if AT32_TIM5_CHANNEL = 1 + +config AT32_TIM5_CH1OUT + bool "TIM5 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM5_CHANNEL = 1 + +if AT32_TIM5_CHANNEL = 2 + +config AT32_TIM5_CH2OUT + bool "TIM5 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM5_CHANNEL = 2 + +if AT32_TIM5_CHANNEL = 3 + +config AT32_TIM5_CH3OUT + bool "TIM5 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +endif # AT32_TIM5_CHANNEL = 3 + +if AT32_TIM5_CHANNEL = 4 + +config AT32_TIM5_CH4OUT + bool "TIM5 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM5_CHANNEL = 4 + +config AT32_TIM5_CHMODE + int "TIM5 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM5_PWM + +config AT32_TIM8_PWM + bool "TIM8 PWM" + default n + depends on AT32_TIM8 + select AT32_PWM + ---help--- + Reserve timer 8 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM8 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM8_PWM + +config AT32_TIM8_MODE + int "TIM8 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +config AT32_TIM8_LOCK + int "TIM8 Lock Level Configuration" + default 0 + range 0 3 + ---help--- + Timer 8 lock level configuration + +config AT32_TIM8_DEADTIME + int "TIM8 Initial Dead-time" + default 0 + range 0 255 + ---help--- + Timer 8 initial dead-time + +config AT32_TIM8_TDTS + int "TIM8 t_DTS Division" + default 0 + range 0 2 + ---help--- + Timer 8 dead-time and sampling clock (t_DTS) division + +if AT32_PWM_MULTICHAN + +config AT32_TIM8_CHANNEL1 + bool "TIM8 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM8_CHANNEL1 + +config AT32_TIM8_CH1MODE + int "TIM8 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM8_CH1OUT + bool "TIM8 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +config AT32_TIM8_CH1NOUT + bool "TIM8 Channel 1 Complementary Output" + default n + ---help--- + Enables channel 1 Complementary Output. + +endif # AT32_TIM8_CHANNEL1 + +config AT32_TIM8_CHANNEL2 + bool "TIM8 Channel 2" + default n + ---help--- + Enables channel 2. + +if AT32_TIM8_CHANNEL2 + +config AT32_TIM8_CH2MODE + int "TIM8 Channel 2 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM8_CH2OUT + bool "TIM8 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +config AT32_TIM8_CH2NOUT + bool "TIM8 Channel 2 Complementary Output" + default n + ---help--- + Enables channel 2 Complementary Output. + +endif # AT32_TIM8_CHANNEL2 + +config AT32_TIM8_CHANNEL3 + bool "TIM8 Channel 3" + default n + ---help--- + Enables channel 3. + +if AT32_TIM8_CHANNEL3 + +config AT32_TIM8_CH3MODE + int "TIM8 Channel 3 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM8_CH3OUT + bool "TIM8 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +config AT32_TIM8_CH3NOUT + bool "TIM8 Channel 3 Complementary Output" + default n + ---help--- + Enables channel 3 Complementary Output. + +endif # AT32_TIM8_CHANNEL3 + +config AT32_TIM8_CHANNEL4 + bool "TIM8 Channel 4" + default n + ---help--- + Enables channel 4. + +if AT32_TIM8_CHANNEL4 + +config AT32_TIM8_CH4MODE + int "TIM8 Channel 4 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM8_CH4OUT + bool "TIM8 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM8_CHANNEL4 + +config AT32_TIM8_CHANNEL5 + bool "TIM8 Channel 5 (internal)" + default n + depends on AT32_HAVE_IP_TIMERS_V2 + ---help--- + Enables channel 5 (not available externally) + +if AT32_TIM8_CHANNEL5 + +config AT32_TIM8_CH5MODE + int "TIM8 Channel 5 Mode" + default 6 + range 0 11 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM8_CH5OUT + bool "TIM8 Channel 5 Output" + default n + ---help--- + Enables channel 5 output. + +endif # AT32_TIM8_CHANNEL5 + +config AT32_TIM8_CHANNEL6 + bool "TIM8 Channel 6 (internal)" + default n + depends on AT32_HAVE_IP_TIMERS_V2 + ---help--- + Enables channel 6 (not available externally) + +if AT32_TIM8_CHANNEL6 + +config AT32_TIM8_CH6MODE + int "TIM8 Channel 6 Mode" + default 6 + range 0 11 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM8_CH6OUT + bool "TIM8 Channel 6 Output" + default n + ---help--- + Enables channel 6 output. + +endif # AT32_TIM8_CHANNEL6 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM8_CHANNEL + int "TIM8 PWM Output Channel" + default 1 + range 1 4 + ---help--- + If TIM8 is enabled for PWM usage, you also need specifies the timer output + channel {1,..,4} + +if AT32_TIM8_CHANNEL = 1 + +config AT32_TIM8_CH1OUT + bool "TIM8 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +config AT32_TIM8_CH1NOUT + bool "TIM8 Channel 1 Complementary Output" + default n + ---help--- + Enables channel 1 Complementary Output. + +endif # AT32_TIM8_CHANNEL = 1 + +if AT32_TIM8_CHANNEL = 2 + +config AT32_TIM8_CH2OUT + bool "TIM8 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +config AT32_TIM8_CH2NOUT + bool "TIM8 Channel 2 Complementary Output" + default n + ---help--- + Enables channel 2 Complementary Output. + +endif # AT32_TIM8_CHANNEL = 2 + +if AT32_TIM8_CHANNEL = 3 + +config AT32_TIM8_CH3OUT + bool "TIM8 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +config AT32_TIM8_CH3NOUT + bool "TIM8 Channel 3 Complementary Output" + default n + ---help--- + Enables channel 3 Complementary Output. + +endif # AT32_TIM8_CHANNEL = 3 + +if AT32_TIM8_CHANNEL = 4 + +config AT32_TIM8_CH4OUT + bool "TIM8 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM8_CHANNEL = 4 + +config AT32_TIM8_CHMODE + int "TIM8 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM8_PWM + +config AT32_TIM9_PWM + bool "TIM9 PWM" + default n + depends on AT32_TIM9 + select AT32_PWM + ---help--- + Reserve timer 9 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM9 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM9_PWM + +if AT32_PWM_MULTICHAN + +config AT32_TIM9_CHANNEL1 + bool "TIM9 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM9_CHANNEL1 + +config AT32_TIM9_CH1MODE + int "TIM9 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM9_CH1OUT + bool "TIM9 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM9_CHANNEL1 + +config AT32_TIM9_CHANNEL2 + bool "TIM9 Channel 2" + default n + ---help--- + Enables channel 2. + +if AT32_TIM9_CHANNEL2 + +config AT32_TIM9_CH2MODE + int "TIM9 Channel 2 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM9_CH2OUT + bool "TIM9 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM9_CHANNEL2 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM9_CHANNEL + int "TIM9 PWM Output Channel" + default 1 + range 1 2 + ---help--- + If TIM9 is enabled for PWM usage, you also need specifies the timer output + channel {1,2} + +if AT32_TIM9_CHANNEL = 1 + +config AT32_TIM9_CH1OUT + bool "TIM9 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM9_CHANNEL = 1 + +if AT32_TIM9_CHANNEL = 2 + +config AT32_TIM9_CH2OUT + bool "TIM9 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM9_CHANNEL = 2 + +config AT32_TIM9_CHMODE + int "TIM9 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM9_PWM + +config AT32_TIM10_PWM + bool "TIM10 PWM" + default n + depends on AT32_TIM10 + select AT32_PWM + ---help--- + Reserve timer 10 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM10 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM10_PWM + +if AT32_PWM_MULTICHAN + +config AT32_TIM10_CHANNEL1 + bool "TIM10 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM10_CHANNEL1 + +config AT32_TIM10_CH1MODE + int "TIM10 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM10_CH1OUT + bool "TIM10 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM10_CHANNEL1 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM10_CHANNEL + int "TIM10 PWM Output Channel" + default 1 + range 1 1 + ---help--- + If TIM10 is enabled for PWM usage, you also need specifies the timer output + channel {1} + +if AT32_TIM10_CHANNEL = 1 + +config AT32_TIM10_CH1OUT + bool "TIM10 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM10_CHANNEL = 1 + +config AT32_TIM10_CHMODE + int "TIM10 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM10_PWM + +config AT32_TIM11_PWM + bool "TIM11 PWM" + default n + depends on AT32_TIM11 + select AT32_PWM + ---help--- + Reserve timer 11 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM11 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM11_PWM + +if AT32_PWM_MULTICHAN + +config AT32_TIM11_CHANNEL1 + bool "TIM11 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM11_CHANNEL1 + +config AT32_TIM11_CH1MODE + int "TIM11 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM11_CH1OUT + bool "TIM11 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM11_CHANNEL1 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM11_CHANNEL + int "TIM11 PWM Output Channel" + default 1 + range 1 1 + ---help--- + If TIM11 is enabled for PWM usage, you also need specifies the timer output + channel {1} + +if AT32_TIM11_CHANNEL = 1 + +config AT32_TIM11_CH1OUT + bool "TIM11 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM11_CHANNEL = 1 + +config AT32_TIM11_CHMODE + int "TIM11 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM11_PWM + +config AT32_TIM12_PWM + bool "TIM12 PWM" + default n + depends on AT32_TIM12 + select AT32_PWM + ---help--- + Reserve timer 12 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM12 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM12_PWM + +if AT32_PWM_MULTICHAN + +config AT32_TIM12_CHANNEL1 + bool "TIM12 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM12_CHANNEL1 + +config AT32_TIM12_CH1MODE + int "TIM12 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM12_CH1OUT + bool "TIM12 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM12_CHANNEL1 + +config AT32_TIM12_CHANNEL2 + bool "TIM12 Channel 2" + default n + ---help--- + Enables channel 2. + +if AT32_TIM12_CHANNEL2 + +config AT32_TIM12_CH2MODE + int "TIM12 Channel 2 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM12_CH2OUT + bool "TIM12 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM12_CHANNEL2 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM12_CHANNEL + int "TIM12 PWM Output Channel" + default 1 + range 1 2 + ---help--- + If TIM12 is enabled for PWM usage, you also need specifies the timer output + channel {1,2} + +if AT32_TIM12_CHANNEL = 1 + +config AT32_TIM12_CH1OUT + bool "TIM12 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM12_CHANNEL = 1 + +if AT32_TIM12_CHANNEL = 2 + +config AT32_TIM12_CH2OUT + bool "TIM12 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM12_CHANNEL = 2 + +config AT32_TIM12_CHMODE + int "TIM12 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM12_PWM + +config AT32_TIM13_PWM + bool "TIM13 PWM" + default n + depends on AT32_TIM13 + select AT32_PWM + ---help--- + Reserve timer 13 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM13 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM13_PWM + +if AT32_PWM_MULTICHAN + +config AT32_TIM13_CHANNEL1 + bool "TIM13 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM13_CHANNEL1 + +config AT32_TIM13_CH1MODE + int "TIM13 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM13_CH1OUT + bool "TIM13 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM13_CHANNEL1 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM13_CHANNEL + int "TIM13 PWM Output Channel" + default 1 + range 1 1 + ---help--- + If TIM13 is enabled for PWM usage, you also need specifies the timer output + channel {1} + +if AT32_TIM13_CHANNEL = 1 + +config AT32_TIM13_CH1OUT + bool "TIM13 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM13_CHANNEL = 1 + +config AT32_TIM13_CHMODE + int "TIM13 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM13_PWM + +config AT32_TIM14_PWM + bool "TIM14 PWM" + default n + depends on AT32_TIM14 + select AT32_PWM + ---help--- + Reserve timer 14 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM14 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM14_PWM + +if AT32_PWM_MULTICHAN + +config AT32_TIM14_CHANNEL1 + bool "TIM14 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM14_CHANNEL1 + +config AT32_TIM14_CH1MODE + int "TIM14 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM14_CH1OUT + bool "TIM14 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM14_CHANNEL1 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM14_CHANNEL + int "TIM14 PWM Output Channel" + default 1 + range 1 1 + ---help--- + If TIM14 is enabled for PWM usage, you also need specifies the timer output + channel {1} + +if AT32_TIM14_CHANNEL = 1 + +config AT32_TIM14_CH1OUT + bool "TIM14 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM14_CHANNEL = 1 + +config AT32_TIM14_CHMODE + int "TIM14 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM14_PWM + +config AT32_TIM15_PWM + bool "TIM15 PWM" + default n + depends on AT32_TIM15 + select AT32_PWM + ---help--- + Reserve timer 15 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM15 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM15_PWM + +config AT32_TIM15_LOCK + int "TIM15 Lock Level Configuration" + default 0 + range 0 3 + ---help--- + Timer 15 lock level configuration + +config AT32_TIM15_TDTS + int "TIM15 t_DTS Division" + default 0 + range 0 2 + ---help--- + Timer 15 dead-time and sampling clock (t_DTS) division + +config AT32_TIM15_DEADTIME + int "TIM15 Initial Dead-time" + default 0 + range 0 255 + ---help--- + Timer 15 initial dead-time + +if AT32_PWM_MULTICHAN + +config AT32_TIM15_CHANNEL1 + bool "TIM15 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM15_CHANNEL1 + +config AT32_TIM15_CH1MODE + int "TIM15 Channel 1 Mode" + default 6 + range 0 9 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM15_CH1OUT + bool "TIM15 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +config AT32_TIM15_CH1NOUT + bool "TIM15 Channel 1 Complementary Output" + default n + ---help--- + Enables channel 1 Complementary Output. + +endif # AT32_TIM15_CHANNEL1 + +config AT32_TIM15_CHANNEL2 + bool "TIM15 Channel 2" + default n + ---help--- + Enables channel 2. + +if AT32_TIM15_CHANNEL2 + +config AT32_TIM15_CH2MODE + int "TIM15 Channel 2 Mode" + default 6 + range 0 9 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM15_CH2OUT + bool "TIM15 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +endif # AT32_TIM15_CHANNEL2 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM15_CHANNEL + int "TIM15 PWM Output Channel" + default 1 + range 1 2 + ---help--- + If TIM15 is enabled for PWM usage, you also need specifies the timer output + channel {1,2} + +if AT32_TIM15_CHANNEL = 1 + +config AT32_TIM15_CH1OUT + bool "TIM15 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +config AT32_TIM15_CH1NOUT + bool "TIM15 Channel 1 Complementary Output" + default n + ---help--- + Enables channel 1 Complementary Output. + +endif # AT32_TIM15_CHANNEL = 1 + +if AT32_TIM15_CHANNEL = 2 + +config AT32_TIM15_CH2OUT + bool "TIM15 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +config AT32_TIM15_CH2NOUT + bool "TIM15 Channel 2 Complementary Output" + default n + ---help--- + Enables channel 2 Complementary Output. + +endif # AT32_TIM15_CHANNEL = 2 + +config AT32_TIM15_CHMODE + int "TIM15 Channel Mode" + default 6 + range 0 9 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM15_PWM + +config AT32_TIM16_PWM + bool "TIM16 PWM" + default n + depends on AT32_TIM16 + select AT32_PWM + ---help--- + Reserve timer 16 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM16 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM16_PWM + +config AT32_TIM16_LOCK + int "TIM16 Lock Level Configuration" + default 0 + range 0 3 + ---help--- + Timer 16 lock level configuration + +config AT32_TIM16_TDTS + int "TIM16 t_DTS division" + default 0 + range 0 2 + ---help--- + Timer 16 dead-time and sampling clock (t_DTS) division + +config AT32_TIM16_DEADTIME + int "TIM16 Initial Dead-time" + default 0 + range 0 255 + ---help--- + Timer 16 initial dead-time + +if AT32_PWM_MULTICHAN + +config AT32_TIM16_CHANNEL1 + bool "TIM16 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM16_CHANNEL1 + +config AT32_TIM16_CH1MODE + int "TIM16 Channel 1 Mode" + default 6 + range 0 7 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM16_CH1OUT + bool "TIM16 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM16_CHANNEL1 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM16_CHANNEL + int "TIM16 PWM Output Channel" + default 1 + range 1 1 + ---help--- + If TIM16 is enabled for PWM usage, you also need specifies the timer output + channel {1} + +if AT32_TIM16_CHANNEL = 1 + +config AT32_TIM16_CH1OUT + bool "TIM16 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM16_CHANNEL = 1 + +config AT32_TIM16_CHMODE + int "TIM16 Channel Mode" + default 6 + range 0 7 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM16_PWM + +config AT32_TIM17_PWM + bool "TIM17 PWM" + default n + depends on AT32_TIM17 + select AT32_PWM + ---help--- + Reserve timer 17 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM17 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM17_PWM + +config AT32_TIM17_LOCK + int "TIM17 Lock Level Configuration" + default 0 + range 0 3 + ---help--- + Timer 17 lock level configuration + +config AT32_TIM17_TDTS + int "TIM17 t_DTS Division" + default 0 + range 0 2 + ---help--- + Timer 17 dead-time and sampling clock (t_DTS) division + +config AT32_TIM17_DEADTIME + int "TIM17 Initial Dead-time" + default 0 + range 0 255 + ---help--- + Timer 17 initial dead-time + +if AT32_PWM_MULTICHAN + +config AT32_TIM17_CHANNEL1 + bool "TIM17 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM17_CHANNEL1 + +config AT32_TIM17_CH1MODE + int "TIM17 Channel 1 Mode" + default 6 + range 0 7 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM17_CH1OUT + bool "TIM17 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM17_CHANNEL1 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM17_CHANNEL + int "TIM17 PWM Output Channel" + default 1 + range 1 1 + ---help--- + If TIM17 is enabled for PWM usage, you also need specifies the timer output + channel {1} + +if AT32_TIM17_CHANNEL = 1 + +config AT32_TIM17_CH1OUT + bool "TIM17 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +endif # AT32_TIM17_CHANNEL = 1 + +config AT32_TIM17_CHMODE + int "TIM17 Channel Mode" + default 6 + range 0 7 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM17_PWM + +config AT32_TIM20_PWM + bool "TIM20 PWM" + default n + depends on AT32_TIM20 + select AT32_PWM + ---help--- + Reserve timer 20 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If AT32_TIM20 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +if AT32_TIM20_PWM + +config AT32_TIM20_MODE + int "TIM20 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +config AT32_TIM20_LOCK + int "TIM20 Lock Level Configuration" + default 0 + range 0 3 + ---help--- + Timer 1 lock level configuration + +config AT32_TIM20_TDTS + int "TIM20 t_DTS Division" + default 0 + range 0 2 + ---help--- + Timer 1 dead-time and sampling clock (t_DTS) division + +config AT32_TIM20_DEADTIME + int "TIM20 Initial Dead-time" + default 0 + range 0 255 + ---help--- + Timer 1 initial dead-time + +if AT32_PWM_MULTICHAN + +config AT32_TIM20_CHANNEL1 + bool "TIM20 Channel 1" + default n + ---help--- + Enables channel 1. + +if AT32_TIM20_CHANNEL1 + +config AT32_TIM20_CH1MODE + int "TIM20 Channel 1 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM20_CH1OUT + bool "TIM20 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +config AT32_TIM20_CH1NOUT + bool "TIM20 Channel 1 Complementary Output" + default n + ---help--- + Enables channel 1 Complementary Output. + +endif # AT32_TIM20_CHANNEL1 + +config AT32_TIM20_CHANNEL2 + bool "TIM20 Channel 2" + default n + ---help--- + Enables channel 2. + +if AT32_TIM20_CHANNEL2 + +config AT32_TIM20_CH2MODE + int "TIM20 Channel 2 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM20_CH2OUT + bool "TIM20 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +config AT32_TIM20_CH2NOUT + bool "TIM20 Channel 2 Complementary Output" + default n + ---help--- + Enables channel 2 Complementary Output. + +endif # AT32_TIM20_CHANNEL2 + +config AT32_TIM20_CHANNEL3 + bool "TIM20 Channel 3" + default n + ---help--- + Enables channel 3. + +if AT32_TIM20_CHANNEL3 + +config AT32_TIM20_CH3MODE + int "TIM20 Channel 3 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM20_CH3OUT + bool "TIM20 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +config AT32_TIM20_CH3NOUT + bool "TIM20 Channel 3 Complementary Output" + default n + ---help--- + Enables channel 3 Complementary Output. + +endif # AT32_TIM20_CHANNEL3 + +config AT32_TIM20_CHANNEL4 + bool "TIM20 Channel 4" + default n + ---help--- + Enables channel 4. + +if AT32_TIM20_CHANNEL4 + +config AT32_TIM20_CH4MODE + int "TIM20 Channel 4 Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM20_CH4OUT + bool "TIM20 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM20_CHANNEL4 + +config AT32_TIM20_CHANNEL5 + bool "TIM20 Channel 5 (internal)" + default n + depends on AT32_HAVE_IP_TIMERS_V2 + ---help--- + Enables channel 5 (not available externally) + +if AT32_TIM20_CHANNEL5 + +config AT32_TIM20_CH5MODE + int "TIM20 Channel 5 Mode" + default 6 + range 0 11 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM20_CH5OUT + bool "TIM20 Channel 5 Output" + default n + ---help--- + Enables channel 5 output. + +endif # AT32_TIM20_CHANNEL5 + +config AT32_TIM20_CHANNEL6 + bool "TIM20 Channel 6 (internal)" + default n + depends on AT32_HAVE_IP_TIMERS_V2 + ---help--- + Enables channel 6 (not available externally) + +if AT32_TIM20_CHANNEL6 + +config AT32_TIM20_CH6MODE + int "TIM20 Channel 6 Mode" + default 6 + range 0 11 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +config AT32_TIM20_CH6OUT + bool "TIM20 Channel 6 Output" + default n + ---help--- + Enables channel 6 output. + +endif # AT32_TIM20_CHANNEL6 + +endif # AT32_PWM_MULTICHAN + +if !AT32_PWM_MULTICHAN + +config AT32_TIM20_CHANNEL + int "TIM20 PWM Output Channel" + default 1 + range 1 4 + ---help--- + If TIM20 is enabled for PWM usage, you also need specifies the timer output + channel {1,..,4} + +if AT32_TIM20_CHANNEL = 1 + +config AT32_TIM20_CH1OUT + bool "TIM20 Channel 1 Output" + default n + ---help--- + Enables channel 1 output. + +config AT32_TIM20_CH1NOUT + bool "TIM20 Channel 1 Complementary Output" + default n + ---help--- + Enables channel 1 Complementary Output. + +endif # AT32_TIM20_CHANNEL = 1 + +if AT32_TIM20_CHANNEL = 2 + +config AT32_TIM20_CH2OUT + bool "TIM20 Channel 2 Output" + default n + ---help--- + Enables channel 2 output. + +config AT32_TIM20_CH2NOUT + bool "TIM20 Channel 2 Complementary Output" + default n + ---help--- + Enables channel 2 Complementary Output. + +endif # AT32_TIM20_CHANNEL = 2 + +if AT32_TIM20_CHANNEL = 3 + +config AT32_TIM20_CH3OUT + bool "TIM20 Channel 3 Output" + default n + ---help--- + Enables channel 3 output. + +config AT32_TIM20_CH3NOUT + bool "TIM20 Channel 3 Complementary Output" + default n + ---help--- + Enables channel 3 Complementary Output. + +endif # AT32_TIM20_CHANNEL = 3 + +if AT32_TIM20_CHANNEL = 4 + +config AT32_TIM20_CH4OUT + bool "TIM20 Channel 4 Output" + default n + ---help--- + Enables channel 4 output. + +endif # AT32_TIM20_CHANNEL = 4 + +config AT32_TIM20_CHMODE + int "TIM20 Channel Mode" + default 6 + range 0 11 if AT32_HAVE_IP_TIMERS_V2 + range 0 7 if !AT32_HAVE_IP_TIMERS_V2 + ---help--- + Specifies the channel mode. See enum at32_pwm_chanmode_e in at32_pwm.h. + +endif # !AT32_PWM_MULTICHAN + +endif # AT32_TIM20_PWM + +config AT32_PWM_MULTICHAN + bool "PWM Multiple Output Channels" + default n + depends on AT32_PWM + select ARCH_HAVE_PWM_MULTICHAN + ---help--- + Specifies that the PWM driver supports multiple output + channels per timer. + +config AT32_PWM_TRGO + bool "TIM PWM TRGO support" + default n + depends on AT32_PWM + ---help--- + Enable TRGO support for PWM driver + +config AT32_TIM1_ADC + bool "TIM1 ADC" + default n + depends on AT32_TIM1 && AT32_ADC + ---help--- + Reserve timer 1 for use by ADC + + Timer devices may be used for different purposes. If AT32_TIM1 is + defined then the following may also be defined to indicate that the + timer is intended to be used for ADC conversion. Note that ADC usage + requires two definition: Not only do you have to assign the timer + for used by the ADC, but then you also have to configure which ADC + channel it is assigned to. + +choice + prompt "Select TIM1 ADC channel" + default AT32_TIM1_ADC1 + depends on AT32_TIM1_ADC + +config AT32_TIM1_ADC1 + bool "TIM1 ADC channel 1" + depends on AT32_ADC1 + select AT32_HAVE_ADC1_TIMER + ---help--- + Reserve TIM1 to trigger ADC1 + +config AT32_TIM1_ADC2 + bool "TIM1 ADC channel 2" + depends on AT32_ADC2 + select AT32_HAVE_ADC2_TIMER + ---help--- + Reserve TIM1 to trigger ADC2 + +config AT32_TIM1_ADC3 + bool "TIM1 ADC channel 3" + depends on AT32_ADC3 + select AT32_HAVE_ADC3_TIMER + ---help--- + Reserve TIM1 to trigger ADC3 + +endchoice + +config AT32_TIM2_ADC + bool "TIM2 ADC" + default n + depends on AT32_TIM2 && AT32_ADC + ---help--- + Reserve timer 1 for use by ADC + + Timer devices may be used for different purposes. If AT32_TIM2 is + defined then the following may also be defined to indicate that the + timer is intended to be used for ADC conversion. Note that ADC usage + requires two definition: Not only do you have to assign the timer + for used by the ADC, but then you also have to configure which ADC + channel it is assigned to. + +choice + prompt "Select TIM2 ADC channel" + default AT32_TIM2_ADC1 + depends on AT32_TIM2_ADC + +config AT32_TIM2_ADC1 + bool "TIM2 ADC channel 1" + depends on AT32_ADC1 + select AT32_HAVE_ADC1_TIMER + ---help--- + Reserve TIM2 to trigger ADC1 + +config AT32_TIM2_ADC2 + bool "TIM2 ADC channel 2" + depends on AT32_ADC2 + select AT32_HAVE_ADC2_TIMER + ---help--- + Reserve TIM2 to trigger ADC2 + +config AT32_TIM2_ADC3 + bool "TIM2 ADC channel 3" + depends on AT32_ADC3 + select AT32_HAVE_ADC3_TIMER + ---help--- + Reserve TIM2 to trigger ADC3 + +endchoice + +config AT32_TIM3_ADC + bool "TIM3 ADC" + default n + depends on AT32_TIM3 && AT32_ADC + ---help--- + Reserve timer 1 for use by ADC + + Timer devices may be used for different purposes. If AT32_TIM3 is + defined then the following may also be defined to indicate that the + timer is intended to be used for ADC conversion. Note that ADC usage + requires two definition: Not only do you have to assign the timer + for used by the ADC, but then you also have to configure which ADC + channel it is assigned to. + +choice + prompt "Select TIM3 ADC channel" + default AT32_TIM3_ADC1 + depends on AT32_TIM3_ADC + +config AT32_TIM3_ADC1 + bool "TIM3 ADC channel 1" + depends on AT32_ADC1 + select AT32_HAVE_ADC1_TIMER + ---help--- + Reserve TIM3 to trigger ADC1 + +config AT32_TIM3_ADC2 + bool "TIM3 ADC channel 2" + depends on AT32_ADC2 + select AT32_HAVE_ADC2_TIMER + ---help--- + Reserve TIM3 to trigger ADC2 + +config AT32_TIM3_ADC3 + bool "TIM3 ADC channel 3" + depends on AT32_ADC3 + select AT32_HAVE_ADC3_TIMER + ---help--- + Reserve TIM3 to trigger ADC3 + +endchoice + +config AT32_TIM4_ADC + bool "TIM4 ADC" + default n + depends on AT32_TIM4 && AT32_ADC + ---help--- + Reserve timer 1 for use by ADC + + Timer devices may be used for different purposes. If AT32_TIM4 is + defined then the following may also be defined to indicate that the + timer is intended to be used for ADC conversion. Note that ADC usage + requires two definition: Not only do you have to assign the timer + for used by the ADC, but then you also have to configure which ADC + channel it is assigned to. + +choice + prompt "Select TIM4 ADC channel" + default AT32_TIM4_ADC1 + depends on AT32_TIM4_ADC + +config AT32_TIM4_ADC1 + bool "TIM4 ADC channel 1" + depends on AT32_ADC1 + select AT32_HAVE_ADC1_TIMER + ---help--- + Reserve TIM4 to trigger ADC1 + +config AT32_TIM4_ADC2 + bool "TIM4 ADC channel 2" + depends on AT32_ADC2 + select AT32_HAVE_ADC2_TIMER + ---help--- + Reserve TIM4 to trigger ADC2 + +config AT32_TIM4_ADC3 + bool "TIM4 ADC channel 3" + depends on AT32_ADC3 + select AT32_HAVE_ADC3_TIMER + ---help--- + Reserve TIM4 to trigger ADC3 + +endchoice + +config AT32_TIM5_ADC + bool "TIM5 ADC" + default n + depends on AT32_TIM5 && AT32_ADC + ---help--- + Reserve timer 1 for use by ADC + + Timer devices may be used for different purposes. If AT32_TIM5 is + defined then the following may also be defined to indicate that the + timer is intended to be used for ADC conversion. Note that ADC usage + requires two definition: Not only do you have to assign the timer + for used by the ADC, but then you also have to configure which ADC + channel it is assigned to. + +choice + prompt "Select TIM5 ADC channel" + default AT32_TIM5_ADC1 + depends on AT32_TIM5_ADC + +config AT32_TIM5_ADC1 + bool "TIM5 ADC channel 1" + depends on AT32_ADC1 + select AT32_HAVE_ADC1_TIMER + ---help--- + Reserve TIM5 to trigger ADC1 + +config AT32_TIM5_ADC2 + bool "TIM5 ADC channel 2" + depends on AT32_ADC2 + select AT32_HAVE_ADC2_TIMER + ---help--- + Reserve TIM5 to trigger ADC2 + +config AT32_TIM5_ADC3 + bool "TIM5 ADC channel 3" + depends on AT32_ADC3 + select AT32_HAVE_ADC3_TIMER + ---help--- + Reserve TIM5 to trigger ADC3 + +endchoice + +config AT32_TIM8_ADC + bool "TIM8 ADC" + default n + depends on AT32_TIM8 && AT32_ADC + ---help--- + Reserve timer 1 for use by ADC + + Timer devices may be used for different purposes. If AT32_TIM8 is + defined then the following may also be defined to indicate that the + timer is intended to be used for ADC conversion. Note that ADC usage + requires two definition: Not only do you have to assign the timer + for used by the ADC, but then you also have to configure which ADC + channel it is assigned to. + +choice + prompt "Select TIM8 ADC channel" + default AT32_TIM8_ADC1 + depends on AT32_TIM8_ADC + +config AT32_TIM8_ADC1 + bool "TIM8 ADC channel 1" + depends on AT32_ADC1 + select AT32_HAVE_ADC1_TIMER + ---help--- + Reserve TIM8 to trigger ADC1 + +config AT32_TIM8_ADC2 + bool "TIM8 ADC channel 2" + depends on AT32_ADC2 + select AT32_HAVE_ADC2_TIMER + ---help--- + Reserve TIM8 to trigger ADC2 + +config AT32_TIM8_ADC3 + bool "TIM8 ADC channel 3" + depends on AT32_ADC3 + select AT32_HAVE_ADC3_TIMER + ---help--- + Reserve TIM8 to trigger ADC3 + +endchoice + +config AT32_HAVE_ADC1_TIMER + bool + +config AT32_HAVE_ADC2_TIMER + bool + +config AT32_HAVE_ADC3_TIMER + bool + +config AT32_HAVE_ADC4_TIMER + bool + +config AT32_HAVE_ADC5_TIMER + bool + +config AT32_ADC1_SAMPLE_FREQUENCY + int "ADC1 Sampling Frequency" + default 100 + depends on AT32_HAVE_ADC1_TIMER + ---help--- + ADC1 sampling frequency. Default: 100Hz + +config AT32_ADC1_TIMTRIG + int "ADC1 Timer Trigger" + default 0 + range 0 4 + depends on AT32_HAVE_ADC1_TIMER + ---help--- + Values 0:CC1 1:CC2 2:CC3 3:CC4 4:TRGO + +config AT32_ADC2_SAMPLE_FREQUENCY + int "ADC2 Sampling Frequency" + default 100 + depends on AT32_HAVE_ADC2_TIMER + ---help--- + ADC2 sampling frequency. Default: 100Hz + +config AT32_ADC2_TIMTRIG + int "ADC2 Timer Trigger" + default 0 + range 0 4 + depends on AT32_HAVE_ADC2_TIMER + ---help--- + Values 0:CC1 1:CC2 2:CC3 3:CC4 4:TRGO + +config AT32_ADC3_SAMPLE_FREQUENCY + int "ADC3 Sampling Frequency" + default 100 + depends on AT32_HAVE_ADC3_TIMER + ---help--- + ADC3 sampling frequency. Default: 100Hz + +config AT32_ADC3_TIMTRIG + int "ADC3 Timer Trigger" + default 0 + range 0 4 + depends on AT32_HAVE_ADC3_TIMER + ---help--- + Values 0:CC1 1:CC2 2:CC3 3:CC4 4:TRGO + +config AT32_TIM1_DAC + bool "TIM1 DAC" + default n + depends on AT32_TIM1 && AT32_DAC + ---help--- + Reserve timer 1 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM1 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM1 DAC channel" + default AT32_TIM1_DAC1 + depends on AT32_TIM1_DAC + +config AT32_TIM1_DAC1 + bool "TIM1 DAC channel 1" + ---help--- + Reserve TIM1 to trigger DAC1 + +config AT32_TIM1_DAC2 + bool "TIM1 DAC channel 2" + ---help--- + Reserve TIM1 to trigger DAC2 + +endchoice + +config AT32_TIM2_DAC + bool "TIM2 DAC" + default n + depends on AT32_TIM2 && AT32_DAC + ---help--- + Reserve timer 2 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM2 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM2 DAC channel" + default AT32_TIM2_DAC1 + depends on AT32_TIM2_DAC + +config AT32_TIM2_DAC1 + bool "TIM2 DAC channel 1" + ---help--- + Reserve TIM2 to trigger DAC1 + +config AT32_TIM2_DAC2 + bool "TIM2 DAC channel 2" + ---help--- + Reserve TIM2 to trigger DAC2 + +endchoice + +config AT32_TIM3_DAC + bool "TIM3 DAC" + default n + depends on AT32_TIM3 && AT32_DAC + ---help--- + Reserve timer 3 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM3 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM3 DAC channel" + default AT32_TIM3_DAC1 + depends on AT32_TIM3_DAC + +config AT32_TIM3_DAC1 + bool "TIM3 DAC channel 1" + ---help--- + Reserve TIM3 to trigger DAC1 + +config AT32_TIM3_DAC2 + bool "TIM3 DAC channel 2" + ---help--- + Reserve TIM3 to trigger DAC2 + +endchoice + +config AT32_TIM4_DAC + bool "TIM4 DAC" + default n + depends on AT32_TIM4 && AT32_DAC + ---help--- + Reserve timer 4 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM4 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM4 DAC channel" + default AT32_TIM4_DAC1 + depends on AT32_TIM4_DAC + +config AT32_TIM4_DAC1 + bool "TIM4 DAC channel 1" + ---help--- + Reserve TIM4 to trigger DAC1 + +config AT32_TIM4_DAC2 + bool "TIM4 DAC channel 2" + ---help--- + Reserve TIM4 to trigger DAC2 + +endchoice + +config AT32_TIM5_DAC + bool "TIM5 DAC" + default n + depends on AT32_TIM5 && AT32_DAC + ---help--- + Reserve timer 5 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM5 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM5 DAC channel" + default AT32_TIM5_DAC1 + depends on AT32_TIM5_DAC + +config AT32_TIM5_DAC1 + bool "TIM5 DAC channel 1" + ---help--- + Reserve TIM5 to trigger DAC1 + +config AT32_TIM5_DAC2 + bool "TIM5 DAC channel 2" + ---help--- + Reserve TIM5 to trigger DAC2 + +endchoice + +config AT32_TIM6_DAC + bool "TIM6 DAC" + default n + depends on AT32_TIM6 && AT32_DAC + ---help--- + Reserve timer 6 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM6 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM6 DAC channel" + default AT32_TIM6_DAC1 + depends on AT32_TIM6_DAC + +config AT32_TIM6_DAC1 + bool "TIM6 DAC channel 1" + ---help--- + Reserve TIM6 to trigger DAC1 + +config AT32_TIM6_DAC2 + bool "TIM6 DAC channel 2" + ---help--- + Reserve TIM6 to trigger DAC2 + +endchoice + +config AT32_TIM7_DAC + bool "TIM7 DAC" + default n + depends on AT32_TIM7 && AT32_DAC + ---help--- + Reserve timer 7 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM7 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM7 DAC channel" + default AT32_TIM7_DAC1 + depends on AT32_TIM7_DAC + +config AT32_TIM7_DAC1 + bool "TIM7 DAC channel 1" + ---help--- + Reserve TIM7 to trigger DAC1 + +config AT32_TIM7_DAC2 + bool "TIM7 DAC channel 2" + ---help--- + Reserve TIM7 to trigger DAC2 + +endchoice + +config AT32_TIM8_DAC + bool "TIM8 DAC" + default n + depends on AT32_TIM8 && AT32_DAC + ---help--- + Reserve timer 8 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM8 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM8 DAC channel" + default AT32_TIM8_DAC1 + depends on AT32_TIM8_DAC + +config AT32_TIM8_DAC1 + bool "TIM8 DAC channel 1" + ---help--- + Reserve TIM8 to trigger DAC1 + +config AT32_TIM8_DAC2 + bool "TIM8 DAC channel 2" + ---help--- + Reserve TIM8 to trigger DAC2 + +endchoice + +config AT32_TIM9_DAC + bool "TIM9 DAC" + default n + depends on AT32_TIM9 && AT32_DAC + ---help--- + Reserve timer 9 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM9 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM9 DAC channel" + default AT32_TIM9_DAC1 + depends on AT32_TIM9_DAC + +config AT32_TIM9_DAC1 + bool "TIM9 DAC channel 1" + ---help--- + Reserve TIM9 to trigger DAC1 + +config AT32_TIM9_DAC2 + bool "TIM9 DAC channel 2" + ---help--- + Reserve TIM9 to trigger DAC2 + +endchoice + +config AT32_TIM10_DAC + bool "TIM10 DAC" + default n + depends on AT32_TIM10 && AT32_DAC + ---help--- + Reserve timer 10 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM10 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM10 DAC channel" + default AT32_TIM10_DAC1 + depends on AT32_TIM10_DAC + +config AT32_TIM10_DAC1 + bool "TIM10 DAC channel 1" + ---help--- + Reserve TIM10 to trigger DAC1 + +config AT32_TIM10_DAC2 + bool "TIM10 DAC channel 2" + ---help--- + Reserve TIM10 to trigger DAC2 + +endchoice + +config AT32_TIM11_DAC + bool "TIM11 DAC" + default n + depends on AT32_TIM11 && AT32_DAC + ---help--- + Reserve timer 11 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM11 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM11 DAC channel" + default AT32_TIM11_DAC1 + depends on AT32_TIM11_DAC + +config AT32_TIM11_DAC1 + bool "TIM11 DAC channel 1" + ---help--- + Reserve TIM11 to trigger DAC1 + +config AT32_TIM11_DAC2 + bool "TIM11 DAC channel 2" + ---help--- + Reserve TIM11 to trigger DAC2 + +endchoice + +config AT32_TIM12_DAC + bool "TIM12 DAC" + default n + depends on AT32_TIM12 && AT32_DAC + ---help--- + Reserve timer 12 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM12 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM12 DAC channel" + default AT32_TIM12_DAC1 + depends on AT32_TIM12_DAC + +config AT32_TIM12_DAC1 + bool "TIM12 DAC channel 1" + ---help--- + Reserve TIM12 to trigger DAC1 + +config AT32_TIM12_DAC2 + bool "TIM12 DAC channel 2" + ---help--- + Reserve TIM12 to trigger DAC2 + +endchoice + +config AT32_TIM13_DAC + bool "TIM13 DAC" + default n + depends on AT32_TIM13 && AT32_DAC + ---help--- + Reserve timer 13 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM13 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM13 DAC channel" + default AT32_TIM13_DAC1 + depends on AT32_TIM13_DAC + +config AT32_TIM13_DAC1 + bool "TIM13 DAC channel 1" + ---help--- + Reserve TIM13 to trigger DAC1 + +config AT32_TIM13_DAC2 + bool "TIM13 DAC channel 2" + ---help--- + Reserve TIM13 to trigger DAC2 + +endchoice + +config AT32_TIM14_DAC + bool "TIM14 DAC" + default n + depends on AT32_TIM14 && AT32_DAC + ---help--- + Reserve timer 14 for use by DAC + + Timer devices may be used for different purposes. If AT32_TIM14 is + defined then the following may also be defined to indicate that the + timer is intended to be used for DAC conversion. Note that DAC usage + requires two definition: Not only do you have to assign the timer + for used by the DAC, but then you also have to configure which DAC + channel it is assigned to. + +choice + prompt "Select TIM14 DAC channel" + default AT32_TIM14_DAC1 + depends on AT32_TIM14_DAC + +config AT32_TIM14_DAC1 + bool "TIM14 DAC channel 1" + ---help--- + Reserve TIM14 to trigger DAC1 + +config AT32_TIM14_DAC2 + bool "TIM14 DAC channel 2" + ---help--- + Reserve TIM14 to trigger DAC2 + +endchoice + +config AT32_TIM1_CAP + bool "TIM1 Capture" + default n + depends on AT32_TIM1 + select AT32_CAP + ---help--- + Reserve timer 1 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM1_CAP + +config AT32_TIM1_CHANNEL + int "TIM1 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM1 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM1_CLOCK + int "TIM1 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM1_CAP + +config AT32_TIM2_CAP + bool "TIM2 Capture" + default n + depends on AT32_TIM2 + select AT32_CAP + ---help--- + Reserve timer 2 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM2_CAP + +config AT32_TIM2_CHANNEL + int "TIM2 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM2 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM2_CLOCK + int "TIM2 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM2_CAP + +config AT32_TIM3_CAP + bool "TIM3 Capture" + default n + depends on AT32_TIM3 + select AT32_CAP + ---help--- + Reserve timer 3 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM3_CAP + +config AT32_TIM3_CHANNEL + int "TIM3 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM3 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM3_CLOCK + int "TIM3 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM3_CAP + +config AT32_TIM4_CAP + bool "TIM4 Capture" + default n + depends on AT32_TIM4 + select AT32_CAP + ---help--- + Reserve timer 4 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM4_CAP + +config AT32_TIM4_CHANNEL + int "TIM4 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM4 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM4_CLOCK + int "TIM4 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM4_CAP + +config AT32_TIM5_CAP + bool "TIM5 Capture" + default n + depends on AT32_TIM5 + select AT32_CAP + ---help--- + Reserve timer 5 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM5_CAP + +config AT32_TIM5_CHANNEL + int "TIM5 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM5 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM5_CLOCK + int "TIM5 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM5_CAP + +config AT32_TIM8_CAP + bool "TIM8 Capture" + default n + depends on AT32_TIM8 + select AT32_CAP + ---help--- + Reserve timer 8 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM8_CAP + +config AT32_TIM8_CHANNEL + int "TIM8 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM8 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM8_CLOCK + int "TIM8 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM8_CAP + +config AT32_TIM9_CAP + bool "TIM9 Capture" + default n + depends on AT32_TIM9 + select AT32_CAP + ---help--- + Reserve timer 9 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM9_CAP + +config AT32_TIM9_CHANNEL + int "TIM9 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM9 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM9_CLOCK + int "TIM9 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM9_CAP + +config AT32_TIM10_CAP + bool "TIM10 Capture" + default n + depends on AT32_TIM10 + select AT32_CAP + ---help--- + Reserve timer 10 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM10_CAP + +config AT32_TIM10_CHANNEL + int "TIM10 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM10 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM10_CLOCK + int "TIM10 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM10_CAP + +config AT32_TIM11_CAP + bool "TIM11 Capture" + default n + depends on AT32_TIM11 + select AT32_CAP + ---help--- + Reserve timer 11 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM11_CAP + +config AT32_TIM11_CHANNEL + int "TIM11 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM11 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM11_CLOCK + int "TIM11 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM11_CAP + +config AT32_TIM12_CAP + bool "TIM12 Capture" + default n + depends on AT32_TIM12 + select AT32_CAP + ---help--- + Reserve timer 12 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM12_CAP + +config AT32_TIM12_CHANNEL + int "TIM12 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM12 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM12_CLOCK + int "TIM12 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM12_CAP + +config AT32_TIM13_CAP + bool "TIM13 Capture" + default n + depends on AT32_TIM13 + select AT32_CAP + ---help--- + Reserve timer 13 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM13_CAP + +config AT32_TIM13_CHANNEL + int "TIM13 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM13 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM13_CLOCK + int "TIM13 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM13_CAP + +config AT32_TIM14_CAP + bool "TIM14 Capture" + default n + depends on AT32_TIM14 + select AT32_CAP + ---help--- + Reserve timer 14 for use by Capture + + Timer devices may be used for different purposes. One special purpose is + to capture input. + +if AT32_TIM14_CAP + +config AT32_TIM14_CHANNEL + int "TIM14 Capture Input Channel" + default 1 + range 1 4 + ---help--- + If TIM14 is enabled for capture usage, you also need specifies the timer input + channel {1,..,4} + +config AT32_TIM14_CLOCK + int "TIM14 work frequence for capture" + default 1000000 + ---help--- + This clock frequence limiting the count rate at the expense of resolution. + +endif # AT32_TIM14_CAP + +menu "AT32 TIMx Outputs Configuration" + +config AT32_TIM1_CH1POL + int "TIM1 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM1_CH1OUT + ---help--- + TIM1 Channel 1 output polarity + +config AT32_TIM1_CH1IDLE + int "TIM1 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM1_CH1OUT + ---help--- + TIM1 Channel 1 output IDLE + +config AT32_TIM1_CH1NPOL + int "TIM1 Channel 1 Complementary Output polarity" + default 0 + range 0 1 + depends on AT32_TIM1_CH1NOUT + ---help--- + TIM1 Channel 1 Complementary Output polarity + +config AT32_TIM1_CH1NIDLE + int "TIM1 Channel 1 Complementary Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM1_CH1NOUT + ---help--- + TIM1 Channel 1 Complementary Output IDLE + +config AT32_TIM1_CH2POL + int "TIM1 Channel 2 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM1_CH2OUT + ---help--- + TIM1 Channel 2 output polarity + +config AT32_TIM1_CH2IDLE + int "TIM1 Channel 2 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM1_CH2OUT + ---help--- + TIM1 Channel 2 output IDLE + +config AT32_TIM1_CH2NPOL + int "TIM1 Channel 2 Complementary Output polarity" + default 0 + range 0 1 + depends on AT32_TIM1_CH2NOUT + ---help--- + TIM1 Channel 2 Complementary Output polarity + +config AT32_TIM1_CH2NIDLE + int "TIM1 Channel 2 Complementary Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM1_CH2NOUT + ---help--- + TIM1 Channel 2 Complementary Output IDLE + +config AT32_TIM1_CH3POL + int "TIM1 Channel 3 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM1_CH3OUT + ---help--- + TIM1 Channel 3 output polarity + +config AT32_TIM1_CH3IDLE + int "TIM1 Channel 3 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM1_CH3OUT + ---help--- + TIM1 Channel 3 output IDLE + +config AT32_TIM1_CH3NPOL + int "TIM1 Channel 3 Complementary Output polarity" + default 0 + range 0 1 + depends on AT32_TIM1_CH3NOUT + ---help--- + TIM1 Channel 3 Complementary Output polarity + +config AT32_TIM1_CH3NIDLE + int "TIM1 Channel 3 Complementary Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM1_CH3NOUT + ---help--- + TIM1 Channel 3 Complementary Output IDLE + +config AT32_TIM1_CH4POL + int "TIM1 Channel 4 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM1_CH4OUT + ---help--- + TIM1 Channel 4 output polarity + +config AT32_TIM1_CH4IDLE + int "TIM1 Channel 4 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM1_CH4OUT + ---help--- + TIM1 Channel 4 output IDLE + +config AT32_TIM1_CH5POL + int "TIM1 Channel 5 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM1_CH5OUT + ---help--- + TIM1 Channel 5 output polarity + +config AT32_TIM1_CH5IDLE + int "TIM1 Channel 5 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM1_CH5OUT + ---help--- + TIM1 Channel 5 output IDLE + +config AT32_TIM1_CH6POL + int "TIM1 Channel 6 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM1_CH6OUT + ---help--- + TIM1 Channel 6 output polarity + +config AT32_TIM1_CH6IDLE + int "TIM1 Channel 6 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM1_CH6OUT + ---help--- + TIM1 Channel 6 output IDLE + +config AT32_TIM2_CH1POL + int "TIM2 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM2_CH1OUT + ---help--- + TIM2 Channel 1 output polarity + +config AT32_TIM2_CH1IDLE + int "TIM2 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM2_CH1OUT + ---help--- + TIM2 Channel 1 output IDLE + +config AT32_TIM2_CH2POL + int "TIM2 Channel 2 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM2_CH2OUT + ---help--- + TIM2 Channel 2 output polarity + +config AT32_TIM2_CH2IDLE + int "TIM2 Channel 2 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM2_CH2OUT + ---help--- + TIM2 Channel 2 output IDLE + +config AT32_TIM2_CH3POL + int "TIM2 Channel 3 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM2_CH3OUT + ---help--- + TIM2 Channel 3 output polarity + +config AT32_TIM2_CH3IDLE + int "TIM2 Channel 3 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM2_CH3OUT + ---help--- + TIM2 Channel 3 output IDLE + +config AT32_TIM2_CH4POL + int "TIM2 Channel 4 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM2_CH4OUT + ---help--- + TIM2 Channel 4 output polarity + +config AT32_TIM2_CH4IDLE + int "TIM2 Channel 4 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM2_CH4OUT + ---help--- + TIM2 Channel 4 output IDLE + +config AT32_TIM3_CH1POL + int "TIM3 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM3_CH1OUT + ---help--- + TIM3 Channel 1 output polarity + +config AT32_TIM3_CH1IDLE + int "TIM3 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM3_CH1OUT + ---help--- + TIM3 Channel 1 output IDLE + +config AT32_TIM3_CH2POL + int "TIM3 Channel 2 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM3_CH2OUT + ---help--- + TIM3 Channel 2 output polarity + +config AT32_TIM3_CH2IDLE + int "TIM3 Channel 2 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM3_CH2OUT + ---help--- + TIM3 Channel 2 output IDLE + +config AT32_TIM3_CH3POL + int "TIM3 Channel 3 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM3_CH3OUT + ---help--- + TIM3 Channel 3 output polarity + +config AT32_TIM3_CH3IDLE + int "TIM3 Channel 3 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM3_CH3OUT + ---help--- + TIM3 Channel 3 output IDLE + +config AT32_TIM3_CH4POL + int "TIM3 Channel 4 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM3_CH4OUT + ---help--- + TIM3 Channel 4 output polarity + +config AT32_TIM3_CH4IDLE + int "TIM3 Channel 4 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM3_CH4OUT + ---help--- + TIM3 Channel 4 output IDLE + +config AT32_TIM4_CH1POL + int "TIM4 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM4_CH1OUT + ---help--- + TIM4 Channel 1 output polarity + +config AT32_TIM4_CH1IDLE + int "TIM4 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM4_CH1OUT + ---help--- + TIM4 Channel 1 output IDLE + +config AT32_TIM4_CH2POL + int "TIM4 Channel 2 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM4_CH2OUT + ---help--- + TIM4 Channel 2 output polarity + +config AT32_TIM4_CH2IDLE + int "TIM4 Channel 2 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM4_CH2OUT + ---help--- + TIM4 Channel 2 output IDLE + +config AT32_TIM4_CH3POL + int "TIM4 Channel 3 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM4_CH3OUT + ---help--- + TIM4 Channel 3 output polarity + +config AT32_TIM4_CH3IDLE + int "TIM4 Channel 3 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM4_CH3OUT + ---help--- + TIM4 Channel 3 output IDLE + +config AT32_TIM4_CH4POL + int "TIM4 Channel 4 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM4_CH4OUT + ---help--- + TIM4 Channel 4 output polarity + +config AT32_TIM4_CH4IDLE + int "TIM4 Channel 4 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM4_CH4OUT + ---help--- + TIM4 Channel 4 output IDLE + +config AT32_TIM5_CH1POL + int "TIM5 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM5_CH1OUT + ---help--- + TIM5 Channel 1 output polarity + +config AT32_TIM5_CH1IDLE + int "TIM5 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM5_CH1OUT + ---help--- + TIM5 Channel 1 output IDLE + +config AT32_TIM5_CH2POL + int "TIM5 Channel 2 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM5_CH2OUT + ---help--- + TIM5 Channel 2 output polarity + +config AT32_TIM5_CH2IDLE + int "TIM5 Channel 2 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM5_CH2OUT + ---help--- + TIM5 Channel 2 output IDLE + +config AT32_TIM5_CH3POL + int "TIM5 Channel 3 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM5_CH3OUT + ---help--- + TIM5 Channel 3 output polarity + +config AT32_TIM5_CH3IDLE + int "TIM5 Channel 3 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM5_CH3OUT + ---help--- + TIM5 Channel 3 output IDLE + +config AT32_TIM5_CH4POL + int "TIM5 Channel 4 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM5_CH4OUT + ---help--- + TIM5 Channel 4 output polarity + +config AT32_TIM5_CH4IDLE + int "TIM5 Channel 4 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM5_CH4OUT + ---help--- + TIM5 Channel 4 output IDLE + +config AT32_TIM8_CH1POL + int "TIM8 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM8_CH1OUT + ---help--- + TIM8 Channel 1 output polarity + +config AT32_TIM8_CH1IDLE + int "TIM8 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM8_CH1OUT + ---help--- + TIM8 Channel 1 output IDLE + +config AT32_TIM8_CH1NPOL + int "TIM8 Channel 1 Complementary Output polarity" + default 0 + range 0 1 + depends on AT32_TIM8_CH1NOUT + ---help--- + TIM8 Channel 1 Complementary Output polarity + +config AT32_TIM8_CH1NIDLE + int "TIM8 Channel 1 Complementary Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM8_CH1NOUT + ---help--- + TIM8 Channel 1 Complementary Output IDLE + +config AT32_TIM8_CH2POL + int "TIM8 Channel 2 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM8_CH2OUT + ---help--- + TIM8 Channel 2 output polarity + +config AT32_TIM8_CH2IDLE + int "TIM8 Channel 2 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM8_CH2OUT + ---help--- + TIM8 Channel 2 output IDLE + +config AT32_TIM8_CH2NPOL + int "TIM8 Channel 2 Complementary Output polarity" + default 0 + range 0 1 + depends on AT32_TIM8_CH2NOUT + ---help--- + TIM8 Channel 2 Complementary Output polarity + +config AT32_TIM8_CH2NIDLE + int "TIM8 Channel 2 Complementary Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM8_CH2NOUT + ---help--- + TIM8 Channel 2 Complementary Output IDLE + +config AT32_TIM8_CH3POL + int "TIM8 Channel 3 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM8_CH3OUT + ---help--- + TIM8 Channel 3 output polarity + +config AT32_TIM8_CH3IDLE + int "TIM8 Channel 3 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM8_CH3OUT + ---help--- + TIM8 Channel 3 output IDLE + +config AT32_TIM8_CH3NPOL + int "TIM8 Channel 3 Complementary Output polarity" + default 0 + range 0 1 + depends on AT32_TIM8_CH3NOUT + ---help--- + TIM8 Channel 3 Complementary Output polarity + +config AT32_TIM8_CH3NIDLE + int "TIM8 Channel 3 Complementary Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM8_CH3NOUT + ---help--- + TIM8 Channel 3 Complementary Output IDLE + +config AT32_TIM8_CH4POL + int "TIM8 Channel 4 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM8_CH4OUT + ---help--- + TIM8 Channel 4 output polarity + +config AT32_TIM8_CH4IDLE + int "TIM8 Channel 4 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM8_CH4OUT + ---help--- + TIM8 Channel 4 output IDLE + +config AT32_TIM8_CH5POL + int "TIM8 Channel 5 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM8_CH5OUT + ---help--- + TIM8 Channel 5 output polarity + +config AT32_TIM8_CH5IDLE + int "TIM8 Channel 5 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM8_CH5OUT + ---help--- + TIM8 Channel 5 output IDLE + +config AT32_TIM8_CH6POL + int "TIM8 Channel 6 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM8_CH6OUT + ---help--- + TIM8 Channel 6 output polarity + +config AT32_TIM8_CH6IDLE + int "TIM8 Channel 6 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM8_CH6OUT + ---help--- + TIM8 Channel 6 output IDLE + +config AT32_TIM9_CH1POL + int "TIM9 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM9_CH1OUT + ---help--- + TIM9 Channel 1 output polarity + +config AT32_TIM9_CH1IDLE + int "TIM9 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM9_CH1OUT + ---help--- + TIM9 Channel 1 output IDLE + +config AT32_TIM9_CH2POL + int "TIM9 Channel 2 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM9_CH2OUT + ---help--- + TIM9 Channel 2 output polarity + +config AT32_TIM9_CH2IDLE + int "TIM9 Channel 2 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM9_CH2OUT + ---help--- + TIM9 Channel 2 output IDLE + +config AT32_TIM10_CH1POL + int "TIM10 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM10_CH1OUT + ---help--- + TIM10 Channel 1 output polarity + +config AT32_TIM10_CH1IDLE + int "TIM10 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM10_CH1OUT + ---help--- + TIM10 Channel 1 output IDLE + +config AT32_TIM11_CH1POL + int "TIM11 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM11_CH1OUT + ---help--- + TIM11 Channel 1 output polarity + +config AT32_TIM11_CH1IDLE + int "TIM11 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM11_CH1OUT + ---help--- + TIM11 Channel 1 output IDLE + +config AT32_TIM12_CH1POL + int "TIM12 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM12_CH1OUT + ---help--- + TIM12 Channel 1 output polarity + +config AT32_TIM12_CH1IDLE + int "TIM12 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM12_CH1OUT + ---help--- + TIM12 Channel 1 output IDLE + +config AT32_TIM12_CH2POL + int "TIM12 Channel 2 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM12_CH2OUT + ---help--- + TIM12 Channel 2 output polarity + +config AT32_TIM12_CH2IDLE + int "TIM12 Channel 2 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM12_CH2OUT + ---help--- + TIM12 Channel 2 output IDLE + +config AT32_TIM13_CH1POL + int "TIM13 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM13_CH1OUT + ---help--- + TIM13 Channel 1 output polarity + +config AT32_TIM13_CH1IDLE + int "TIM13 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM13_CH1OUT + ---help--- + TIM13 Channel 1 output IDLE + +config AT32_TIM14_CH1POL + int "TIM14 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM14_CH1OUT + ---help--- + TIM14 Channel 1 output polarity + +config AT32_TIM14_CH1IDLE + int "TIM14 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM14_CH1OUT + ---help--- + TIM14 Channel 1 output IDLE + +config AT32_TIM15_CH1POL + int "TIM15 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM15_CH1OUT + ---help--- + TIM15 Channel 1 output polarity + +config AT32_TIM15_CH1IDLE + int "TIM15 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM15_CH1OUT + ---help--- + TIM15 Channel 1 output IDLE + +config AT32_TIM15_CH1NPOL + int "TIM15 Channel 1 Complementary Output polarity" + default 0 + range 0 1 + depends on AT32_TIM15_CH1NOUT + ---help--- + TIM15 Channel 1 Complementary Output polarity + +config AT32_TIM15_CH1NIDLE + int "TIM15 Channel 1 Complementary Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM15_CH1NOUT + ---help--- + TIM15 Channel 1 Complementary Output IDLE + +config AT32_TIM15_CH2POL + int "TIM15 Channel 2 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM15_CH2OUT + ---help--- + TIM15 Channel 2 output polarity + +config AT32_TIM15_CH2IDLE + int "TIM15 Channel 2 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM15_CH2OUT + ---help--- + TIM15 Channel 2 output IDLE + +config AT32_TIM15_CH2NPOL + int "TIM15 Channel 2 Complementary Output polarity" + default 0 + range 0 1 + depends on AT32_TIM15_CH2NOUT + ---help--- + TIM15 Channel 2 Complementary Output polarity + +config AT32_TIM15_CH2NIDLE + int "TIM15 Channel 2 Complementary Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM15_CH2NOUT + ---help--- + TIM15 Channel 2 Complementary Output IDLE + +config AT32_TIM16_CH1POL + int "TIM16 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM16_CH1OUT + ---help--- + TIM16 Channel 1 output polarity + +config AT32_TIM16_CH1IDLE + int "TIM16 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM16_CH1OUT + ---help--- + TIM16 Channel 1 output IDLE + +config AT32_TIM17_CH1POL + int "TIM17 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM17_CH1OUT + ---help--- + TIM17 Channel 1 output polarity + +config AT32_TIM17_CH1IDLE + int "TIM17 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM17_CH1OUT + ---help--- + TIM17 Channel 1 output IDLE + +config AT32_TIM20_CH1POL + int "TIM20 Channel 1 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM20_CH1OUT + ---help--- + TIM20 Channel 1 output polarity + +config AT32_TIM20_CH1IDLE + int "TIM20 Channel 1 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM20_CH1OUT + ---help--- + TIM20 Channel 1 output IDLE + +config AT32_TIM20_CH1NPOL + int "TIM20 Channel 1 Complementary Output polarity" + default 0 + range 0 1 + depends on AT32_TIM20_CH1NOUT + ---help--- + TIM20 Channel 1 Complementary Output polarity + +config AT32_TIM20_CH1NIDLE + int "TIM20 Channel 1 Complementary Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM20_CH1NOUT + ---help--- + TIM20 Channel 1 Complementary Output IDLE + +config AT32_TIM20_CH2POL + int "TIM20 Channel 2 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM20_CH2OUT + ---help--- + TIM20 Channel 2 output polarity + +config AT32_TIM20_CH2IDLE + int "TIM20 Channel 2 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM20_CH2OUT + ---help--- + TIM20 Channel 2 output IDLE + +config AT32_TIM20_CH2NPOL + int "TIM20 Channel 2 Complementary Output polarity" + default 0 + range 0 1 + depends on AT32_TIM20_CH2NOUT + ---help--- + TIM20 Channel 2 Complementary Output polarity + +config AT32_TIM20_CH2NIDLE + int "TIM20 Channel 2 Complementary Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM20_CH2NOUT + ---help--- + TIM20 Channel 2 Complementary Output IDLE + +config AT32_TIM20_CH3POL + int "TIM20 Channel 3 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM20_CH3OUT + ---help--- + TIM20 Channel 3 output polarity + +config AT32_TIM20_CH3IDLE + int "TIM20 Channel 3 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM20_CH3OUT + ---help--- + TIM20 Channel 3 output IDLE + +config AT32_TIM20_CH3NPOL + int "TIM20 Channel 3 Complementary Output polarity" + default 0 + range 0 1 + depends on AT32_TIM20_CH3NOUT + ---help--- + TIM20 Channel 3 Complementary Output polarity + +config AT32_TIM20_CH3NIDLE + int "TIM20 Channel 3 Complementary Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM20_CH3NOUT + ---help--- + TIM20 Channel 3 Complementary Output IDLE + +config AT32_TIM20_CH4POL + int "TIM20 Channel 4 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM20_CH4OUT + ---help--- + TIM20 Channel 4 output polarity + +config AT32_TIM20_CH4IDLE + int "TIM20 Channel 4 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM20_CH4OUT + ---help--- + TIM20 Channel 4 output IDLE + +config AT32_TIM20_CH5POL + int "TIM20 Channel 5 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM20_CH5OUT + ---help--- + TIM20 Channel 5 output polarity + +config AT32_TIM20_CH5IDLE + int "TIM20 Channel 5 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM20_CH5OUT + ---help--- + TIM20 Channel 5 output IDLE + +config AT32_TIM20_CH6POL + int "TIM20 Channel 6 Output polarity" + default 0 + range 0 1 + depends on AT32_TIM20_CH6OUT + ---help--- + TIM20 Channel 6 output polarity + +config AT32_TIM20_CH6IDLE + int "TIM20 Channel 6 Output IDLE" + default 0 + range 0 1 + depends on AT32_TIM20_CH6OUT + ---help--- + TIM20 Channel 6 output IDLE + +endmenu #AT32 TIMx Outputs Configuration + +endmenu # Timer Configuration + +menu "ADC Configuration" + depends on AT32_ADC + +config AT32_ADC1_RESOLUTION + int "ADC1 resolution" + depends on AT32_ADC1 && !AT32_HAVE_IP_ADC_V1_BASIC + default 0 + range 0 3 + ---help--- + ADC1 resolution. 0 - 12 bit, 1 - 10 bit, 2 - 8 bit, 3 - 6 bit + +config AT32_ADC2_RESOLUTION + int "ADC2 resolution" + depends on AT32_ADC2 && !AT32_HAVE_IP_ADC_V1_BASIC + default 0 + range 0 3 + ---help--- + ADC2 resolution. 0 - 12 bit, 1 - 10 bit, 2 - 8 bit, 3 - 6 bit + +config AT32_ADC3_RESOLUTION + int "ADC3 resolution" + depends on AT32_ADC3 && !AT32_HAVE_IP_ADC_V1_BASIC + default 0 + range 0 3 + ---help--- + ADC3 resolution. 0 - 12 bit, 1 - 10 bit, 2 - 8 bit, 3 - 6 bit + +config AT32_ADC4_RESOLUTION + int "ADC4 resolution" + depends on AT32_ADC4 && !AT32_HAVE_IP_ADC_V1_BASIC + default 0 + range 0 3 + ---help--- + ADC4 resolution. 0 - 12 bit, 1 - 10 bit, 2 - 8 bit, 3 - 6 bit + +config AT32_ADC5_RESOLUTION + int "ADC5 resolution" + depends on AT32_ADC5 && !AT32_HAVE_IP_ADC_V1_BASIC + default 0 + range 0 3 + ---help--- + ADC5 resolution. 0 - 12 bit, 1 - 10 bit, 2 - 8 bit, 3 - 6 bit + +config AT32_ADC_MAX_SAMPLES + int "The maximum number of channels that can be sampled" + default 16 + ---help--- + The maximum number of samples which can be handled without + overrun depends on various factors. This is the user's + responsibility to correctly select this value. + Since the interface to update the sampling time is available + for all supported devices, the user can change the default + values in the board initialization logic and avoid ADC overrun. + +config AT32_ADC_NO_STARTUP_CONV + bool "Do not start conversion when opening ADC device" + default n + ---help--- + Do not start conversion when opening ADC device. + +config AT32_ADC_NOIRQ + bool "Do not use default ADC interrupts" + default n + ---help--- + Do not use default ADC interrupts handlers. + +config AT32_ADC_LL_OPS + bool "ADC low-level operations" + default n + ---help--- + Enable low-level ADC ops. + +config AT32_ADC_CHANGE_SAMPLETIME + bool "ADC sample time configuration" + default n + depends on AT32_ADC_LL_OPS + ---help--- + Enable ADC sample time configuration (SMPRx registers). + +config AT32_ADC1_DMA + bool "ADC1 DMA" + depends on AT32_ADC1 && AT32_HAVE_ADC1_DMA + default n + ---help--- + If DMA is selected, then the ADC may be configured to support + DMA transfer, which is necessary if multiple channels are read + or if very high trigger frequencies are used. + +config AT32_ADC1_SCAN + bool "ADC1 scan mode" + depends on AT32_ADC1 && AT32_HAVE_IP_ADC_V1 + default y if AT32_ADC1_DMA + default n + +config AT32_ADC1_DMA_CFG + int "ADC1 DMA configuration" + depends on AT32_ADC1_DMA && !AT32_HAVE_IP_ADC_V1_BASIC + range 0 1 + default 0 + ---help--- + 0 - ADC1 DMA in One Shot Mode, 1 - ADC1 DMA in Circular Mode + +config AT32_ADC1_ANIOC_TRIGGER + int "ADC1 software trigger (ANIOC_TRIGGER) configuration" + depends on AT32_ADC1 + range 1 3 + default 3 + ---help--- + 1 - ANIOC_TRIGGER only starts regular conversion + 2 - ANIOC_TRIGGER only starts injected conversion + 3 - ANIOC_TRIGGER starts both regular and injected conversions + +config AT32_ADC2_DMA + bool "ADC2 DMA" + depends on AT32_ADC2 && AT32_HAVE_ADC2_DMA + default n + ---help--- + If DMA is selected, then the ADC may be configured to support + DMA transfer, which is necessary if multiple channels are read + or if very high trigger frequencies are used. + +config AT32_ADC2_SCAN + bool "ADC2 scan mode" + depends on AT32_ADC2 && AT32_HAVE_IP_ADC_V1 + default y if AT32_ADC2_DMA + default n + +config AT32_ADC2_DMA_CFG + int "ADC2 DMA configuration" + depends on AT32_ADC2_DMA && !AT32_HAVE_IP_ADC_V1_BASIC + range 0 1 + default 0 + ---help--- + 0 - ADC2 DMA in One Shot Mode, 1 - ADC2 DMA in Circular Mode + +config AT32_ADC2_ANIOC_TRIGGER + int "ADC2 software trigger (ANIOC_TRIGGER) configuration" + depends on AT32_ADC2 + range 1 3 + default 3 + ---help--- + 1 - ANIOC_TRIGGER only starts regular conversion + 2 - ANIOC_TRIGGER only starts injected conversion + 3 - ANIOC_TRIGGER starts both regular and injected conversions + +config AT32_ADC3_DMA + bool "ADC3 DMA" + depends on AT32_ADC3 && AT32_HAVE_ADC3_DMA + default n + ---help--- + If DMA is selected, then the ADC may be configured to support + DMA transfer, which is necessary if multiple channels are read + or if very high trigger frequencies are used. + +config AT32_ADC3_SCAN + bool "ADC3 scan mode" + depends on AT32_ADC3 && AT32_HAVE_IP_ADC_V1 + default y if AT32_ADC3_DMA + default n + +config AT32_ADC3_DMA_CFG + int "ADC3 DMA configuration" + depends on AT32_ADC3_DMA && !AT32_HAVE_IP_ADC_V1_BASIC + range 0 1 + default 0 + ---help--- + 0 - ADC3 DMA in One Shot Mode, 1 - ADC3 DMA in Circular Mode + +config AT32_ADC3_ANIOC_TRIGGER + int "ADC3 software trigger (ANIOC_TRIGGER) configuration" + depends on AT32_ADC3 + range 1 3 + default 3 + ---help--- + 1 - ANIOC_TRIGGER only starts regular conversion + 2 - ANIOC_TRIGGER only starts injected conversion + 3 - ANIOC_TRIGGER starts both regular and injected conversions + +config AT32_ADC4_DMA + bool "ADC4 DMA" + depends on AT32_ADC4 && AT32_HAVE_ADC4_DMA + default n + ---help--- + If DMA is selected, then the ADC may be configured to support + DMA transfer, which is necessary if multiple channels are read + or if very high trigger frequencies are used. + +config AT32_ADC4_DMA_CFG + int "ADC4 DMA configuration" + depends on AT32_ADC4_DMA && !AT32_HAVE_IP_ADC_V1_BASIC + range 0 1 + default 0 + ---help--- + 0 - ADC4 DMA in One Shot Mode, 1 - ADC4 DMA in Circular Mode + +config AT32_ADC4_ANIOC_TRIGGER + int "ADC4 software trigger (ANIOC_TRIGGER) configuration" + depends on AT32_ADC4 + range 1 3 + default 3 + ---help--- + 1 - ANIOC_TRIGGER only starts regular conversion + 2 - ANIOC_TRIGGER only starts injected conversion + 3 - ANIOC_TRIGGER starts both regular and injected conversions + +config AT32_ADC5_DMA + bool "ADC5 DMA" + depends on AT32_ADC5 && AT32_HAVE_ADC5_DMA + default n + ---help--- + If DMA is selected, then the ADC may be configured to support + DMA transfer, which is necessary if multiple channels are read + or if very high trigger frequencies are used. + +config AT32_ADC5_DMA_CFG + int "ADC5 DMA configuration" + depends on AT32_ADC5_DMA && !AT32_HAVE_IP_ADC_V1_BASIC + range 0 1 + default 0 + ---help--- + 0 - ADC5 DMA in One Shot Mode, 1 - ADC5 DMA in Circular Mode + +config AT32_ADC1_INJECTED_CHAN + int "ADC1 injected channels" + depends on AT32_ADC1 + range 0 4 + default 0 + ---help--- + Support for ADC1 injected channels. + +config AT32_ADC2_INJECTED_CHAN + int "ADC2 injected channels" + depends on AT32_ADC2 + range 0 4 + default 0 + ---help--- + Support for ADC2 injected channels. + +config AT32_ADC3_INJECTED_CHAN + int "ADC3 injected channels" + depends on AT32_ADC3 + range 0 4 + default 0 + ---help--- + Support for ADC3 injected channels. + +config AT32_ADC4_INJECTED_CHAN + int "ADC4 injected channels" + depends on AT32_ADC4 + range 0 4 + default 0 + ---help--- + Support for ADC4 injected channels. + +config AT32_ADC5_INJECTED_CHAN + int "ADC5 injected channels" + depends on AT32_ADC5 + range 0 4 + default 0 + ---help--- + Support for ADC5 injected channels. + +config AT32_ADC1_EXTSEL + bool "ADC1 external trigger for regular group" + depends on AT32_ADC1 && !AT32_HAVE_ADC1_TIMER + default n + ---help--- + Enable EXTSEL for ADC1. + +config AT32_ADC2_EXTSEL + bool "ADC2 external trigger for regular group" + depends on AT32_ADC2 && !AT32_HAVE_ADC2_TIMER + default n + ---help--- + Enable EXTSEL for ADC2. + +config AT32_ADC3_EXTSEL + bool "ADC3 external trigger for regular group" + depends on AT32_ADC3 && !AT32_HAVE_ADC3_TIMER + default n + ---help--- + Enable EXTSEL for ADC3. + +config AT32_ADC4_EXTSEL + bool "ADC4 external trigger for regular group" + depends on AT32_ADC4 && !AT32_HAVE_ADC4_TIMER + default n + ---help--- + Enable EXTSEL for ADC4. + +config AT32_ADC5_EXTSEL + bool "ADC5 external trigger for regular group" + depends on AT32_ADC5 && !AT32_HAVE_ADC5_TIMER + default n + ---help--- + Enable EXTSEL for ADC5. + +config AT32_ADC1_JEXTSEL + bool "ADC1 external trigger for injected group" + depends on AT32_ADC1 + default n + ---help--- + Enable JEXTSEL for ADC1. + +config AT32_ADC2_JEXTSEL + bool "ADC2 external trigger for injected group" + depends on AT32_ADC2 + default n + ---help--- + Enable JEXTSEL for ADC2. + +config AT32_ADC3_JEXTSEL + bool "ADC3 external trigger for injected group" + depends on AT32_ADC3 + default n + ---help--- + Enable JEXTSEL for ADC3. + +config AT32_ADC4_JEXTSEL + bool "ADC4 external trigger for injected group" + depends on AT32_ADC4 + default n + ---help--- + Enable JEXTSEL for ADC4. + +config AT32_ADC5_JEXTSEL + bool "ADC5 external trigger for injected group" + depends on AT32_ADC5 + default n + ---help--- + Enable JEXTSEL for ADC5. + +endmenu + + +config AT32_USART + bool + default n + +config AT32_USART_RXDMA + bool + default n + +config AT32_SERIALDRIVER + bool + default n + +config AT32_1WIREDRIVER + bool + default n + +config AT32_HCIUART + bool + default n + +config AT32_HCIUART_RXDMA + bool + default n + +menu "U[S]ART Configuration" + depends on AT32_USART + +comment "U[S]ART Device Configuration" + +choice + prompt "USART1 Driver Configuration" + default AT32_USART1_SERIALDRIVER + depends on AT32_USART1 + +config AT32_USART1_SERIALDRIVER + bool "Standard serial driver" + select USART1_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + select AT32_SERIALDRIVER + +config AT32_USART1_1WIREDRIVER + bool "1-Wire driver" + select AT32_1WIREDRIVER + +config AT32_USART1_HCIUART + bool "Bluetooth HCI-UART" + select AT32_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # USART1 Driver Configuration + +if AT32_USART1_SERIALDRIVER + +config USART1_RS485 + bool "RS-485 on USART1" + default n + ---help--- + Enable RS-485 interface on USART1. Your board config will have to + provide GPIO_USART1_RS485_DIR pin definition. Currently it cannot be + used with USART1_RXDMA. + +config USART1_RS485_DIR_POLARITY + int "USART1 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART1_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART1. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config USART1_RXDMA + bool "USART1 Rx DMA" + default n + depends on AT32_DMA1 || AT32_DMA2 + select AT32_USART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config USART1_TXDMA + bool "USART1 Tx DMA" + default n + depends on AT32_DMA1 || AT32_DMA2 + select AT32_USART_TXDMA + ---help--- + In high data rate usage, Tx DMA may reduce CPU load + +endif # AT32_USART1_SERIALDRIVER + +if AT32_USART1_HCIUART + +config AT32_HCIUART1_RXBUFSIZE + int "HCI UART1 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config AT32_HCIUART1_TXBUFSIZE + int "HCI UART1 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config AT32_HCIUART1_BAUD + int "HCI UART1 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCIR USART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +config AT32_HCIUART1_RXDMA + bool "HCI UART1 Rx DMA" + default n + depends on AT32_DMA1 || AT32_DMA2 + select AT32_HCIUART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +endif # AT32_USART1_HCIUART + +choice + prompt "USART2 Driver Configuration" + default AT32_USART2_SERIALDRIVER + depends on AT32_USART2 + +config AT32_USART2_SERIALDRIVER + bool "Standard serial driver" + select USART2_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + select AT32_SERIALDRIVER + +config AT32_USART2_1WIREDRIVER + bool "1-Wire driver" + select AT32_1WIREDRIVER + +config AT32_USART2_HCIUART + bool "Bluetooth HCI-UART" + select AT32_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # USART2 Driver Configuration + +if AT32_USART2_SERIALDRIVER + +config USART2_RS485 + bool "RS-485 on USART2" + default n + ---help--- + Enable RS-485 interface on USART2. Your board config will have to + provide GPIO_USART2_RS485_DIR pin definition. Currently it cannot be + used with USART2_RXDMA. + +config USART2_RS485_DIR_POLARITY + int "USART2 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART2_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART2. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config USART2_RXDMA + bool "USART2 Rx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config USART2_TXDMA + bool "USART2 Tx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_TXDMA + ---help--- + In high data rate usage, Tx DMA may reduce CPU load + +endif # AT32_USART2_SERIALDRIVER + +if AT32_USART2_HCIUART + +config AT32_HCIUART2_RXBUFSIZE + int "HCI UART2 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config AT32_HCIUART2_TXBUFSIZE + int "HCI UART2 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config AT32_HCIUART2_BAUD + int "HCI UART2 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCIR USART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +config AT32_HCIUART2_RXDMA + bool "HCI UART2 Rx DMA" + default n + depends on AT32_DMA1 + select AT32_HCIUART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +endif # AT32_USART2_HCIUART + +choice + prompt "USART3 Driver Configuration" + default AT32_USART3_SERIALDRIVER + depends on AT32_USART3 + +config AT32_USART3_SERIALDRIVER + bool "Standard serial driver" + select USART3_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + select AT32_SERIALDRIVER + +config AT32_USART3_1WIREDRIVER + bool "1-Wire driver" + select AT32_1WIREDRIVER + +config AT32_USART3_HCIUART + bool "Bluetooth HCI-UART" + select AT32_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # USART3 Driver Configuration + +if AT32_USART3_SERIALDRIVER + +config USART3_RS485 + bool "RS-485 on USART3" + default n + ---help--- + Enable RS-485 interface on USART3. Your board config will have to + provide GPIO_USART3_RS485_DIR pin definition. Currently it cannot be + used with USART3_RXDMA. + +config USART3_RS485_DIR_POLARITY + int "USART3 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART3_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART3. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config USART3_RXDMA + bool "USART3 Rx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config USART3_TXDMA + bool "USART3 Tx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_TXDMA + ---help--- + In high data rate usage, Tx DMA may reduce CPU load + +endif # AT32_USART3_SERIALDRIVER + +if AT32_USART3_HCIUART + +config AT32_HCIUART3_RXBUFSIZE + int "HCI UART3 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config AT32_HCIUART3_TXBUFSIZE + int "HCI UART3 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config AT32_HCIUART3_BAUD + int "HCI UART3 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCIR USART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +config AT32_HCIUART3_RXDMA + bool "HCI UART3 Rx DMA" + default n + depends on AT32_DMA1 + select AT32_HCIUART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +endif # AT32_USART3_HCIUART + +choice + prompt "UART4 Driver Configuration" + default AT32_UART4_SERIALDRIVER + depends on AT32_UART4 + +config AT32_UART4_SERIALDRIVER + bool "Standard serial driver" + select UART4_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + select AT32_SERIALDRIVER + +config AT32_UART4_1WIREDRIVER + bool "1-Wire driver" + select AT32_1WIREDRIVER + +endchoice # UART1 Driver Configuration + +if AT32_UART4_SERIALDRIVER + +config UART4_RS485 + bool "RS-485 on UART4" + default n + ---help--- + Enable RS-485 interface on UART4. Your board config will have to + provide GPIO_UART4_RS485_DIR pin definition. Currently it cannot be + used with UART4_RXDMA. + +config UART4_RS485_DIR_POLARITY + int "UART4 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART4_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART4. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config UART4_RXDMA + bool "UART4 Rx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config UART4_TXDMA + bool "UART4 Tx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_TXDMA + ---help--- + In high data rate usage, Tx DMA may reduce CPU load + +endif # AT32_UART4_SERIALDRIVER + +choice + prompt "UART5 Driver Configuration" + default AT32_UART5_SERIALDRIVER + depends on AT32_UART5 + +config AT32_UART5_SERIALDRIVER + bool "Standard serial driver" + select UART5_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + select AT32_SERIALDRIVER + +config AT32_UART5_1WIREDRIVER + bool "1-Wire driver" + select AT32_1WIREDRIVER + +endchoice # UART5 Driver Configuration + +if AT32_UART5_SERIALDRIVER + +config UART5_RS485 + bool "RS-485 on UART5" + default n + ---help--- + Enable RS-485 interface on UART5. Your board config will have to + provide GPIO_UART5_RS485_DIR pin definition. Currently it cannot be + used with UART5_RXDMA. + +config UART5_RS485_DIR_POLARITY + int "UART5 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART5_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART5. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config UART5_RXDMA + bool "UART5 Rx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config UART5_TXDMA + bool "UART5 Tx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_TXDMA + ---help--- + In high data rate usage, Tx DMA may reduce CPU load + +endif # AT32_UART5_SERIALDRIVER + +choice + prompt "USART6 Driver Configuration" + default AT32_USART6_SERIALDRIVER + depends on AT32_USART6 + +config AT32_USART6_SERIALDRIVER + bool "Standard serial driver" + select USART6_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + select AT32_SERIALDRIVER + +config AT32_USART6_1WIREDRIVER + bool "1-Wire driver" + select AT32_1WIREDRIVER + +config AT32_USART6_HCIUART + bool "Bluetooth HCI-UART" + select AT32_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # USART6 Driver Configuration + +if AT32_USART6_SERIALDRIVER + +config USART6_RS485 + bool "RS-485 on USART6" + default n + ---help--- + Enable RS-485 interface on USART6. Your board config will have to + provide GPIO_USART6_RS485_DIR pin definition. Currently it cannot be + used with USART6_RXDMA. + +config USART6_RS485_DIR_POLARITY + int "USART6 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART6_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART6. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config USART6_RXDMA + bool "USART6 Rx DMA" + default n + depends on AT32_DMA2 + select AT32_USART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config USART6_TXDMA + bool "USART6 Tx DMA" + default n + depends on AT32_DMA2 + select AT32_USART_TXDMA + ---help--- + In high data rate usage, Tx DMA may reduce CPU load + +endif # AT32_USART6_SERIALDRIVER + +if AT32_USART6_HCIUART + +config AT32_HCIUART6_RXBUFSIZE + int "HCI UART6 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config AT32_HCIUART6_TXBUFSIZE + int "HCI UART6 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config AT32_HCIUART6_BAUD + int "HCI UART6 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCIR USART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +config AT32_HCIUART6_RXDMA + bool "HCI UART6 Rx DMA" + default n + depends on AT32_DMA1 + select AT32_HCIUART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +endif # AT32_USART6_HCIUART + +choice + prompt "UART7 Driver Configuration" + default AT32_UART7_SERIALDRIVER + depends on AT32_UART7 + +config AT32_UART7_SERIALDRIVER + bool "Standard serial driver" + select UART7_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + select AT32_SERIALDRIVER + +config AT32_UART7_1WIREDRIVER + bool "1-Wire driver" + select AT32_1WIREDRIVER + +config AT32_UART7_HCIUART + bool "Bluetooth HCI-UART" + select AT32_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # UART7 Driver Configuration + +if AT32_UART7_SERIALDRIVER + +config UART7_RS485 + bool "RS-485 on UART7" + default n + ---help--- + Enable RS-485 interface on UART7. Your board config will have to + provide GPIO_UART7_RS485_DIR pin definition. Currently it cannot be + used with UART7_RXDMA. + +config UART7_RS485_DIR_POLARITY + int "UART7 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART7_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART7. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config UART7_RXDMA + bool "UART7 Rx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config UART7_TXDMA + bool "UART7 Tx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_TXDMA + ---help--- + In high data rate usage, Tx DMA may reduce CPU load + +endif # AT32_UART7_SERIALDRIVER + +if AT32_UART7_HCIUART + +config AT32_HCIUART7_RXBUFSIZE + int "HCI UART7 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config AT32_HCIUART7_TXBUFSIZE + int "HCI UART7 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config AT32_HCIUART7_BAUD + int "HCI UART7 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCIR USART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +config AT32_HCIUART7_RXDMA + bool "HCI UART7 Rx DMA" + default n + depends on AT32_DMA2 + select AT32_HCIUART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +endif # AT32_UART7_HCIUART + +choice + prompt "UART8 Driver Configuration" + default AT32_UART8_SERIALDRIVER + depends on AT32_UART8 + +config AT32_UART8_SERIALDRIVER + bool "Standard serial driver" + select UART8_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + select AT32_SERIALDRIVER + +config AT32_UART8_1WIREDRIVER + bool "1-Wire driver" + select AT32_1WIREDRIVER + +config AT32_UART8_HCIUART + bool "Bluetooth HCI-UART" + select AT32_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # UART8 Driver Configuration + +if AT32_UART8_SERIALDRIVER + +config UART8_RS485 + bool "RS-485 on UART8" + default n + ---help--- + Enable RS-485 interface on UART8. Your board config will have to + provide GPIO_UART8_RS485_DIR pin definition. Currently it cannot be + used with UART8_RXDMA. + +config UART8_RS485_DIR_POLARITY + int "UART8 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART8_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART8. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config UART8_RXDMA + bool "UART8 Rx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config UART8_TXDMA + bool "UART8 Tx DMA" + default n + depends on AT32_DMA1 + select AT32_USART_TXDMA + ---help--- + In high data rate usage, Tx DMA may reduce CPU load + +endif # AT32_UART8_SERIALDRIVER + +if AT32_UART8_HCIUART + +config AT32_HCIUART8_RXBUFSIZE + int "HCI UART8 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config AT32_HCIUART8_TXBUFSIZE + int "HCI UART8 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config AT32_HCIUART8_BAUD + int "HCI UART8 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCIR USART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +config AT32_HCIUART8_RXDMA + bool "HCI UART8 Rx DMA" + default n + depends on AT32_DMA2 + select AT32_HCIUART_RXDMA + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +endif # AT32_UART8_HCIUART + +menu "Serial Driver Configuration" + depends on AT32_SERIALDRIVER + +config AT32_SERIAL_RXDMA_BUFFER_SIZE + int "Rx DMA buffer size" + default 32 + range 32 4096 + depends on AT32_USART_RXDMA + ---help--- + The DMA buffer size when using RX DMA to emulate a FIFO. + + When streaming data, the generic serial layer will be called + every time the FIFO receives half or this number of bytes. + + Value given here will be rounded up to next multiple of 4 bytes. + +config AT32_SERIAL_DISABLE_REORDERING + bool "Disable reordering of ttySx devices." + default n + ---help--- + NuttX per default reorders the serial ports (/dev/ttySx) so that the + console is always on /dev/ttyS0. If more than one UART is in use this + can, however, have the side-effect that all port mappings + (hardware USART1 -> /dev/ttyS0) change if the console is moved to another + UART. This is in particular relevant if a project uses the USB console + in some boards and a serial console in other boards, but does not + want the side effect of having all serial port names change when just + the console is moved from serial to USB. + +config AT32_FLOWCONTROL_BROKEN + bool "Use Software UART RTS flow control" + default n + ---help--- + Enable UART RTS flow control using Software. Because Artery + Current AT32 have broken HW based RTS behavior (they assert + nRTS after every byte received) Enable this setting workaround + this issue by using software based management of RTS + +config AT32_USART_BREAKS + bool "Add TIOxSBRK to support sending Breaks" + default n + ---help--- + Add TIOCxBRK routines to send a line break per the AT32 manual, the + break will be a pulse based on the value M. This is not a BSD compatible + break. + +config AT32_SERIALBRK_BSDCOMPAT + bool "Use GPIO To send Break" + depends on AT32_USART_BREAKS + default n + ---help--- + Enable using GPIO on the TX pin to send a BSD compatible break: + TIOCSBRK will start the break and TIOCCBRK will end the break. + The current AT32 U[S]ARTS have no way to leave the break on + (TX=LOW) because software starts the break and then the hardware + automatically clears the break. This makes it difficult to send + a long break. + +config AT32_USART_SINGLEWIRE + bool "Single Wire Support" + default n + depends on AT32_USART + ---help--- + Enable single wire UART support. The option enables support for the + TIOCSSINGLEWIRE ioctl in the AT32 serial driver. + +endmenu # Serial Driver Configuration + +menu "HCI UART Driver Configuration" + depends on AT32_SERIALDRIVER + +config AT32_HCIUART_RXDMA_BUFSIZE + int "Rx DMA buffer size" + default 32 + range 32 4096 + depends on AT32_HCIUART_RXDMA + ---help--- + The DMA buffer size when using RX DMA to emulate a FIFO. + + When streaming data, the generic serial layer will be called + every time the FIFO receives half or this number of bytes. + + Value given here will be rounded up to next multiple of 4 bytes. + +config AT32_HCIUART_RXDMAPRIO + hex "HCI UART DMA priority" + default 0x00001000 + depends on AT32_HCIUART_RXDMA + ---help--- + Select HCI UART DMA priority. + + +config AT32_HCIUART_SW_RXFLOW + bool "Use Software UART RTS flow control" + default n + ---help--- + Enable UART RTS flow control using Software. Current AT32 have + broken HW based RTS behavior (they assert nRTS after every byte + received) Enable this setting workaround this issue by using + software based management of RTS + + If HCI UART DMA is enabled, this is probably the better selection + as well. In that case, the Rx DMA buffer will avoid Rx overrun due + to short, bursty activity. Software RTS management will probably + result in overall better throughput and should still avoid Rx data + overrun conditions. + +config AT32_HCIUART_UPPER_WATERMARK + int "RTS flow control upper watermark (%)" + default 75 + range 2 100 + depends on AT32_HCIUART_SW_RXFLOW + ---help--- + If software RTS flow control is enable, then RTS will be asserted + when this amount of Rx data has been buffered. The amount is + expressed as a percentage of the Rx buffer size. + +config AT32_HCIUART_LOWER_WATERMARK + int "RTS flow control lower watermark (%)" + default 25 + range 1 99 + depends on AT32_HCIUART_SW_RXFLOW + ---help--- + If software RTS flow control is enable, then RTS will be de-asserted + when there is less than this amount ofdata in the Rx buffere. The + amount is expressed as a percentage of the Rx buffer size. + +endmenu # HCI UART Driver Configuration + +if PM + +config AT32_PM_SERIAL_ACTIVITY + int "PM serial activity" + default 10 + ---help--- + PM activity reported to power management logic on every serial + interrupt. + +endif + +endmenu # U[S]ART Configuration + +menu "SPI Configuration" + depends on AT32_SPI + +config AT32_SPI_INTERRUPTS + bool "Interrupt driver SPI" + default n + ---help--- + Select to enable interrupt driven SPI support. Non-interrupt-driven, + poll-waiting is recommended if the interrupt rate would be to high in + the interrupt driven case. + +config AT32_SPI1_DMA + bool "SPI1 DMA" + default n + depends on AT32_SPI1 && !AT32_SPI_INTERRUPT + select AT32_SPI_DMA + ---help--- + Use DMA to improve SPI1 transfer performance. Cannot be used with AT32_SPI_INTERRUPT. + +config AT32_SPI1_DMA_BUFFER + int "SPI1 DMA buffer size" + default 0 + depends on AT32_SPI1_DMA + ---help--- + Add a properly aligned DMA buffer for RX and TX DMA for SPI1. + +config AT32_SPI_DMATHRESHOLD + int "SPI DMA threshold" + default 4 + depends on AT32_SPI_DMA + ---help--- + When SPI DMA is enabled, small DMA transfers will still be performed + by polling logic. But we need a threshold value to determine what + is small. + +config AT32_SPI2_DMA + bool "SPI2 DMA" + default n + depends on AT32_SPI2 && !AT32_SPI_INTERRUPT + select AT32_SPI_DMA + ---help--- + Use DMA to improve SPI2 transfer performance. Cannot be used with AT32_SPI_INTERRUPT. + +config AT32_SPI2_DMA_BUFFER + int "SPI2 DMA buffer size" + default 0 + depends on AT32_SPI2_DMA + ---help--- + Add a properly aligned DMA buffer for RX and TX DMA for SPI2. + +config AT32_SPI3_DMA + bool "SPI3 DMA" + default n + depends on AT32_SPI3 && !AT32_SPI_INTERRUPT + select AT32_SPI_DMA + ---help--- + Use DMA to improve SPI3 transfer performance. Cannot be used with AT32_SPI_INTERRUPT. + +config AT32_SPI3_DMA_BUFFER + int "SPI3 DMA buffer size" + default 0 + depends on AT32_SPI3_DMA + ---help--- + Add a properly aligned DMA buffer for RX and TX DMA for SPI3. + +config AT32_SPI4_DMA + bool "SPI4 DMA" + default n + depends on AT32_SPI4 && !AT32_SPI_INTERRUPT + select AT32_SPI_DMA + ---help--- + Use DMA to improve SPI4 transfer performance. Cannot be used with AT32_SPI_INTERRUPT. + +config AT32_SPI4_DMA_BUFFER + int "SPI4 DMA buffer size" + default 0 + depends on AT32_SPI4_DMA + ---help--- + Add a properly aligned DMA buffer for RX and TX DMA for SPI4. + +endmenu # SPI Configuration + + +menu "I2C Configuration" + depends on AT32_I2C + +config AT32_I2C_DYNTIMEO + bool "Use dynamic timeouts" + default n + depends on AT32_I2C + +config AT32_I2C_DYNTIMEO_USECPERBYTE + int "Timeout Microseconds per Byte" + default 500 + depends on AT32_I2C_DYNTIMEO + +config AT32_I2C_DYNTIMEO_STARTSTOP + int "Timeout for Start/Stop (Milliseconds)" + default 1000 + depends on AT32_I2C_DYNTIMEO + +config AT32_I2CTIMEOSEC + int "Timeout seconds" + default 0 + depends on AT32_I2C + +config AT32_I2CTIMEOMS + int "Timeout Milliseconds" + default 500 + depends on AT32_I2C && !AT32_I2C_DYNTIMEO + +config AT32_I2CTIMEOTICKS + int "Timeout for Done and Stop (ticks)" + default 500 + depends on AT32_I2C && !AT32_I2C_DYNTIMEO + +config AT32_I2C_DUTY16_9 + bool "Frequency with Tlow/Thigh = 16/9" + default n + depends on AT32_I2C + +config AT32_I2C_DMA + bool "I2C DMA Support" + default n + depends on AT32_I2C && AT32_AT32F43XX && (AT32_DMA1 || AT32_DMA2) && !I2C_POLLED + ---help--- + This option enables the DMA for I2C transfers. + Note: The user can define CONFIG_I2C_DMAPRIO: a custom priority value for the + I2C dma streams, else the default priority level is set to medium. + +endmenu + +menu "SDIO Configuration" + depends on (AT32_SDIO || AT32_SDIO2) + +config AT32_SDIO_CARD + bool "SDIO Card support" + default n + ---help--- + Build in additional support needed only for SDIO cards (vs. SD + memory cards) + +config AT32_SDIO_PULLUP + bool "Enable internal Pull-Ups" + default n + ---help--- + If you are using an external SDCard module that does not have the + pull-up resistors for the SDIO interface (like the Gadgeteer SD Card + Module) then enable this option to activate the internal pull-up + resistors. + +config AT32_SDIO_DMA + bool "Support DMA data transfers" + default y if AT32_DMA2 + default n if !AT32_DMA2 + select SDIO_DMA + depends on AT32_DMA2 + ---help--- + Support DMA data transfers. Requires AT32_SDIO and config AT32_DMA2. + +config AT32_SDIO_DMAPRIO + hex "SDIO DMA priority" + default 0x00001000 + ---help--- + Select SDIO DMA priority. + + For AT32 , options are: 0x00000000 low, 0x00001000 medium, + 0x00002000 high, 0x00003000 very high. Default: medium. + + +config AT32_SDIO_WIDTH_D1_ONLY + bool "Use D1 only" + default n + ---help--- + Select 1-bit transfer mode. Default: 4-bit transfer mode. + +endmenu + + +config AT32_HAVE_RTC_COUNTER + bool + default n + +config AT32_HAVE_RTC_SUBSECONDS + bool + select ARCH_HAVE_RTC_SUBSECONDS + default n + +menu "RTC Configuration" + depends on AT32_RTC + +config AT32_RTC_MAGIC_REG + int "BKP register" + default 0 + range 0 19 + depends on !AT32_HAVE_RTC_COUNTER + ---help--- + The BKP register used to store/check the Magic value to determine if + RTC is already setup + +config AT32_RTC_MAGIC + hex "RTC Magic 1" + default 0xfacefeed + depends on !AT32_HAVE_RTC_COUNTER + ---help--- + Value used as Magic to determine if the RTC is already setup + +config AT32_RTC_MAGIC_TIME_SET + hex "RTC Magic 2" + default 0xf00dface + depends on !AT32_HAVE_RTC_COUNTER + ---help--- + Value used as Magic to determine if the RTC has been setup and has + time set + +choice + prompt "RTC clock source" + default AT32_RTC_LSECLOCK + +config AT32_RTC_LSECLOCK + bool "LSE clock" + ---help--- + Drive the RTC with the LSE clock + +config AT32_RTC_LSICLOCK + bool "LSI clock" + ---help--- + Drive the RTC with the LSI clock + +config AT32_RTC_HSECLOCK + bool "HSE clock" + ---help--- + Drive the RTC with the HSE clock, divided down to 1MHz. + +endchoice # RTC clock source +endmenu # RTC configuration + +menu "Ethernet MAC configuration" + depends on AT32_ETHMAC + +config AT32_PHYADDR + int "PHY address" + default 1 + ---help--- + The 5-bit address of the PHY on the board. Default: 1 + +config AT32_PHYINIT + bool "Board-specific PHY Initialization" + default n + ---help--- + Some boards require specialized initialization of the PHY before it can be used. + This may include such things as configuring GPIOs, resetting the PHY, etc. If + AT32_PHYINIT is defined in the configuration then the board specific logic must + provide at32_phyinitialize(); The AT32 Ethernet driver will call this function + one time before it first uses the PHY. + +config AT32_MII + bool "Use MII interface" + default n + ---help--- + Support Ethernet MII interface. + +choice + prompt "MII clock configuration" + default AT32_MII_MCO1 if AT32_AT32F43XX + depends on AT32_MII + +config AT32_MII_MCO1 + bool "Use MC01 as MII clock" + depends on AT32_AT32F43XX + ---help--- + Use MCO1 to clock the MII interface. Default: Use MC01 + +config AT32_MII_MCO2 + bool "Use MC02 as MII clock" + depends on AT32_AT32F43XX + ---help--- + Use MCO2 to clock the MII interface. Default: Use MC01 + +config AT32_MII_EXTCLK + bool "External MII clock" + ---help--- + Clocking is provided by external logic. Don't use MCO for MII + clock. Default: Use MC0[1] + +endchoice + +config AT32_AUTONEG + bool "Use autonegotiation" + default y + ---help--- + Use PHY autonegotiation to determine speed and mode + +config AT32_ETHFD + bool "Full duplex" + default n + depends on !AT32_AUTONEG + ---help--- + If AT32_AUTONEG is not defined, then this may be defined to select full duplex + mode. Default: half-duplex + +config AT32_ETH100MBPS + bool "100 Mbps" + default n + depends on !AT32_AUTONEG + ---help--- + If AT32_AUTONEG is not defined, then this may be defined to select 100 MBps + speed. Default: 10 Mbps + +config AT32_PHYSR + int "PHY Status Register Address (decimal)" + depends on AT32_AUTONEG + ---help--- + This must be provided if AT32_AUTONEG is defined. The PHY status register + address may diff from PHY to PHY. This configuration sets the address of + the PHY status register. + +config AT32_PHYSR_ALTCONFIG + bool "PHY Status Alternate Bit Layout" + default n + depends on AT32_AUTONEG + ---help--- + Different PHYs present speed and mode information in different ways. Some + will present separate information for speed and mode (this is the default). + Those PHYs, for example, may provide a 10/100 Mbps indication and a separate + full/half duplex indication. This options selects an alternative representation + where speed and mode information are combined. This might mean, for example, + separate bits for 10HD, 100HD, 10FD and 100FD. + +config AT32_PHYSR_SPEED + hex "PHY Speed Mask" + depends on AT32_AUTONEG && !AT32_PHYSR_ALTCONFIG + ---help--- + This must be provided if AT32_AUTONEG is defined. This provides bit mask + for isolating the 10 or 100MBps speed indication. + +config AT32_PHYSR_100MBPS + hex "PHY 100Mbps Speed Value" + depends on AT32_AUTONEG && !AT32_PHYSR_ALTCONFIG + ---help--- + This must be provided if AT32_AUTONEG is defined. This provides the value + of the speed bit(s) indicating 100MBps speed. + +config AT32_PHYSR_MODE + hex "PHY Mode Mask" + depends on AT32_AUTONEG && !AT32_PHYSR_ALTCONFIG + ---help--- + This must be provided if AT32_AUTONEG is defined. This provide bit mask + for isolating the full or half duplex mode bits. + +config AT32_PHYSR_FULLDUPLEX + hex "PHY Full Duplex Mode Value" + depends on AT32_AUTONEG && !AT32_PHYSR_ALTCONFIG + ---help--- + This must be provided if AT32_AUTONEG is defined. This provides the + value of the mode bits indicating full duplex mode. + +config AT32_PHYSR_ALTMODE + hex "PHY Mode Mask" + depends on AT32_AUTONEG && AT32_PHYSR_ALTCONFIG + ---help--- + This must be provided if AT32_AUTONEG is defined. This provide bit mask + for isolating the speed and full/half duplex mode bits. + +config AT32_PHYSR_10HD + hex "10MBase-T Half Duplex Value" + depends on AT32_AUTONEG && AT32_PHYSR_ALTCONFIG + ---help--- + This must be provided if AT32_AUTONEG is defined. This is the value + under the bit mask that represents the 10Mbps, half duplex setting. + +config AT32_PHYSR_100HD + hex "100Base-T Half Duplex Value" + depends on AT32_AUTONEG && AT32_PHYSR_ALTCONFIG + ---help--- + This must be provided if AT32_AUTONEG is defined. This is the value + under the bit mask that represents the 100Mbps, half duplex setting. + +config AT32_PHYSR_10FD + hex "10Base-T Full Duplex Value" + depends on AT32_AUTONEG && AT32_PHYSR_ALTCONFIG + ---help--- + This must be provided if AT32_AUTONEG is defined. This is the value + under the bit mask that represents the 10Mbps, full duplex setting. + +config AT32_PHYSR_100FD + hex "100Base-T Full Duplex Value" + depends on AT32_AUTONEG && AT32_PHYSR_ALTCONFIG + ---help--- + This must be provided if AT32_AUTONEG is defined. This is the value + under the bit mask that represents the 100Mbps, full duplex setting. + +config AT32_ETH_PTP + bool "Precision Time Protocol (PTP)" + default n + ---help--- + Precision Time Protocol (PTP). Not supported but some hooks are indicated + with this condition. + +config AT32_RMII + bool + default y if !AT32_MII + +choice + prompt "RMII clock configuration" + default AT32_RMII_MCO1 if AT32_AT32F43XX + depends on AT32_RMII + +config AT32_RMII_MCO1 + bool "Use MC01 as RMII clock" + depends on AT32_AT32F43XX + ---help--- + Use MCO1 to clock the RMII interface. Default: Use MC01 + +config AT32_RMII_MCO2 + bool "Use MC02 as RMII clock" + depends on AT32_AT32F43XX + ---help--- + Use MCO2 to clock the RMII interface. Default: Use MC01 + +config AT32_RMII_EXTCLK + bool "External RMII clock" + ---help--- + Clocking is provided by external logic. Don't use MCO for RMII + clock. Default: Use MC0[1] + +endchoice + +config AT32_ETHMAC_REGDEBUG + bool "Register-Level Debug" + default n + depends on DEBUG_NET_INFO + ---help--- + Enable very low-level register access debug. Depends on CONFIG_DEBUG_FEATURES. + +endmenu # Ethernet MAC configuration + +config AT32_USBHOST + bool "Enable USB Host Support" + depends on AT32_OTGFS || AT32_OTGFS2 + default n + select USBHOST + +menu "USB FS Host Configuration" + depends on AT32_OTGFS && AT32_USBHOST + +config AT32_OTGFS_RXFIFO_SIZE + int "Rx Packet Size" + default 128 + ---help--- + Size of the RX FIFO in 32-bit words. Default 128 (512 bytes) + +config AT32_OTGFS_NPTXFIFO_SIZE + int "Non-periodic Tx FIFO Size" + default 96 + ---help--- + Size of the non-periodic Tx FIFO in 32-bit words. Default 96 (384 bytes) + +config AT32_OTGFS_PTXFIFO_SIZE + int "Periodic Tx FIFO size" + default 128 + ---help--- + Size of the periodic Tx FIFO in 32-bit words. Default 96 (384 bytes) + +config AT32_OTGFS_DESCSIZE + int "Descriptor Size" + default 128 + ---help--- + Maximum size to allocate for descriptor memory descriptor. Default: 128 + +config AT32_OTGFS_SOFINTR + bool "Enable SOF interrupts" + default n + ---help--- + Enable SOF interrupts. Why would you ever want to do that? + +config AT32_OTGFS_VBUS_CONTROL + bool "Enable VBus Control" + default y + ---help--- + Enable VBus control. Used when the board has VBus sensing and + a power switch for the OTG FS USB port. Disable this config + if the board lacks this USB VBus control circuitry. + +endmenu + +menu "USB FS2 Host Configuration" + depends on AT32_OTGFS2 && AT32_USBHOST + +config AT32_OTGFS2_RXFIFO_SIZE + int "Rx Packet Size" + default 128 + ---help--- + Size of the RX FIFO in 32-bit words. Default 128 (512 bytes) + +config AT32_OTGFS2_NPTXFIFO_SIZE + int "Non-periodic Tx FIFO Size" + default 96 + ---help--- + Size of the non-periodic Tx FIFO in 32-bit words. Default 96 (384 bytes) + +config AT32_OTGFS2_PTXFIFO_SIZE + int "Periodic Tx FIFO size" + default 128 + ---help--- + Size of the periodic Tx FIFO in 32-bit words. Default 96 (384 bytes) + +config AT32_OTGFS2_DESCSIZE + int "Descriptor Size" + default 128 + ---help--- + Maximum size to allocate for descriptor memory descriptor. Default: 128 + +config AT32_OTGFS2_SOFINTR + bool "Enable SOF interrupts" + default n + ---help--- + Enable SOF interrupts. Why would you ever want to do that? + +config AT32_OTGFS2_VBUS_CONTROL + bool "Enable VBus Control" + default y + ---help--- + Enable VBus control. Used when the board has VBus sensing and + a power switch for the OTG FS2 USB port. Disable this config + if the board lacks this USB VBus control circuitry. + +endmenu + +menu "USB Host Debug Configuration" + depends on AT32_USBHOST + +config AT32_USBHOST_REGDEBUG + bool "Register-Level Debug" + default n + depends on AT32_USBHOST && DEBUG_USB_INFO + ---help--- + Enable very low-level register access debug. + +config AT32_USBHOST_PKTDUMP + bool "Packet Dump Debug" + default n + depends on AT32_USBHOST && DEBUG_USB_INFO + ---help--- + Dump all incoming and outgoing USB packets. + +endmenu + +comment "USB Device Configuration" + +menu "USB Full Speed Debug Configuration" + depends on AT32_USBFS + +config AT32_USBFS_REGDEBUG + bool "Register-Level Debug" + default n + depends on AT32_USBFS && DEBUG_USB_INFO + ---help--- + Enable very low-level register access debug. + +endmenu + +menu "OTG Configuration" + depends on (AT32_OTGFS || AT32_OTGFS2) + +config OTG_ID_GPIO_DISABLE + bool "Disable the use of GPIO_OTG_ID pin." + default n + ---help--- + Disables/Enables the use of GPIO_OTG_ID pin. This allows non OTG use + cases to reuse this GPIO pin and ensure it is not set incorrectlty + during OS boot. + +endmenu + + +menu "CAN driver configuration" + depends on AT32_CAN + +choice + prompt "CAN character driver or SocketCAN support" + default AT32_CAN_CHARDRIVER + +config AT32_CAN_CHARDRIVER + bool "AT32 CAN character driver support" + select ARCH_HAVE_CAN_ERRORS + select CAN + +config AT32_CAN_SOCKET + bool "AT32 CAN SocketCAN support" + select NET_CAN_HAVE_ERRORS + +endchoice # CAN character driver or SocketCAN support + +config AT32_CAN1_BAUD + int "CAN1 BAUD" + default 250000 + depends on AT32_CAN1 + ---help--- + CAN1 BAUD rate. Required if CONFIG_AT32_CAN1 is defined. + +config AT32_CAN2_BAUD + int "CAN2 BAUD" + default 250000 + depends on AT32_CAN2 + ---help--- + CAN2 BAUD rate. Required if CONFIG_AT32_CAN2 is defined. + +config AT32_CAN_TSEG1 + int "TSEG1 quanta" + default 13 + ---help--- + The number of CAN time quanta in segment 1. Default: 13 + +config AT32_CAN_TSEG2 + int "TSEG2 quanta" + default 2 + ---help--- + The number of CAN time quanta in segment 2. Default: 2 + +config AT32_CAN_REGDEBUG + bool "CAN Register level debug" + depends on DEBUG_CAN_INFO + default n + ---help--- + Output detailed register-level CAN device debug information. + Requires also CONFIG_DEBUG_CAN_INFO. + +endmenu # "CAN driver configuration" + + +menu "AT32 QEncoder Driver" + depends on SENSORS_QENCODER + depends on AT32_TIM1 || AT32_TIM2 || AT32_TIM3 || AT32_TIM4 || AT32_TIM5 || AT32_TIM8 + +config AT32_QENCODER_DISABLE_EXTEND16BTIMERS + bool "Disable QEncoder timers extension from 16-bit to 32-bit" + default n + +config AT32_QENCODER_INDEX_PIN + bool "Enable QEncoder timers support for index pin" + default n + +config AT32_TIM1_QE + bool "TIM1 QE" + default n + depends on AT32_TIM1 + ---help--- + Reserve TIM1 for use by QEncoder. + +if AT32_TIM1_QE + +config AT32_TIM1_QEPSC + int "TIM1 QE pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config AT32_TIM2_QE + bool "TIM2 QE" + default n + depends on AT32_TIM2 + ---help--- + Reserve TIM2 for use by QEncoder. + +if AT32_TIM2_QE + +config AT32_TIM2_QEPSC + int "TIM2 QE pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config AT32_TIM3_QE + bool "TIM3 QE" + default n + depends on AT32_TIM3 + ---help--- + Reserve TIM3 for use by QEncoder. + +if AT32_TIM3_QE + +config AT32_TIM3_QEPSC + int "TIM3 QE pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config AT32_TIM4_QE + bool "TIM4 QE" + default n + depends on AT32_TIM4 + ---help--- + Reserve TIM4 for use by QEncoder. + +if AT32_TIM4_QE + +config AT32_TIM4_QEPSC + int "TIM4 QE pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config AT32_TIM5_QE + bool "TIM5 QE" + default n + depends on AT32_TIM5 + ---help--- + Reserve TIM5 for use by QEncoder. + +if AT32_TIM5_QE + +config AT32_TIM5_QEPSC + int "TIM5 QE pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config AT32_TIM8_QE + bool "TIM8 QE" + default n + depends on AT32_TIM8 + ---help--- + Reserve TIM8 for use by QEncoder. + +if AT32_TIM8_QE + +config AT32_TIM8_QEPSC + int "TIM8 QE pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config AT32_QENCODER_FILTER + bool "Enable filtering on AT32 QEncoder input" + default y + +choice + depends on AT32_QENCODER_FILTER + prompt "Input channel sampling frequency" + default AT32_QENCODER_SAMPLE_FDTS_4 + +config AT32_QENCODER_SAMPLE_FDTS + bool "fDTS" + +config AT32_QENCODER_SAMPLE_CKINT + bool "fCK_INT" + +config AT32_QENCODER_SAMPLE_FDTS_2 + bool "fDTS/2" + +config AT32_QENCODER_SAMPLE_FDTS_4 + bool "fDTS/4" + +config AT32_QENCODER_SAMPLE_FDTS_8 + bool "fDTS/8" + +config AT32_QENCODER_SAMPLE_FDTS_16 + bool "fDTS/16" + +config AT32_QENCODER_SAMPLE_FDTS_32 + bool "fDTS/32" + +endchoice + +choice + depends on AT32_QENCODER_FILTER + prompt "Input channel event count" + default AT32_QENCODER_SAMPLE_EVENT_6 + +config AT32_QENCODER_SAMPLE_EVENT_1 + depends on AT32_QENCODER_SAMPLE_FDTS + bool "1" + +config AT32_QENCODER_SAMPLE_EVENT_2 + depends on AT32_QENCODER_SAMPLE_CKINT + bool "2" + +config AT32_QENCODER_SAMPLE_EVENT_4 + depends on AT32_QENCODER_SAMPLE_CKINT + bool "4" + +config AT32_QENCODER_SAMPLE_EVENT_5 + depends on AT32_QENCODER_SAMPLE_FDTS_16 || AT32_QENCODER_SAMPLE_FDTS_32 + bool "5" + +config AT32_QENCODER_SAMPLE_EVENT_6 + depends on !AT32_QENCODER_SAMPLE_FDTS && !AT32_QENCODER_SAMPLE_CKINT + bool "6" + +config AT32_QENCODER_SAMPLE_EVENT_8 + depends on !AT32_QENCODER_SAMPLE_FDTS + bool "8" + +endchoice + +endmenu + diff --git a/arch/arm/src/at32/Make.defs b/arch/arm/src/at32/Make.defs new file mode 100644 index 0000000000..9d24ca0a83 --- /dev/null +++ b/arch/arm/src/at32/Make.defs @@ -0,0 +1,181 @@ +############################################################################ +# arch/arm/src/at32/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include armv7-m/Make.defs + +CHIP_CSRCS = at32_allocateheap.c at32_start.c at32_rcc.c at32_lse.c +CHIP_CSRCS += at32_lsi.c at32_gpio.c at32_exti_gpio.c at32_flash.c +CHIP_CSRCS += at32_irq.c at32_lowputc.c +CHIP_CSRCS += at32_waste.c at32_uid.c +CHIP_CSRCS += at32_serial.c + +ifeq ($(CONFIG_AT32_TIM),y) +CHIP_CSRCS += at32_tim.c +endif + +ifeq ($(CONFIG_AT32_SDIO),y) +CHIP_CSRCS += at32_sdio.c +endif + +ifeq ($(CONFIG_AT32_SPI),y) +CHIP_CSRCS += at32_spi.c +endif + +ifeq ($(CONFIG_AT32_DMA),y) +CHIP_CSRCS += at32_dma.c +endif + +ifeq ($(CONFIG_TIMER),y) +CHIP_CSRCS += at32_tim_lowerhalf.c +endif + +ifdef CONFIG_AT32_TICKLESS_TIMER +CHIP_CSRCS += at32_tickless.c +else +CHIP_CSRCS += at32_timerisr.c +endif + +ifeq ($(CONFIG_AT32_ONESHOT),y) +CHIP_CSRCS += at32_oneshot.c at32_oneshot_lowerhalf.c +endif + +ifeq ($(CONFIG_AT32_FREERUN),y) +CHIP_CSRCS += at32_freerun.c +endif + +ifeq ($(CONFIG_BUILD_PROTECTED),y) +CHIP_CSRCS += at32_userspace.c at32_mpuinit.c +endif + +ifeq ($(CONFIG_AT32_I2C),y) +CHIP_CSRCS += at32_i2c.c +endif + +ifeq ($(CONFIG_USBDEV),y) +ifeq ($(CONFIG_AT32_USB),y) +CHIP_CSRCS += at32_usbdev.c +endif +ifeq ($(CONFIG_AT32_USBFS),y) +CHIP_CSRCS += at32_usbfs.c +endif +ifeq ($(CONFIG_AT32_OTGFS),y) +CHIP_CSRCS += at32_otgfsdev.c +endif +endif + +ifeq ($(CONFIG_AT32_USBHOST),y) +ifeq ($(CONFIG_AT32_OTGFS),y) +CHIP_CSRCS += at32_otgfshost.c +endif +ifeq ($(CONFIG_USBHOST_TRACE),y) +CHIP_CSRCS += at32_usbhost.c +else +ifeq ($(CONFIG_DEBUG_USB),y) +CHIP_CSRCS += at32_usbhost.c +endif +endif +endif + +ifneq ($(CONFIG_ARCH_IDLE_CUSTOM),y) +CHIP_CSRCS += at32_idle.c +endif + +CHIP_CSRCS += at32_pmstop.c at32_pmstandby.c at32_pmsleep.c + +ifneq ($(CONFIG_ARCH_CUSTOM_PMINIT),y) +CHIP_CSRCS += at32_pminitialize.c +endif + +ifeq ($(CONFIG_AT32_ETHMAC),y) +CHIP_CSRCS += at32_eth.c +endif + +ifeq ($(CONFIG_AT32_PWR),y) +CHIP_CSRCS += at32_pwr.c at32_exti_pwr.c +endif + +ifeq ($(CONFIG_AT32_RTC),y) +CHIP_CSRCS += at32_rtc.c +ifeq ($(CONFIG_RTC_ALARM),y) +CHIP_CSRCS += at32_exti_alarm.c +endif +ifeq ($(CONFIG_RTC_PERIODIC),y) +CHIP_CSRCS += at32_exti_wakeup.c +endif +ifeq ($(CONFIG_RTC_DRIVER),y) +CHIP_CSRCS += at32_rtc_lowerhalf.c +endif +endif + +ifeq ($(CONFIG_AT32_ADC),y) +CHIP_CSRCS += at32_adc.c +endif + +ifeq ($(CONFIG_AT32_DAC),y) +CHIP_CSRCS += at32_dac.c +endif + +ifeq ($(CONFIG_AT32_1WIREDRIVER),y) +CHIP_CSRCS += at32_1wire.c +endif + +ifeq ($(CONFIG_AT32_HCIUART),y) +CHIP_CSRCS += at32_hciuart.c +endif + +ifeq ($(CONFIG_AT32_PWM),y) +CHIP_CSRCS += at32_pwm.c +endif + +ifeq ($(CONFIG_AT32_CAP),y) +CHIP_CSRCS += at32_capture_lowerhalf.c +endif + + +ifeq ($(CONFIG_SENSORS_HALL3PHASE),y) +CHIP_CSRCS += at32_hall3ph.c +endif + +ifeq ($(CONFIG_AT32_CAN),y) +ifeq ($(CONFIG_AT32_CAN_CHARDRIVER),y) +CHIP_CSRCS += at32_can.c +endif +ifeq ($(CONFIG_AT32_CAN_SOCKET),y) +CHIP_CSRCS += at32_can_sock.c +endif +endif + +ifeq ($(CONFIG_AT32_IWDG),y) +CHIP_CSRCS += at32_iwdg.c +endif + +ifeq ($(CONFIG_AT32_WWDG),y) +CHIP_CSRCS += at32_wwdg.c +endif + +ifeq ($(CONFIG_DEBUG_FEATURES),y) +CHIP_CSRCS += at32_dumpgpio.c +endif + +ifeq ($(CONFIG_AT32_FOC),y) +CHIP_CSRCS += at32_foc.c +endif + + diff --git a/arch/arm/src/at32/at32.h b/arch/arm/src/at32/at32.h new file mode 100644 index 0000000000..9293581573 --- /dev/null +++ b/arch/arm/src/at32/at32.h @@ -0,0 +1,57 @@ +/**************************************************************************** + * arch/arm/src/at32/at32.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_H +#define __ARCH_ARM_SRC_AT32_AT32_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include "arm_internal.h" + +/* Peripherals **************************************************************/ + +#include "chip.h" +#include "at32_gpio.h" +#include "at32_uart.h" +#include "at32_exti.h" +#include "at32_flash.h" +#include "at32_dma.h" +#include "at32_pwr.h" +#include "at32_rcc.h" +#include "at32_lowputc.h" +#include "at32_adc.h" +#include "at32_can.h" +#include "at32_i2c.h" +#include "at32_rtc.h" +#include "at32_sdio.h" +#include "at32_spi.h" +#include "at32_tim.h" +#include "at32_eth.h" +#include "at32_wdg.h" +#include "at32_dbgmcu.h" + +#endif /* __ARCH_ARM_SRC_AT32_AT32_H */ diff --git a/arch/arm/src/at32/at32_adc.c b/arch/arm/src/at32/at32_adc.c new file mode 100644 index 0000000000..59efce00a2 --- /dev/null +++ b/arch/arm/src/at32/at32_adc.c @@ -0,0 +1,4433 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_adc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32_rcc.h" +#include "at32_tim.h" +#include "at32_dma.h" +#include "at32_adc.h" + +/* The AT32 ADC lower-half driver functionality overview: + * - one lower-half driver for all AT32 ADC IP cores, + * - general lower-half logic for the NuttX upper-half ADC driver, + * - lower-half ADC driver can be used not only with the upper-half ADC + * driver, but also in the lower-half logic for special-case custom + * drivers (eg. power-control, custom sensors), + * - ADC can be used in time-critical operations (eg. control loop for + * converters or motor drivers) therefore it is necessary to support the + * high performance, zero latency ADC interrupts, + * - ADC triggering from different sources (EXTSEL and JEXTSEL), + * - regular sequence conversion (supported in upper-half ADC driver) + * - injected sequence conversion (not supported in upper-half ADC driver) + */ + +/* AT32 ADC "lower-half" support must be enabled */ + +#ifdef CONFIG_AT32_ADC + +/* This implementation is for the AT32 ADC IP version 1 and 2 */ + +#if !defined(HAVE_IP_ADC_V1) && !defined(HAVE_IP_ADC_V2) +# error "AT32 ADC IP version not specified" +#endif + +/* Supported ADC modes: + * - SW triggering with/without DMA transfer + * - TIM triggering with/without DMA transfer + * - external triggering with/without DMA transfer + * + * (tested with ADC example app from NuttX apps repo). + */ + +/* If ADC use HSI as clock-source and HSI is not used for PLL and system + * clock, then we can control it directly from ADC driver. + */ + +#if defined(HAVE_ADC_CLOCK_HSI) && \ + (AT32_CFGR_PLLSRC != 0 || AT32_SYSCLK_SW != RCC_CFGR_SW_HSI) +# define HAVE_HSI_CONTROL +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* RCC reset ****************************************************************/ + +#define AT32_RCC_RSTR AT32_CRM_APB2RST +#define RCC_RSTR_ADC123RST CRM_APB2RST_ADCRST + +/* ADC Channels/DMA *********************************************************/ + +#define ADC_DMA_CONTROL_WORD (DMA_CCR_MSIZE_16BITS | \ + DMA_CCR_PSIZE_16BITS | \ + DMA_CCR_MINC | \ + DMA_CCR_CIRC) + +/* Sample time default configuration + * + * REVISIT: simplify this, use adc_sampletime_write() function. + * REVISIT: default SMPR configurable from Kconfig + */ + +#if defined(CONFIG_AT32_AT32F43XX) + +# define ADC_SMPR_DEFAULT ADC_SMPR_92p5 + +# define ADC_SMPR1_DEFAULT ((ADC_SMPR_DEFAULT << ADC_SMPR1_SMP10_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP11_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP12_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP13_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP14_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP15_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP16_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP17_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP18_SHIFT)) +# define ADC_SMPR2_DEFAULT ((ADC_SMPR_DEFAULT << ADC_SMPR2_SMP0_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP1_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP2_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP3_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP4_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP5_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP6_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP7_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP8_SHIFT) | \ + (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP9_SHIFT)) + +#endif + +/* Number of channels per ADC: + */ + +#if defined(CONFIG_AT32_AT32F43XX) +# define ADC_CHANNELS_NUMBER 19 +#else +# error "Not supported" +#endif + +/* ADC resolution. Not supported for basic AT32 ADC IPv1 */ + +#ifndef CONFIG_AT32_HAVE_IP_ADC_V1_BASIC +# define HAVE_ADC_RESOLUTION +#else +# undef HAVE_ADC_RESOLUTION +#endif + +/* ADC have common registers for all cores except basic ADC IPv1 (F1, F37x) */ + +#ifdef CONFIG_AT32_HAVE_IP_ADC_V1_BASIC +# undef HAVE_ADC_CMN_REGS +#else +# define HAVE_ADC_CMN_REGS +#endif +#if defined(HAVE_ADC_CMN_REGS) && AT32_NADC > 1 +# define HAVE_ADC_CMN_DATA +#else +# undef HAVE_ADC_CMN_DATA +#endif + +/* Max 4 injected channels */ + +#define ADC_INJ_MAX_SAMPLES 4 + +/* ADC DMA configuration bit support */ + +#ifndef CONFIG_AT32_HAVE_IP_ADC_V1_BASIC +# define ADC_HAVE_DMACFG 1 +#else +# undef ADC_HAVE_DMACFG +#endif + +/* ADC scan mode support - only for ADCv1 */ + +#ifdef CONFIG_AT32_HAVE_IP_ADC_V1 +# define ADC_HAVE_SCAN 1 +# ifndef CONFIG_AT32_ADC1_SCAN +# define CONFIG_AT32_ADC1_SCAN 0 +# endif +# ifndef CONFIG_AT32_ADC2_SCAN +# define CONFIG_AT32_ADC2_SCAN 0 +# endif +# ifndef CONFIG_AT32_ADC3_SCAN +# define CONFIG_AT32_ADC3_SCAN 0 +# endif +#else +# undef ADC_HAVE_SCAN +#endif + +/* We have to support ADC callbacks if default ADC interrupts or + * DMA transfer are enabled + */ + +#if !defined(CONFIG_AT32_ADC_NOIRQ) || defined(ADC_HAVE_DMA) +# define ADC_HAVE_CB +#else +# undef ADC_HAVE_CB +#endif + +/* ADC software trigger configuration */ + +#define ANIOC_TRIGGER_REGULAR (1 << 0) +#define ANIOC_TRIGGER_INJECTED (1 << 1) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Data common to all ADC instances */ + +#ifdef HAVE_ADC_CMN_DATA +struct adccmn_data_s +{ + uint8_t refcount; /* How many ADC instances are currently in use */ + mutex_t lock; /* Exclusive access to common ADC data */ +}; +#endif + +/* This structure describes the state of one ADC block + * REVISIT: save some space with bit fields. + */ + +struct at32_dev_s +{ +#ifdef CONFIG_AT32_ADC_LL_OPS + const struct at32_adc_ops_s *llops; /* Low-level ADC ops */ + struct adc_dev_s *dev; /* Upper-half ADC reference */ +#endif +#ifdef ADC_HAVE_CB + const struct adc_callback_s *cb; + uint8_t irq; /* Interrupt generated by this ADC block */ +#endif +#ifdef HAVE_ADC_CMN_DATA + struct adccmn_data_s *cmn; /* Common ADC data */ +#endif + uint8_t rnchannels; /* Number of regular channels */ + uint8_t cr_channels; /* Number of configured regular channels */ +#ifdef ADC_HAVE_INJECTED + uint8_t cj_channels; /* Number of configured injected channels */ +#endif + uint8_t intf; /* ADC interface number */ + uint8_t initialized; /* ADC interface initialization counter */ + uint8_t current; /* Current ADC channel being converted */ + uint8_t anioc_trg; /* ANIOC_TRIGGER configuration */ +#ifdef HAVE_ADC_RESOLUTION + uint8_t resolution; /* ADC resolution (0-3) */ +#endif +#ifdef ADC_HAVE_DMA + uint8_t dmachan; /* DMA channel needed by this ADC */ +# ifdef ADC_HAVE_DMACFG + uint8_t dmacfg; /* DMA channel configuration, only for ADC IPv2 */ +# endif + bool hasdma; /* True: This channel supports DMA */ +#endif +#ifdef ADC_HAVE_SCAN + bool scan; /* True: Scan mode */ +#endif +#ifdef CONFIG_AT32_ADC_CHANGE_SAMPLETIME + /* Sample time selection. These bits must be written only when ADON=0. + * REVISIT: this takes too much space. We need only 3 bits per channel. + */ + + uint8_t sample_rate[ADC_CHANNELS_NUMBER]; + uint8_t adc_channels; /* ADC channels number */ +#endif +#ifdef ADC_HAVE_TIMER + uint8_t trigger; /* Timer trigger channel: 0=CC1, 1=CC2, 2=CC3, + * 3=CC4, 4=TRGO */ +#endif + xcpt_t isr; /* Interrupt handler for this ADC block */ + uint32_t base; /* Base address of registers unique to this ADC + * block */ +#ifdef ADC_HAVE_EXTCFG + uint32_t extcfg; /* External event configuration for regular group */ +#endif +#ifdef ADC_HAVE_JEXTCFG + uint32_t jextcfg; /* External event configuration for injected group */ +#endif +#ifdef ADC_HAVE_TIMER + uint32_t tbase; /* Base address of timer used by this ADC block */ + uint32_t pclck; /* The PCLK frequency that drives this timer */ + uint32_t freq; /* The desired frequency of conversions */ +#endif +#ifdef ADC_HAVE_DMA + DMA_HANDLE dma; /* Allocated DMA channel */ + + /* DMA transfer buffer */ + + uint16_t r_dmabuffer[CONFIG_AT32_ADC_MAX_SAMPLES]; +#endif + + /* List of selected ADC channels to sample */ + + uint8_t r_chanlist[CONFIG_AT32_ADC_MAX_SAMPLES]; + +#ifdef ADC_HAVE_INJECTED + /* List of selected ADC injected channels to sample */ + + uint8_t j_chanlist[ADC_INJ_MAX_SAMPLES]; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* ADC Register access */ + +#ifndef HAVE_BASIC_ADC +static void at32_modifyreg32(unsigned int addr, uint32_t clrbits, + uint32_t setbits); +#endif +static uint32_t adc_getreg(struct at32_dev_s *priv, int offset); +static void adc_putreg(struct at32_dev_s *priv, int offset, + uint32_t value); +static void adc_modifyreg(struct at32_dev_s *priv, int offset, + uint32_t clrbits, uint32_t setbits); +#ifdef HAVE_ADC_CMN_REGS +static uint32_t adccmn_base_get(struct at32_dev_s *priv); +static void adccmn_modifyreg(struct at32_dev_s *priv, uint32_t offset, + uint32_t clrbits, uint32_t setbits); +static uint32_t adccmn_getreg(struct at32_dev_s *priv, uint32_t offset); +#endif +#ifdef ADC_HAVE_TIMER +static uint16_t tim_getreg(struct at32_dev_s *priv, int offset); +static void tim_putreg(struct at32_dev_s *priv, int offset, + uint16_t value); +static void tim_modifyreg(struct at32_dev_s *priv, int offset, + uint16_t clrbits, uint16_t setbits); +static void tim_dumpregs(struct at32_dev_s *priv, const char *msg); +#endif + +static void adc_rccreset(struct at32_dev_s *priv, bool reset); + +/* ADC Interrupt Handler */ + +#ifndef CONFIG_AT32_ADC_NOIRQ +static int adc_interrupt(struct adc_dev_s *dev); +# if defined(AT32_IRQ_ADC1) && defined(CONFIG_AT32_ADC1) +static int adc1_interrupt(int irq, void *context, void *arg); +# endif +# if defined(AT32_IRQ_ADC12) && (defined(CONFIG_AT32_ADC1) || \ + defined(CONFIG_AT32_ADC2)) +static int adc12_interrupt(int irq, void *context, void *arg); +# endif +# if (defined(AT32_IRQ_ADC3) && defined(CONFIG_AT32_ADC3)) +static int adc3_interrupt(int irq, void *context, void *arg); +# endif + +# if defined(AT32_IRQ_ADC) +static int adc123_interrupt(int irq, void *context, void *arg); +# endif +#endif /* CONFIG_AT32_ADC_NOIRQ */ + +/* ADC Driver Methods */ + +static int adc_bind(struct adc_dev_s *dev, + const struct adc_callback_s *callback); +static void adc_reset(struct adc_dev_s *dev); +static int adc_setup(struct adc_dev_s *dev); +static void adc_shutdown(struct adc_dev_s *dev); +static void adc_rxint(struct adc_dev_s *dev, bool enable); +static int adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg); +static void adc_enable(struct at32_dev_s *priv, bool enable); + +static uint32_t adc_sqrbits(struct at32_dev_s *priv, int first, + int last, int offset); +static int adc_set_ch(struct adc_dev_s *dev, uint8_t ch); + +static int adc_ioc_change_ints(struct adc_dev_s *dev, int cmd, + bool arg); + +#ifdef HAVE_ADC_RESOLUTION +static int adc_resolution_set(struct adc_dev_s *dev, uint8_t res); +#endif +#ifdef HAVE_ADC_VBAT +static void adc_enable_vbat_channel(struct adc_dev_s *dev, bool enable); +#endif +#ifdef HAVE_ADC_POWERDOWN +static int adc_ioc_change_sleep_between_opers(struct adc_dev_s *dev, + int cmd, bool arg); +static void adc_power_down_idle(struct at32_dev_s *priv, + bool pdi_high); +static void adc_power_down_delay(struct at32_dev_s *priv, + bool pdd_high); +#endif + +#ifdef HAVE_HSI_CONTROL +static void adc_enable_hsi(bool enable); +static void adc_reset_hsi_disable(struct adc_dev_s *dev); +#endif + +#ifdef ADC_HAVE_TIMER +static void adc_timstart(struct at32_dev_s *priv, bool enable); +static int adc_timinit(struct at32_dev_s *priv); +#endif + +#if defined(ADC_HAVE_DMA) && !defined(CONFIG_AT32_ADC_NOIRQ) +static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t isr, + void *arg); +#endif + +static void adc_reg_startconv(struct at32_dev_s *priv, bool enable); +#ifdef ADC_HAVE_INJECTED +static void adc_inj_startconv(struct at32_dev_s *priv, bool enable); +static int adc_inj_set_ch(struct adc_dev_s *dev, uint8_t ch); +#endif + +#ifdef ADC_HAVE_EXTCFG +static int adc_extcfg_set(struct at32_dev_s *priv, uint32_t extcfg); +#endif +#ifdef ADC_HAVE_JEXTCFG +static int adc_jextcfg_set(struct at32_dev_s *priv, uint32_t jextcfg); +#endif + +static void adc_dumpregs(struct at32_dev_s *priv); + +#ifdef CONFIG_AT32_ADC_LL_OPS +static int adc_llops_setup(struct at32_adc_dev_s *dev); +static void adc_llops_shutdown(struct at32_adc_dev_s *dev); +static void adc_intack(struct at32_adc_dev_s *dev, uint32_t source); +static void adc_inten(struct at32_adc_dev_s *dev, uint32_t source); +static void adc_intdis(struct at32_adc_dev_s *dev, uint32_t source); +static uint32_t adc_intget(struct at32_adc_dev_s *dev); +static uint32_t adc_regget(struct at32_adc_dev_s *dev); +static void adc_llops_reg_startconv(struct at32_adc_dev_s *dev, + bool enable); +static int adc_offset_set(struct at32_adc_dev_s *dev, uint8_t ch, + uint8_t i, uint16_t offset); +# ifdef ADC_HAVE_EXTCFG +static void adc_llops_extcfg_set(struct at32_adc_dev_s *dev, + uint32_t extcfg); +# endif +# ifdef ADC_HAVE_JEXTCFG +static void adc_llops_jextcfg_set(struct at32_adc_dev_s *dev, + uint32_t jextcfg); +# endif +# ifdef ADC_HAVE_DMA +static int adc_regbufregister(struct at32_adc_dev_s *dev, + uint16_t *buffer, uint8_t len); +# endif +# ifdef ADC_HAVE_INJECTED +static uint32_t adc_injget(struct at32_adc_dev_s *dev, uint8_t chan); +static void adc_llops_inj_startconv(struct at32_adc_dev_s *dev, + bool enable); +# endif +# ifdef CONFIG_AT32_ADC_CHANGE_SAMPLETIME +static void adc_sampletime_set(struct at32_adc_dev_s *dev, + struct adc_sample_time_s *time_samples); +static void adc_sampletime_write(struct at32_adc_dev_s *dev); +# endif +static void adc_llops_dumpregs(struct at32_adc_dev_s *dev); +static int adc_llops_multicfg(struct at32_adc_dev_s *dev, uint8_t mode); +static void adc_llops_enable(struct at32_adc_dev_s *dev, bool enable); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* ADC interface operations */ + +static const struct adc_ops_s g_adcops = +{ + .ao_bind = adc_bind, +#ifdef HAVE_HSI_CONTROL + .ao_reset = adc_reset_hsi_disable, +#else + .ao_reset = adc_reset, +#endif + .ao_setup = adc_setup, + .ao_shutdown = adc_shutdown, + .ao_rxint = adc_rxint, + .ao_ioctl = adc_ioctl, +}; + +/* Publicly visible ADC lower-half operations */ + +#ifdef CONFIG_AT32_ADC_LL_OPS +static const struct at32_adc_ops_s g_adc_llops = +{ + .setup = adc_llops_setup, + .shutdown = adc_llops_shutdown, + .int_ack = adc_intack, + .int_get = adc_intget, + .int_en = adc_inten, + .int_dis = adc_intdis, + .val_get = adc_regget, + .reg_startconv = adc_llops_reg_startconv, + .offset_set = adc_offset_set, +# ifdef ADC_HAVE_DMA + .regbuf_reg = adc_regbufregister, +# endif +# ifdef ADC_HAVE_EXTCFG + .extcfg_set = adc_llops_extcfg_set, +# endif +# ifdef ADC_HAVE_JEXTCFG + .jextcfg_set = adc_llops_jextcfg_set, +# endif +# ifdef ADC_HAVE_INJECTED + .inj_get = adc_injget, + .inj_startconv = adc_llops_inj_startconv, +# endif +# ifdef CONFIG_AT32_ADC_CHANGE_SAMPLETIME + .stime_set = adc_sampletime_set, + .stime_write = adc_sampletime_write, +# endif + .dump_regs = adc_llops_dumpregs, + .multi_cfg = adc_llops_multicfg, + .enable = adc_llops_enable +}; +#endif + +/* ADC instances are coupled in blocks for all IP versions except + * basic ADC IPv1 (F1, F37x). + */ + +#ifdef HAVE_ADC_CMN_DATA +# ifdef HAVE_IP_ADC_V1 +# define ADC1CMN_DATA g_adc123_cmn +# define ADC2CMN_DATA g_adc123_cmn +# define ADC3CMN_DATA g_adc123_cmn + +/* ADC123 common data */ + +struct adccmn_data_s g_adc123_cmn = +{ + .refcount = 0, + .lock = NXMUTEX_INITIALIZER, +}; + +# elif defined(HAVE_IP_ADC_V2) +# define ADC1CMN_DATA g_adc12_cmn +# define ADC2CMN_DATA g_adc12_cmn +# define ADC3CMN_DATA g_adc34_cmn +# if defined(CONFIG_AT32_ADC1) || defined(CONFIG_AT32_ADC2) + +/* ADC12 common data */ + +struct adccmn_data_s g_adc12_cmn = +{ + .refcount = 0, + .lock = NXMUTEX_INITIALIZER, +}; + +# endif +# if defined(CONFIG_AT32_ADC3) + +/* ADC3 common data */ + +struct adccmn_data_s g_adc34_cmn = +{ + .refcount = 0, + .lock = NXMUTEX_INITIALIZER, +}; + +# endif +# endif /* !HAVE_IP_ADC_V1 */ +#endif /* HAVE_ADC_CMN_DATA */ + +/* ADC1 state */ + +#ifdef CONFIG_AT32_ADC1 +static struct at32_dev_s g_adcpriv1 = +{ +#ifdef CONFIG_AT32_ADC_LL_OPS + .llops = &g_adc_llops, +#endif +#ifndef CONFIG_AT32_ADC_NOIRQ +# if defined(AT32_IRQ_ADC1) + .irq = AT32_IRQ_ADC1, + .isr = adc1_interrupt, +# elif defined(AT32_IRQ_ADC12) + .irq = AT32_IRQ_ADC12, + .isr = adc12_interrupt, +# elif defined(AT32_IRQ_ADC) + .irq = AT32_IRQ_ADC, + .isr = adc123_interrupt, +# else +# error "No AT32_IRQ_ADC1 AT32_IRQ_ADC12 or AT32_IRQ_ADC defined for CONFIG_AT32_ADC1" +# endif +#endif /* CONFIG_AT32_ADC_NOIRQ */ +#ifdef HAVE_ADC_CMN_DATA + .cmn = &ADC1CMN_DATA, +#endif + .intf = 1, + .initialized = 0, + .anioc_trg = CONFIG_AT32_ADC1_ANIOC_TRIGGER, +#ifdef HAVE_ADC_RESOLUTION + .resolution = CONFIG_AT32_ADC1_RESOLUTION, +#endif + .base = AT32_ADC1_BASE, +#ifdef ADC1_HAVE_EXTCFG + .extcfg = ADC1_EXTCFG_VALUE, +#endif +#ifdef ADC1_HAVE_JEXTCFG + .jextcfg = ADC1_JEXTCFG_VALUE, +#endif +#ifdef ADC1_HAVE_TIMER + .trigger = CONFIG_AT32_ADC1_TIMTRIG, + .tbase = ADC1_TIMER_BASE, + .pclck = ADC1_TIMER_PCLK_FREQUENCY, + .freq = CONFIG_AT32_ADC1_SAMPLE_FREQUENCY, +#endif +#ifdef ADC1_HAVE_DMA + .dmachan = DMAMUX_ADC1, +# ifdef ADC_HAVE_DMACFG + .dmacfg = CONFIG_AT32_ADC1_DMA_CFG, +# endif + .hasdma = true, +#endif +#ifdef ADC_HAVE_SCAN + .scan = CONFIG_AT32_ADC1_SCAN, +#endif +}; + +static struct adc_dev_s g_adcdev1 = +{ + .ad_ops = &g_adcops, + .ad_priv = &g_adcpriv1, +}; +#endif + +/* ADC2 state */ + +#ifdef CONFIG_AT32_ADC2 +static struct at32_dev_s g_adcpriv2 = +{ +#ifdef CONFIG_AT32_ADC_LL_OPS + .llops = &g_adc_llops, +#endif +#ifndef CONFIG_AT32_ADC_NOIRQ +# if defined(AT32_IRQ_ADC12) + .irq = AT32_IRQ_ADC12, + .isr = adc12_interrupt, +# elif defined(AT32_IRQ_ADC) + .irq = AT32_IRQ_ADC, + .isr = adc123_interrupt, +# else +# error "No AT32_IRQ_ADC12 or AT32_IRQ_ADC defined for CONFIG_AT32_ADC2" +# endif +#endif /* CONFIG_AT32_ADC_NOIRQ */ +#ifdef HAVE_ADC_CMN_DATA + .cmn = &ADC2CMN_DATA, +#endif + .intf = 2, + .initialized = 0, + .anioc_trg = CONFIG_AT32_ADC2_ANIOC_TRIGGER, +#ifdef HAVE_ADC_RESOLUTION + .resolution = CONFIG_AT32_ADC2_RESOLUTION, +#endif + .base = AT32_ADC2_BASE, +#ifdef ADC2_HAVE_EXTCFG + .extcfg = ADC2_EXTCFG_VALUE, +#endif +#ifdef ADC2_HAVE_JEXTCFG + .jextcfg = ADC2_JEXTCFG_VALUE, +#endif +#ifdef ADC2_HAVE_TIMER + .trigger = CONFIG_AT32_ADC2_TIMTRIG, + .tbase = ADC2_TIMER_BASE, + .pclck = ADC2_TIMER_PCLK_FREQUENCY, + .freq = CONFIG_AT32_ADC2_SAMPLE_FREQUENCY, +#endif +#ifdef ADC2_HAVE_DMA + .dmachan = DMAMUX_ADC2, +# ifdef ADC_HAVE_DMACFG + .dmacfg = CONFIG_AT32_ADC2_DMA_CFG, +# endif + .hasdma = true, +#endif +#ifdef ADC_HAVE_SCAN + .scan = CONFIG_AT32_ADC2_SCAN, +#endif +}; + +static struct adc_dev_s g_adcdev2 = +{ + .ad_ops = &g_adcops, + .ad_priv = &g_adcpriv2, +}; +#endif + +/* ADC3 state */ + +#ifdef CONFIG_AT32_ADC3 +static struct at32_dev_s g_adcpriv3 = +{ +#ifdef CONFIG_AT32_ADC_LL_OPS + .llops = &g_adc_llops, +#endif +#ifndef CONFIG_AT32_ADC_NOIRQ +# if defined(AT32_IRQ_ADC3) + .irq = AT32_IRQ_ADC3, + .isr = adc3_interrupt, +# elif defined(AT32_IRQ_ADC) + .irq = AT32_IRQ_ADC, + .isr = adc123_interrupt, +# else +# error "No AT32_IRQ_ADC3 or AT32_IRQ_ADC defined for CONFIG_AT32_ADC3" +# endif +#endif /* CONFIG_AT32_ADC_NOIRQ */ +#ifdef HAVE_ADC_CMN_DATA + .cmn = &ADC3CMN_DATA, +#endif + .intf = 3, + .initialized = 0, + .anioc_trg = CONFIG_AT32_ADC3_ANIOC_TRIGGER, +#ifdef HAVE_ADC_RESOLUTION + .resolution = CONFIG_AT32_ADC3_RESOLUTION, +#endif + .base = AT32_ADC3_BASE, +#ifdef ADC3_HAVE_EXTCFG + .extcfg = ADC3_EXTCFG_VALUE, +#endif +#ifdef ADC3_HAVE_JEXTCFG + .jextcfg = ADC3_JEXTCFG_VALUE, +#endif +#ifdef ADC3_HAVE_TIMER + .trigger = CONFIG_AT32_ADC3_TIMTRIG, + .tbase = ADC3_TIMER_BASE, + .pclck = ADC3_TIMER_PCLK_FREQUENCY, + .freq = CONFIG_AT32_ADC3_SAMPLE_FREQUENCY, +#endif +#ifdef ADC3_HAVE_DMA + .dmachan = DMAMUX_ADC3, +# ifdef ADC_HAVE_DMACFG + .dmacfg = CONFIG_AT32_ADC3_DMA_CFG, +# endif + .hasdma = true, +#endif +#ifdef ADC_HAVE_SCAN + .scan = CONFIG_AT32_ADC3_SCAN, +#endif +}; + +static struct adc_dev_s g_adcdev3 = +{ + .ad_ops = &g_adcops, + .ad_priv = &g_adcpriv3, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_modifyreg32 + * + * Description: + * Modify the value of a 32-bit register (not atomic). + * + * Input Parameters: + * addr - The address of the register + * clrbits - The bits to clear + * setbits - The bits to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef HAVE_BASIC_ADC +static void at32_modifyreg32(unsigned int addr, uint32_t clrbits, + uint32_t setbits) +{ + putreg32((getreg32(addr) & ~clrbits) | setbits, addr); +} +#endif + +/**************************************************************************** + * Name: adc_getreg + * + * Description: + * Read the value of an ADC register. + * + * Input Parameters: + * priv - A reference to the ADC block status + * offset - The offset to the register to read + * + * Returned Value: + * The current contents of the specified register + * + ****************************************************************************/ + +static uint32_t adc_getreg(struct at32_dev_s *priv, int offset) +{ + return getreg32(priv->base + offset); +} + +/**************************************************************************** + * Name: adc_putreg + * + * Description: + * Write a value to an ADC register. + * + * Input Parameters: + * priv - A reference to the ADC block status + * offset - The offset to the register to write to + * value - The value to write to the register + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void adc_putreg(struct at32_dev_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->base + offset); +} + +/**************************************************************************** + * Name: adc_modifyreg + * + * Description: + * Modify the value of an ADC register (not atomic). + * + * Input Parameters: + * priv - A reference to the ADC block status + * offset - The offset to the register to modify + * clrbits - The bits to clear + * setbits - The bits to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void adc_modifyreg(struct at32_dev_s *priv, int offset, + uint32_t clrbits, uint32_t setbits) +{ + adc_putreg(priv, offset, (adc_getreg(priv, offset) & ~clrbits) | setbits); +} + +#ifdef HAVE_ADC_CMN_REGS + +/**************************************************************************** + * Name: adccmn_base_get + ****************************************************************************/ + +static uint32_t adccmn_base_get(struct at32_dev_s *priv) +{ + uint32_t base = 0; + +#if defined(HAVE_IP_ADC_V2) + if (priv->base == AT32_ADC1_BASE || priv->base == AT32_ADC2_BASE) + { + base = AT32_ADC12CMN_BASE; + } +# if defined(CONFIG_AT32_ADC3) + else + { + base = AT32_ADC3CMN_BASE; + } +# endif + +#elif defined(HAVE_IP_ADC_V1) + base = AT32_ADCCMN_BASE; + UNUSED(priv); +#endif + + return base; +} + +/**************************************************************************** + * Name: adccmn_modifyreg + ****************************************************************************/ + +static void adccmn_modifyreg(struct at32_dev_s *priv, uint32_t offset, + uint32_t clrbits, uint32_t setbits) +{ + uint32_t base = 0; + + /* Get base address for ADC common register */ + + base = adccmn_base_get(priv); + + /* Modify register */ + + at32_modifyreg32(offset + base, clrbits, setbits); +} + +/**************************************************************************** + * Name: adccmn_getreg + ****************************************************************************/ + +static uint32_t adccmn_getreg(struct at32_dev_s *priv, uint32_t offset) +{ + uint32_t base = 0; + + /* Get base address for ADC common register */ + + base = adccmn_base_get(priv); + + /* Return register value */ + + return getreg32(base + offset); +} +#endif /* HAVE_ADC_CMN_REGS */ + +/**************************************************************************** + * Name: tim_getreg + * + * Description: + * Read the value of an ADC timer register. + * + * Input Parameters: + * priv - A reference to the ADC block status + * offset - The offset to the register to read + * + * Returned Value: + * The current contents of the specified register + * + ****************************************************************************/ + +#ifdef ADC_HAVE_TIMER +static uint16_t tim_getreg(struct at32_dev_s *priv, int offset) +{ + return getreg16(priv->tbase + offset); +} +#endif + +/**************************************************************************** + * Name: tim_putreg + * + * Description: + * Write a value to an ADC timer register. + * + * Input Parameters: + * priv - A reference to the ADC block status + * offset - The offset to the register to write to + * value - The value to write to the register + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef ADC_HAVE_TIMER +static void tim_putreg(struct at32_dev_s *priv, int offset, + uint16_t value) +{ + putreg16(value, priv->tbase + offset); +} +#endif + +/**************************************************************************** + * Name: tim_modifyreg + * + * Description: + * Modify the value of an ADC timer register (not atomic). + * + * Input Parameters: + * priv - A reference to the ADC block status + * offset - The offset to the register to modify + * clrbits - The bits to clear + * setbits - The bits to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef ADC_HAVE_TIMER +static void tim_modifyreg(struct at32_dev_s *priv, int offset, + uint16_t clrbits, uint16_t setbits) +{ + tim_putreg(priv, offset, (tim_getreg(priv, offset) & ~clrbits) | setbits); +} +#endif + +/**************************************************************************** + * Name: tim_dumpregs + * + * Description: + * Dump all timer registers. + * + * Input Parameters: + * priv - A reference to the ADC block status + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef ADC_HAVE_TIMER +static void tim_dumpregs(struct at32_dev_s *priv, const char *msg) +{ + ainfo("%s:\n", msg); + ainfo(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n", + tim_getreg(priv, AT32_GTIM_CR1_OFFSET), + tim_getreg(priv, AT32_GTIM_CR2_OFFSET), + tim_getreg(priv, AT32_GTIM_SMCR_OFFSET), + tim_getreg(priv, AT32_GTIM_DIER_OFFSET)); + ainfo(" SR: %04x EGR: 0000 CCMR1: %04x CCMR2: %04x\n", + tim_getreg(priv, AT32_GTIM_SR_OFFSET), + tim_getreg(priv, AT32_GTIM_CCMR1_OFFSET), + tim_getreg(priv, AT32_GTIM_CCMR2_OFFSET)); + ainfo(" CCER: %04x CNT: %04x PSC: %04x ARR: %04x\n", + tim_getreg(priv, AT32_GTIM_CCER_OFFSET), + tim_getreg(priv, AT32_GTIM_CNT_OFFSET), + tim_getreg(priv, AT32_GTIM_PSC_OFFSET), + tim_getreg(priv, AT32_GTIM_ARR_OFFSET)); + ainfo(" CCR1: %04x CCR2: %04x CCR3: %04x CCR4: %04x\n", + tim_getreg(priv, AT32_GTIM_CCR1_OFFSET), + tim_getreg(priv, AT32_GTIM_CCR2_OFFSET), + tim_getreg(priv, AT32_GTIM_CCR3_OFFSET), + tim_getreg(priv, AT32_GTIM_CCR4_OFFSET)); +#if AT32_NATIM > 0 + if (priv->tbase == AT32_TMR1_BASE +# ifdef AT32_TMR8_BASE + || priv->tbase == AT32_TMR8_BASE +# endif + ) + { + ainfo(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n", + tim_getreg(priv, AT32_ATIM_RCR_OFFSET), + tim_getreg(priv, AT32_ATIM_BDTR_OFFSET), + tim_getreg(priv, AT32_ATIM_DCR_OFFSET), + tim_getreg(priv, AT32_ATIM_DMAR_OFFSET)); + } + else +#endif + { + ainfo(" DCR: %04x DMAR: %04x\n", + tim_getreg(priv, AT32_GTIM_DCR_OFFSET), + tim_getreg(priv, AT32_GTIM_DMAR_OFFSET)); + } +} +#endif + +/**************************************************************************** + * Name: adc_timstart + * + * Description: + * Start (or stop) the timer counter + * + * Input Parameters: + * priv - A reference to the ADC block status + * enable - True: Start conversion + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef ADC_HAVE_TIMER +static void adc_timstart(struct at32_dev_s *priv, bool enable) +{ + ainfo("enable: %d\n", enable ? 1 : 0); + + if (enable) + { + /* Start the counter */ + + tim_modifyreg(priv, AT32_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN); + } + else + { + /* Disable the counter */ + + tim_modifyreg(priv, AT32_GTIM_CR1_OFFSET, GTIM_CR1_CEN, 0); + } +} +#endif + +/**************************************************************************** + * Name: adc_timinit + * + * Description: + * Initialize the timer that drivers the ADC sampling for this channel + * using the pre-calculated timer divider definitions. + * + * Input Parameters: + * priv - A reference to the ADC block status + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef ADC_HAVE_TIMER +static int adc_timinit(struct at32_dev_s *priv) +{ + uint32_t prescaler; + uint32_t reload; + uint32_t timclk; + uint16_t clrbits = 0; + uint16_t setbits = 0; + uint16_t cr2; + uint16_t ccmr1; + uint16_t ccmr2; + uint16_t ocmode1; + uint16_t ocmode2; + uint16_t ccenable; + uint16_t ccer; + uint16_t egr; + + /* If the timer base address is zero, then this ADC was not configured to + * use a timer. + */ + + if (priv->tbase == 0) + { + return ERROR; + } + + /* NOTE: EXTSEL configuration is done in adc_reset function */ + + /* Configure the timer channel to drive the ADC */ + + /* Calculate optimal values for the timer prescaler and for the timer + * reload register. If freq is the desired frequency, then + * + * reload = timclk / freq + * reload = (pclck / prescaler) / freq + * + * There are many solutions to do this, but the best solution will be the + * one that has the largest reload value and the smallest prescaler value. + * That is the solution that should give us the most accuracy in the timer + * control. Subject to: + * + * 0 <= prescaler <= 65536 + * 1 <= reload <= 65535 + * + * So (prescaler = pclck / 65535 / freq) would be optimal. + */ + + prescaler = (priv->pclck / priv->freq + 65534) / 65535; + + /* We need to decrement the prescaler value by one, but only, the value + * does not underflow. + */ + + if (prescaler < 1) + { + awarn("WARNING: Prescaler underflowed.\n"); + prescaler = 1; + } + + /* Check for overflow */ + + else if (prescaler > 65536) + { + awarn("WARNING: Prescaler overflowed.\n"); + prescaler = 65536; + } + + timclk = priv->pclck / prescaler; + + reload = timclk / priv->freq; + if (reload < 1) + { + awarn("WARNING: Reload value underflowed.\n"); + reload = 1; + } + else if (reload > 65535) + { + awarn("WARNING: Reload value overflowed.\n"); + reload = 65535; + } + + /* Disable the timer until we get it configured */ + + adc_timstart(priv, false); + + /* Set up the timer CR1 register. + * + * Select the Counter Mode == count up: + * + * ATIM_CR1_EDGE: The counter counts up or down depending on the + * direction bit(DIR). + * ATIM_CR1_DIR: 0: count up, 1: count down + * + * Set the clock division to zero for all + */ + + clrbits = GTIM_CR1_DIR | GTIM_CR1_CMS_MASK | GTIM_CR1_CKD_MASK; + setbits = GTIM_CR1_EDGE; + tim_modifyreg(priv, AT32_GTIM_CR1_OFFSET, clrbits, setbits); + + /* Set the reload and prescaler values */ + + tim_putreg(priv, AT32_GTIM_PSC_OFFSET, prescaler - 1); + tim_putreg(priv, AT32_GTIM_ARR_OFFSET, reload); + + /* Clear the advanced timers repetition counter in TIM1 */ + +#if AT32_NATIM > 0 + if (priv->tbase == AT32_TMR1_BASE +# ifdef AT32_TMR8_BASE + || priv->tbase == AT32_TMR8_BASE +# endif + ) + { + tim_putreg(priv, AT32_ATIM_RCR_OFFSET, 0); + tim_putreg(priv, AT32_ATIM_BDTR_OFFSET, ATIM_BDTR_MOE); /* Check me */ + } +#endif + + /* TIMx event generation: Bit 0 UG: Update generation */ + + tim_putreg(priv, AT32_GTIM_EGR_OFFSET, GTIM_EGR_UG); + + /* Handle channel specific setup */ + + ocmode1 = 0; + ocmode2 = 0; + + switch (priv->trigger) + { + case 0: /* TimerX CC1 event */ + { + ccenable = ATIM_CCER_CC1E; + ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT) | + (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC1M_SHIFT) | + ATIM_CCMR1_OC1PE; + + /* Set the event CC1 */ + + egr = ATIM_EGR_CC1G; + + /* Set the duty cycle by writing to the CCR register for this + * channel + */ + + tim_putreg(priv, AT32_GTIM_CCR1_OFFSET, (uint16_t)(reload >> 1)); + } + break; + + case 1: /* TimerX CC2 event */ + { + ccenable = ATIM_CCER_CC2E; + ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT) | + (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC2M_SHIFT) | + ATIM_CCMR1_OC2PE; + + /* Set the event CC2 */ + + egr = ATIM_EGR_CC2G; + + /* Set the duty cycle by writing to the CCR register for this + * channel + */ + + tim_putreg(priv, AT32_GTIM_CCR2_OFFSET, (uint16_t)(reload >> 1)); + } + break; + + case 2: /* TimerX CC3 event */ + { + ccenable = ATIM_CCER_CC3E; + ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC3S_SHIFT) | + (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC3M_SHIFT) | + ATIM_CCMR2_OC3PE; + + /* Set the event CC3 */ + + egr = ATIM_EGR_CC3G; + + /* Set the duty cycle by writing to the CCR register for this + * channel + */ + + tim_putreg(priv, AT32_GTIM_CCR3_OFFSET, (uint16_t)(reload >> 1)); + } + break; + + case 3: /* TimerX CC4 event */ + { + ccenable = ATIM_CCER_CC4E; + ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC4S_SHIFT) | + (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC4M_SHIFT) | + ATIM_CCMR2_OC4PE; + + /* Set the event CC4 */ + + egr = ATIM_EGR_CC4G; + + /* Set the duty cycle by writing to the CCR register for this + * channel + */ + + tim_putreg(priv, AT32_GTIM_CCR4_OFFSET, (uint16_t)(reload >> 1)); + } + break; + + case 4: /* TimerX TRGO event */ + { + /* TODO: TRGO support not yet implemented */ + + /* Set the event TRGO */ + + ccenable = 0; + egr = GTIM_EGR_TG; + + /* Set the duty cycle by writing to the CCR register for this + * channel + */ + + tim_putreg(priv, AT32_GTIM_CCR4_OFFSET, (uint16_t)(reload >> 1)); + } + break; + + default: + aerr("ERROR: No such trigger: %d\n", priv->trigger); + return -EINVAL; + } + + /* Disable the Channel by resetting the CCxE Bit in the CCER register */ + + ccer = tim_getreg(priv, AT32_GTIM_CCER_OFFSET); + ccer &= ~ccenable; + tim_putreg(priv, AT32_GTIM_CCER_OFFSET, ccer); + + /* Fetch the CR2, CCMR1, and CCMR2 register (already have ccer) */ + + cr2 = tim_getreg(priv, AT32_GTIM_CR2_OFFSET); + ccmr1 = tim_getreg(priv, AT32_GTIM_CCMR1_OFFSET); + ccmr2 = tim_getreg(priv, AT32_GTIM_CCMR2_OFFSET); + + /* Reset the Output Compare Mode Bits and set the select output compare + * mode + */ + + ccmr1 &= ~(ATIM_CCMR1_CC1S_MASK | ATIM_CCMR1_OC1M_MASK | ATIM_CCMR1_OC1PE | + ATIM_CCMR1_CC2S_MASK | ATIM_CCMR1_OC2M_MASK | ATIM_CCMR1_OC2PE); + ccmr2 &= ~(ATIM_CCMR2_CC3S_MASK | ATIM_CCMR2_OC3M_MASK | ATIM_CCMR2_OC3PE | + ATIM_CCMR2_CC4S_MASK | ATIM_CCMR2_OC4M_MASK | ATIM_CCMR2_OC4PE); + ccmr1 |= ocmode1; + ccmr2 |= ocmode2; + + /* Reset the output polarity level of all channels (selects high + * polarity) + */ + + ccer &= ~(ATIM_CCER_CC1P | ATIM_CCER_CC2P | + ATIM_CCER_CC3P | ATIM_CCER_CC4P); + + /* Enable the output state of the selected channel (only) */ + + ccer &= ~(ATIM_CCER_CC1E | ATIM_CCER_CC2E | + ATIM_CCER_CC3E | ATIM_CCER_CC4E); + ccer |= ccenable; + + /* TODO: revisit and simplify logic below */ + +#if AT32_NATIM > 0 + if (priv->tbase == AT32_TMR1_BASE +# ifdef AT32_TMR8_BASE + || priv->tbase == AT32_TMR8_BASE +# endif + ) + { + /* Reset output N polarity level, output N state, output compare state, + * output compare N idle state. + */ + + ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP | + ATIM_CCER_CC2NE | ATIM_CCER_CC2NP | + ATIM_CCER_CC3NE | ATIM_CCER_CC3NP); + + /* Reset the output compare and output compare N IDLE State */ + + cr2 &= ~(ATIM_CR2_OIS1 | ATIM_CR2_OIS1N | + ATIM_CR2_OIS2 | ATIM_CR2_OIS2N | + ATIM_CR2_OIS3 | ATIM_CR2_OIS3N | + ATIM_CR2_OIS4); + } +# if defined(HAVE_GTIM_CCXNP) + else + { + ccer &= ~(GTIM_CCER_CC1NP | GTIM_CCER_CC2NP | GTIM_CCER_CC3NP | + GTIM_CCER_CC4NP); + } +# endif + +#else /* No ADV TIM */ + + /* For only these timers can be used: 2-4, 6, 7, 9, + * 10. Reset the output compare and output compare N IDLE State + */ + + if (priv->tbase >= AT32_TMR2_BASE && priv->tbase <= AT32_TMR4_BASE) + { + /* Reset output N polarity level, output N state, output compare state, + * output compare N idle state. + */ + + ccer &= ~(GTIM_CCER_CC1NE | GTIM_CCER_CC1NP | + GTIM_CCER_CC2NE | GTIM_CCER_CC2NP | + GTIM_CCER_CC3NE | GTIM_CCER_CC3NP | + GTIM_CCER_CC4NP); + } +#endif + + /* Save the modified register values */ + + tim_putreg(priv, AT32_GTIM_CR2_OFFSET, cr2); + tim_putreg(priv, AT32_GTIM_CCMR1_OFFSET, ccmr1); + tim_putreg(priv, AT32_GTIM_CCMR2_OFFSET, ccmr2); + tim_putreg(priv, AT32_GTIM_CCER_OFFSET, ccer); + tim_putreg(priv, AT32_GTIM_EGR_OFFSET, egr); + + /* Set the ARR Preload Bit */ + + tim_modifyreg(priv, AT32_GTIM_CR1_OFFSET, 0, GTIM_CR1_ARPE); + + /* Enable the timer counter */ + + adc_timstart(priv, true); + + tim_dumpregs(priv, "After starting timers"); + + return OK; +} +#endif + +/**************************************************************************** + * Name: adc_reg_startconv + * + * Description: + * Start (or stop) the ADC regular conversion process + * + * Input Parameters: + * priv - A reference to the ADC block status + * enable - True: Start conversion + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(HAVE_IP_ADC_V2) +static void adc_reg_startconv(struct at32_dev_s *priv, bool enable) +{ + uint32_t regval; + + ainfo("reg enable: %d\n", enable ? 1 : 0); + + if (enable) + { + /* Start the conversion of regular channels */ + + adc_modifyreg(priv, AT32_ADC_CR_OFFSET, 0, ADC_CR_ADSTART); + } + else + { + regval = adc_getreg(priv, AT32_ADC_CR_OFFSET); + + /* Is a conversion ongoing? */ + + if ((regval & ADC_CR_ADSTART) != 0) + { + /* Stop the conversion */ + + adc_putreg(priv, AT32_ADC_CR_OFFSET, regval | ADC_CR_ADSTP); + + /* Wait for the conversion to stop */ + + while ((adc_getreg(priv, AT32_ADC_CR_OFFSET) & + ADC_CR_ADSTP) != 0); + } + } +} +#elif defined(HAVE_IP_ADC_V1) && !defined(HAVE_BASIC_ADC) +static void adc_reg_startconv(struct at32_dev_s *priv, bool enable) +{ + ainfo("reg enable: %d\n", enable ? 1 : 0); + + if (enable) + { + /* Start the conversion of regular channels */ + + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, 0, ADC_CR2_SWSTART); + } + else + { + /* Stop the conversion */ + + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, ADC_CR2_SWSTART, 0); + } +} +#else /* ADV IPv1 BASIC */ +static void adc_reg_startconv(struct at32_dev_s *priv, bool enable) +{ + ainfo("reg enable: %d\n", enable ? 1 : 0); + + if (!enable) + { + /* Clear ADON to stop the conversion and put the ADC in the + * power down state. + */ + + adc_enable(priv, false); + } + + /* If the ADC is already on, set ADON again to start the conversion. + * Otherwise, set ADON once to wake up the ADC from the power down state. + */ + + adc_enable(priv, true); +} +#endif + +#ifdef ADC_HAVE_INJECTED + +/**************************************************************************** + * Name: adc_inj_startconv + * + * Description: + * Start (or stop) the ADC injected conversion process + * + * Input Parameters: + * priv - A reference to the ADC block status + * enable - True: Start conversion + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(HAVE_IP_ADC_V2) +static void adc_inj_startconv(struct at32_dev_s *priv, bool enable) +{ + uint32_t regval; + + ainfo("inj enable: %d\n", enable ? 1 : 0); + + if (enable) + { + /* Start the conversion of regular channels */ + + adc_modifyreg(priv, AT32_ADC_CR_OFFSET, 0, ADC_CR_JADSTART); + } + else + { + regval = adc_getreg(priv, AT32_ADC_CR_OFFSET); + + /* Is a conversion ongoing? */ + + if ((regval & ADC_CR_JADSTART) != 0) + { + /* Stop the conversion */ + + adc_putreg(priv, AT32_ADC_CR_OFFSET, regval | ADC_CR_JADSTP); + + /* Wait for the conversion to stop */ + + while ((adc_getreg(priv, AT32_ADC_CR_OFFSET) & + ADC_CR_JADSTP) != 0); + } + } +} +#elif defined(HAVE_IP_ADC_V1) +static void adc_inj_startconv(struct at32_dev_s *priv, bool enable) +{ + ainfo("inj enable: %d\n", enable ? 1 : 0); + + if (enable) + { + /* Start the conversion of injected channels */ + + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, 0, ADC_CR2_JSWSTART); + } + else + { + /* Stop the conversion */ + + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, ADC_CR2_JSWSTART, 0); + } +} +#endif + +#endif /* ADC_HAVE_INJECTED */ + +/**************************************************************************** + * Name: adc_rccreset + * + * Description: + * Deinitializes the ADCx peripheral registers to their default + * reset values. It could set all the ADCs configured. + * + * Input Parameters: + * priv - A reference to the ADC block status + * reset - Condition, set or reset + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(HAVE_IP_ADC_V1) && defined(HAVE_BASIC_ADC) +static void adc_rccreset(struct at32_dev_s *priv, bool reset) +{ + uint32_t adcbit; + + /* Pick the appropriate bit in the RCC reset register. + * For the basic AT32 ADC IPv1, there is an individual bit to reset + * each ADC (ADC12 and ADC34). + */ + + switch (priv->intf) + { +#ifdef CONFIG_AT32_ADC1 + case 1: + { + adcbit = RCC_RSTR_ADC1RST; + break; + } + +#endif +#ifdef CONFIG_AT32_ADC2 + case 2: + { + adcbit = RCC_RSTR_ADC2RST; + break; + } + +#endif +#ifdef CONFIG_AT32_ADC3 + case 3: + { + adcbit = RCC_RSTR_ADC3RST; + break; + } + +#endif + + default: + { + return; + } + } + + /* Set or clear the selected bit in the RCC reset register */ + + if (reset) + { + /* Enable ADC reset state */ + + modifyreg32(AT32_RCC_RSTR, 0, adcbit); + } + else + { + /* Release ADC from reset state */ + + modifyreg32(AT32_RCC_RSTR, adcbit, 0); + } +} +#elif defined(HAVE_IP_ADC_V1) +static void adc_rccreset(struct at32_dev_s *priv, bool reset) +{ + uint32_t adcbit; + + /* Pick the appropriate bit in the RCC reset register. + * For the AT32 ADC IPv1, there is one common reset for all ADCs. + */ + + switch (priv->intf) + { + case 1: + case 2: + case 3: + { + adcbit = RCC_RSTR_ADC123RST; + break; + } + + default: + { + return; + } + } + + /* Set or clear the selected bit in the RCC reset register */ + + if (reset) + { + /* Enable ADC reset state */ + + modifyreg32(AT32_RCC_RSTR, 0, adcbit); + } + else + { + /* Release ADC from reset state */ + + modifyreg32(AT32_RCC_RSTR, adcbit, 0); + } +} +#elif defined(HAVE_IP_ADC_V2) +static void adc_rccreset(struct at32_dev_s *priv, bool reset) +{ + uint32_t adcbit; + + /* Pick the appropriate bit in the RCC reset register. + * For the AT32 ADC IPv2, there is an individual bit to reset each + * ADC block. + */ + + switch (priv->intf) + { +#if defined(CONFIG_AT32_ADC1) || defined(CONFIG_AT32_ADC2) + case 1: + case 2: + { + adcbit = RCC_RSTR_ADC12RST; + break; + } + +#endif +#if defined(CONFIG_AT32_ADC3) + case 3: + { + adcbit = RCC_RSTR_ADC3RST; + break; + } + +#endif + default: + { + return; + } + } + + /* Set or clear the selected bit in the RCC reset register */ + + if (reset) + { + /* Enable ADC reset state */ + + modifyreg32(AT32_RCC_RSTR, 0, adcbit); + } + else + { + /* Release ADC from reset state */ + + modifyreg32(AT32_RCC_RSTR, adcbit, 0); + } +} +#endif + +/**************************************************************************** + * Name: adc_enable + * + * Description: + * Enables or disables the specified ADC peripheral. Also, starts a + * conversion when the ADC is not triggered by timers + * + * Input Parameters: + * + * enable - true: enable ADC conversion + * false: disable ADC conversion + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(HAVE_IP_ADC_V2) +static void adc_enable(struct at32_dev_s *priv, bool enable) +{ + uint32_t regval; + + ainfo("enable: %d\n", enable ? 1 : 0); + + regval = adc_getreg(priv, AT32_ADC_CR_OFFSET); + + if (enable) + { + /* Enable the ADC */ + + adc_putreg(priv, AT32_ADC_CR_OFFSET, regval | ADC_CR_ADEN); + + /* Wait for the ADC to be ready */ + + while ((adc_getreg(priv, AT32_ADC_ISR_OFFSET) & ADC_INT_ARDY) == 0); + } + else if ((regval & ADC_CR_ADEN) != 0 && (regval & ADC_CR_ADDIS) == 0) + { + /* Stop ongoing regular conversions */ + + adc_reg_startconv(priv, false); + + /* Disable the ADC */ + + adc_putreg(priv, AT32_ADC_CR_OFFSET, regval | ADC_CR_ADDIS); + + /* Wait for the ADC to be disabled */ + + while ((adc_getreg(priv, AT32_ADC_CR_OFFSET) & ADC_CR_ADEN) != 0); + } +} +#else /* HAVE_IP_ADC_V1 */ +static void adc_enable(struct at32_dev_s *priv, bool enable) +{ +#ifdef ADC_SR_ADONS + bool enabled = (adc_getreg(priv, AT32_ADC_SR_OFFSET) & ADC_SR_ADONS) != 0; +#else + bool enabled = false; +#endif + + ainfo("enable: %d\n", enable ? 1 : 0); + + if (!enabled && enable) + { + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, 0, ADC_CR2_ADON); + } + else if (enabled && !enable) + { + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, ADC_CR2_ADON, 0); + } +} +#endif + +/**************************************************************************** + * Name: adc_dmaconvcallback + * + * Description: + * Callback for DMA. Called from the DMA transfer complete interrupt after + * all channels have been converted and transferred with DMA. + * + * Input Parameters: + * + * handle - handle to DMA + * isr - + * arg - adc device + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(ADC_HAVE_DMA) && !defined(CONFIG_AT32_ADC_NOIRQ) +static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t isr, + void *arg) +{ + struct adc_dev_s *dev = (struct adc_dev_s *)arg; + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + int i; + + /* Verify that the upper-half driver has bound its callback functions */ + + if (priv->cb != NULL) + { + DEBUGASSERT(priv->cb->au_receive != NULL); + + for (i = 0; i < priv->rnchannels; i++) + { + priv->cb->au_receive(dev, priv->r_chanlist[priv->current], + priv->r_dmabuffer[priv->current]); + priv->current++; + if (priv->current >= priv->rnchannels) + { + /* Restart the conversion sequence from the beginning */ + + priv->current = 0; + } + } + } + + /* Restart DMA for the next conversion series */ + + adc_modifyreg(priv, AT32_ADC_DMAREG_OFFSET, ADC_DMAREG_DMA, 0); + adc_modifyreg(priv, AT32_ADC_DMAREG_OFFSET, 0, ADC_DMAREG_DMA); +} +#endif + +/**************************************************************************** + * Name: adc_bind + * + * Description: + * Bind the upper-half driver callbacks to the lower-half implementation. + * This must be called early in order to receive ADC event notifications. + * + ****************************************************************************/ + +static int adc_bind(struct adc_dev_s *dev, + const struct adc_callback_s *callback) +{ +#ifdef ADC_HAVE_CB + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + + DEBUGASSERT(priv != NULL); + priv->cb = callback; +#else + UNUSED(dev); + UNUSED(callback); +#endif + + return OK; +} + +/**************************************************************************** + * Name: adc_watchdog_cfg + ****************************************************************************/ + +#if defined(HAVE_IP_ADC_V2) +static void adc_watchdog_cfg(struct at32_dev_s *priv) +{ + uint32_t clrbits = 0; + uint32_t setbits = 0; + + /* Initialize the watchdog 1 threshold register */ + + adc_putreg(priv, AT32_ADC_TR1_OFFSET, 0x0fff0000); + + /* Enable the analog watchdog */ + + clrbits = ADC_CFGR1_AWD1CH_MASK; + setbits = ADC_CFGR1_AWD1EN | ADC_CFGR1_AWD1SGL | + (priv->r_chanlist[0] << ADC_CFGR1_AWD1CH_SHIFT); + + /* Modify CFGR configuration */ + + adc_modifyreg(priv, AT32_ADC_CFGR1_OFFSET, clrbits, setbits); +} +#else +static void adc_watchdog_cfg(struct at32_dev_s *priv) +{ + uint32_t clrbits = 0; + uint32_t setbits = 0; + + /* Initialize the watchdog high threshold register */ + + adc_putreg(priv, AT32_ADC_HTR_OFFSET, 0x00000fff); + + /* Initialize the watchdog low threshold register */ + + adc_putreg(priv, AT32_ADC_LTR_OFFSET, 0x00000000); + + clrbits = ADC_CR1_AWDCH_MASK; + setbits = ADC_CR1_AWDEN | (priv->r_chanlist[0] << ADC_CR1_AWDCH_SHIFT); + + /* Modify CR1 configuration */ + + adc_modifyreg(priv, AT32_ADC_CR1_OFFSET, clrbits, setbits); +} +#endif + +/**************************************************************************** + * Name: adc_calibrate + ****************************************************************************/ + +#if defined(HAVE_IP_ADC_V2) +static void adc_calibrate(struct at32_dev_s *priv) +{ +#if 0 /* Doesn't work */ + /* Calibrate the ADC */ + + adc_modifyreg(priv, AT32_ADC_CR_OFFSET, ADC_CR_ADCALDIF, AD_CR_ADCAL); + + /* Wait for the calibration to complete */ + + while ((adc_getreg(priv, AT32_ADC_CR_OFFSET) & ADC_CR_ADCAL) != 0); + +#else + UNUSED(priv); +#endif +} +#elif defined(HAVE_IP_ADC_V1) && defined(HAVE_BASIC_ADC) +static void adc_calibrate(struct at32_dev_s *priv) +{ + /* Power on the ADC */ + + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, 0, ADC_CR2_ADON); + + /* Wait for the ADC power on at least 2 ADCCLK cycles */ + + up_udelay(10); + + /* Reset calibration registers */ + + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, 0, ADC_CR2_RSTCAL); + + /* Wait for the calibration register reset to complete */ + + while ((adc_getreg(priv, AT32_ADC_CR2_OFFSET) & ADC_CR2_RSTCAL) != 0); + + /* Start ADC auto-calibration procedure */ + + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, 0, ADC_CR2_CAL); + + /* Wait for the calibration procedure to complete */ + + while ((adc_getreg(priv, AT32_ADC_CR2_OFFSET) & ADC_CR2_CAL) != 0); + + /* Power off the ADC */ + + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, ADC_CR2_ADON, 0); +} +#else +# define adc_calibrate(priv) +#endif + +/**************************************************************************** + * Name: adc_mode_cfg + ****************************************************************************/ + +#ifdef HAVE_IP_ADC_V2 +static void adc_mode_cfg(struct at32_dev_s *priv) +{ + uint32_t clrbits = 0; + uint32_t setbits = 0; + + /* Disable continuous mode and set align to right */ + + clrbits = ADC_CFGR1_CONT | ADC_CFGR1_ALIGN; + + /* Disable external trigger for regular channels */ + + clrbits |= ADC_CFGR1_EXTEN_MASK; + setbits |= ADC_CFGR1_EXTEN_NONE; + + /* Set CFGR configuration */ + + adc_modifyreg(priv, AT32_ADC_CFGR1_OFFSET, clrbits, setbits); +} +#else +static void adc_mode_cfg(struct at32_dev_s *priv) +{ + uint32_t clrbits = 0; + uint32_t setbits = 0; + +#ifdef HAVE_BASIC_ADC + /* Set independent mode */ + + clrbits |= ADC_CR1_DUALMOD_MASK; + setbits |= ADC_CR1_IND; +#endif + +#ifdef ADC_HAVE_SCAN + if (priv->scan == true) + { + setbits |= ADC_CR1_SCAN; + } +#endif + + /* Set CR1 configuration */ + + adc_modifyreg(priv, AT32_ADC_CR1_OFFSET, clrbits, setbits); + + /* Disable continuous mode and set align to right */ + + clrbits = ADC_CR2_CONT | ADC_CR2_ALIGN; + setbits = 0; + + /* Disable external trigger for regular channels */ + + clrbits |= ADC_EXTREG_EXTEN_MASK; + setbits |= ADC_EXTREG_EXTEN_NONE; + + /* Enable software trigger for regular channels + * REVISIT: SWSTART must be set if no EXT trigger and basic ADC IPv1 + */ + + /* Set CR2 configuration */ + + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, clrbits, setbits); +} +#endif + +/**************************************************************************** + * Name: adc_voltreg_cfg + ****************************************************************************/ + +#if defined(HAVE_IP_ADC_V2) +static void adc_voltreg_cfg(struct at32_dev_s *priv) +{ + /* Set ADC voltage regulator to intermediate state */ + + adc_modifyreg(priv, AT32_ADC_CR_OFFSET, ADC_CR_ADVREGEN_MASK, + ADC_CR_ADVREGEN_INTER); + + /* Enable the ADC voltage regulator */ + + adc_modifyreg(priv, AT32_ADC_CR_OFFSET, ADC_CR_ADVREGEN_MASK, + ADC_CR_ADVREGEN_ENABLED); + + /* Wait for the ADC voltage regulator to startup */ + + up_udelay(10); +} +#else +static void adc_voltreg_cfg(struct at32_dev_s *priv) +{ + /* Nothing to do here */ + + UNUSED(priv); +} +#endif + +/**************************************************************************** + * Name: adc_sampletime_cfg + ****************************************************************************/ + +static void adc_sampletime_cfg(struct adc_dev_s *dev) +{ + /* Initialize the same sample time for each ADC. + * During sample cycles channel selection bits must remain unchanged. + */ + +#ifdef CONFIG_AT32_ADC_CHANGE_SAMPLETIME + adc_sampletime_write((struct at32_adc_dev_s *)dev->ad_priv); +#else + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + + adc_putreg(priv, AT32_ADC_SMPR1_OFFSET, ADC_SMPR1_DEFAULT); + adc_putreg(priv, AT32_ADC_SMPR2_OFFSET, ADC_SMPR2_DEFAULT); +# ifdef AT32_ADC_SMPR3_OFFSET + adc_putreg(priv, AT32_ADC_SMPR3_OFFSET, ADC_SMPR3_DEFAULT); +# endif +# ifdef AT32_ADC_SMPR0_OFFSET + adc_putreg(priv, AT32_ADC_SMPR0_OFFSET, ADC_SMPR0_DEFAULT); +# endif +#endif +} + +/**************************************************************************** + * Name: adc_common_cfg + ****************************************************************************/ + +#if defined(HAVE_IP_ADC_V2) +static void adc_common_cfg(struct at32_dev_s *priv) +{ + uint32_t clrbits = 0; + uint32_t setbits = 0; + + /* REVISIT: */ + + clrbits = ADC_CCR_DUAL_MASK | ADC_CCR_DELAY_MASK | ADC_CCR_DMACFG | + ADC_CCR_MDMA_MASK | ADC_CCR_CKMODE_MASK | ADC_CCR_VREFEN | + ADC_CCR_TSEN | ADC_CCR_VBATEN; + setbits = ADC_CCR_DUAL_IND | ADC_CCR_DELAY(1) | ADC_CCR_MDMA_DISABLED | + ADC_CCR_CKMODE_ASYNCH; + + adccmn_modifyreg(priv, AT32_ADC_CCR_OFFSET, clrbits, setbits); +} +#elif defined(HAVE_IP_ADC_V1) && !defined(HAVE_BASIC_ADC) +static void adc_common_cfg(struct at32_dev_s *priv) +{ + uint32_t clrbits = 0; + uint32_t setbits = 0; + + clrbits = ADC_CCR_ADCPRE_MASK | ADC_CCR_TSVREFE; + setbits = ADC_CCR_ADCPRE_DIV2; + + /* REVISIT: */ + + clrbits |= ADC_CCR_MULTI_MASK | ADC_CCR_DELAY_MASK | ADC_CCR_DDS | + ADC_CCR_DMA_MASK | ADC_CCR_VBATEN; + setbits |= ADC_CCR_MULTI_NONE | ADC_CCR_DMA_DISABLED; + + adccmn_modifyreg(priv, AT32_ADC_CCR_OFFSET, clrbits, setbits); +} +#else +static void adc_common_cfg(struct at32_dev_s *priv) +{ + /* Do nothing here */ + + UNUSED(priv); +} +#endif + +#ifdef ADC_HAVE_DMA +/**************************************************************************** + * Name: adc_dma_cfg + ****************************************************************************/ + +#ifdef HAVE_IP_ADC_V2 +static void adc_dma_cfg(struct at32_dev_s *priv) +{ + uint32_t clrbits = 0; + uint32_t setbits = 0; + + /* Set DMA mode */ + + if (priv->dmacfg == 0) + { + /* One Shot Mode */ + + clrbits |= ADC_CFGR1_DMACFG; + } + else + { + /* Circular Mode */ + + setbits |= ADC_CFGR1_DMACFG; + } + + /* Enable DMA */ + + setbits |= ADC_CFGR1_DMAEN; + + /* Modify CFGR configuration */ + + adc_modifyreg(priv, AT32_ADC_CFGR1_OFFSET, clrbits, setbits); +} +#else +static void adc_dma_cfg(struct at32_dev_s *priv) +{ + uint32_t clrbits = 0; + uint32_t setbits = 0; + +#ifdef ADC_HAVE_DMACFG + /* Set DMA mode */ + + if (priv->dmacfg == 0) + { + /* One Shot Mode */ + + clrbits |= ADC_CR2_DDS; + } + else + { + /* Circular Mode */ + + setbits |= ADC_CR2_DDS; + } +#endif + + /* Enable DMA */ + + setbits |= ADC_CR2_DMA; + + /* Modify CR2 configuration */ + + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, clrbits, setbits); +} +#endif + +/**************************************************************************** + * Name: adc_dma_start + ****************************************************************************/ + +static void adc_dma_start(struct adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + + /* Stop and free DMA if it was started before */ + + if (priv->dma != NULL) + { + at32_dmastop(priv->dma); + at32_dmafree(priv->dma); + } + + priv->dma = at32_dmachannel(priv->dmachan); + +#ifndef CONFIG_AT32_ADC_NOIRQ + /* Start DMA only if standard ADC interrupts used */ + + at32_dmasetup(priv->dma, + priv->base + AT32_ADC_DR_OFFSET, + (uint32_t)priv->r_dmabuffer, + priv->rnchannels, + ADC_DMA_CONTROL_WORD); + + at32_dmastart(priv->dma, adc_dmaconvcallback, dev, false); +#endif +} +#endif /* ADC_HAVE_DMA */ + +/**************************************************************************** + * Name: adc_configure + ****************************************************************************/ + +static void adc_configure(struct adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + + /* Turn off the ADC before configuration */ + + adc_enable(priv, false); + + /* Configure voltage regulator if present */ + + adc_voltreg_cfg(priv); + + /* Calibrate ADC - doesn't work for now */ + + adc_calibrate(priv); + + /* Initialize the ADC watchdog */ + + adc_watchdog_cfg(priv); + + /* Initialize the ADC sample time */ + + adc_sampletime_cfg(dev); + + /* Set ADC working mode */ + + adc_mode_cfg(priv); + + /* Configuration of the channel conversions */ + + if (priv->cr_channels > 0) + { + adc_set_ch(dev, 0); + } + +#ifdef ADC_HAVE_INJECTED + /* Configuration of the injected channel conversions after adc enabled */ + + if (priv->cj_channels > 0) + { + adc_inj_set_ch(dev, 0); + } +#endif + + /* ADC common register configuration */ + + adc_common_cfg(priv); + +#ifdef ADC_HAVE_DMA + /* Configure ADC DMA if enabled */ + + if (priv->hasdma) + { + /* Configure ADC DMA */ + + adc_dma_cfg(priv); + + /* Start ADC DMA */ + + adc_dma_start(dev); + } +#endif + +#ifdef HAVE_ADC_RESOLUTION + /* Configure ADC resolution */ + + adc_resolution_set(dev, priv->resolution); +#endif + +#ifdef ADC_HAVE_EXTCFG + /* Configure external event for regular group */ + + adc_extcfg_set(priv, priv->extcfg); +#endif + + /* Enable ADC */ + + adc_enable(priv, true); + +#ifdef ADC_HAVE_JEXTCFG + /* Configure external event for injected group when ADC enabled */ + + adc_jextcfg_set(priv, priv->jextcfg); + +#if defined(HAVE_IP_ADC_V2) + /* For ADC IPv2 there is queue of context for injected conversion. + * JEXTCFG configuration is the second write to JSQR register which means + * configuration is stored on queue. + * We trigger single INJ conversion here to update context. + */ + + adc_inj_startconv(priv, true); +#endif +#endif + + /* Dump regs */ + + adc_dumpregs(priv); +} + +/**************************************************************************** + * Name: adc_reset + * + * Description: + * Reset the ADC device. Called early to initialize the hardware. + * This is called, before adc_setup() and on error conditions. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +static void adc_reset(struct adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + irqstate_t flags; + + ainfo("intf: %d\n", priv->intf); + flags = enter_critical_section(); + + /* Do nothing if ADC instance is currently in use */ + + if (priv->initialized > 0) + { + goto out; + } + +#if defined(HAVE_IP_ADC_V2) + /* Turn off the ADC so we can write the RCC bits */ + + adc_enable(priv, false); +#endif + + /* Only if this is the first initialzied ADC instance in the ADC block */ + +#ifdef HAVE_ADC_CMN_DATA + if (nxmutex_lock(&priv->cmn->lock) < 0) + { + goto out; + } + + if (priv->cmn->refcount == 0) +#endif + { + /* Enable ADC reset state */ + + adc_rccreset(priv, true); + + /* Release ADC from reset state */ + + adc_rccreset(priv, false); + } + +#ifdef HAVE_ADC_CMN_DATA + nxmutex_unlock(&priv->cmn->lock); +#endif + +out: + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: adc_setup + * + * Description: + * Configure the ADC. This method is called the first time that the ADC + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching ADC interrupts. + * Interrupts are all disabled upon return. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +static int adc_setup(struct adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + int ret = OK; + + /* Do nothing when the ADC device is already set up */ + + if (priv->initialized > 0) + { + return OK; + } + + /* Attach the ADC interrupt */ + +#ifndef CONFIG_AT32_ADC_NOIRQ + ret = irq_attach(priv->irq, priv->isr, NULL); + if (ret < 0) + { + ainfo("irq_attach failed: %d\n", ret); + return ret; + } +#endif + + /* Make sure that the ADC device is in the powered up, reset state */ + + adc_reset(dev); + + /* Configure ADC device */ + + adc_configure(dev); + +#ifdef ADC_HAVE_TIMER + /* Configure timer */ + + if (priv->tbase != 0) + { + ret = adc_timinit(priv); + if (ret < 0) + { + aerr("ERROR: adc_timinit failed: %d\n", ret); + } + } +#endif + + /* As default conversion is started here. + * + * NOTE: for ADC IPv2 (J)ADSTART bit must be set to start ADC conversion + * even if hardware trigger is selected. + * This can be done here during the opening of the ADC device + * or later with ANIOC_TRIGGER ioctl call. + */ + +#ifndef CONFIG_AT32_ADC_NO_STARTUP_CONV + /* Start regular conversion */ + + adc_reg_startconv(priv, true); + +# ifdef ADC_HAVE_INJECTED + /* Start injected conversion */ + + adc_inj_startconv(priv, true); +# endif +#endif + +#ifdef HAVE_ADC_CMN_DATA + /* Increase instances counter */ + + ret = nxmutex_lock(&priv->cmn->lock); + if (ret < 0) + { + return ret; + } + + if (priv->cmn->refcount == 0) +#endif + { + /* Enable the ADC interrupt */ + +#ifndef CONFIG_AT32_ADC_NOIRQ + ainfo("Enable the ADC interrupt: irq=%d\n", priv->irq); + up_enable_irq(priv->irq); +#endif + } + +#ifdef HAVE_ADC_CMN_DATA + priv->cmn->refcount += 1; + nxmutex_unlock(&priv->cmn->lock); +#endif + + /* The ADC device is ready */ + + priv->initialized += 1; + + return ret; +} + +/**************************************************************************** + * Name: adc_shutdown + * + * Description: + * Disable the ADC. This method is called when the ADC device is closed. + * This method reverses the operation the setup method. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +static void adc_shutdown(struct adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + + /* Decrement count only when ADC device is in use */ + + if (priv->initialized > 0) + { + priv->initialized -= 1; + } + + /* Shutdown the ADC device only when not in use */ + + if (priv->initialized > 0) + { + return; + } + + /* Disable ADC */ + + adc_enable(priv, false); + +#ifdef HAVE_HSI_CONTROL + adc_enable_hsi(false); +#endif + +#ifdef HAVE_ADC_CMN_DATA + if (nxmutex_lock(&priv->cmn->lock) < 0) + { + return; + } + + if (priv->cmn->refcount <= 1) +#endif + { +#ifndef CONFIG_AT32_ADC_NOIRQ + /* Disable ADC interrupts and detach the ADC interrupt handler */ + + up_disable_irq(priv->irq); + irq_detach(priv->irq); +#endif + + /* Disable and reset the ADC module. + * + * NOTE: The ADC block will be reset to its reset state only if all + * ADC block instances are closed. This means that the closed + * ADC may not be reset which in turn may affect low-power + * applications. (But ADC is turned off here, is not that + * enough?) + */ + + adc_rccreset(priv, true); + } + +#ifdef ADC_HAVE_TIMER + /* Disable timer */ + + if (priv->tbase != 0) + { + adc_timstart(priv, false); + } +#endif + +#ifdef HAVE_ADC_CMN_DATA + /* Decrease instances counter */ + + if (priv->cmn->refcount > 0) + { + priv->cmn->refcount -= 1; + } + + nxmutex_unlock(&priv->cmn->lock); +#endif +} + +/**************************************************************************** + * Name: adc_rxint + * + * Description: + * Call to enable or disable RX interrupts. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +static void adc_rxint(struct adc_dev_s *dev, bool enable) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + uint32_t regval; + + ainfo("intf: %d enable: %d\n", priv->intf, enable ? 1 : 0); + + if (enable) + { + /* Enable the analog watchdog / overrun interrupts, and if no DMA, + * end-of-conversion ADC. + */ + + regval = ADC_IER_ALLINTS; +#ifdef ADC_HAVE_DMA + if (priv->hasdma) + { + regval &= ~(ADC_IER_EOC | ADC_IER_JEOC); + } +#endif + + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, 0, regval); + } + else + { + /* Disable all ADC interrupts */ + + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, ADC_IER_ALLINTS, 0); + } +} + +/**************************************************************************** + * Name: adc_enable_tvref_register + * + * Description: + * Enable/disable the temperature sensor and the VREFINT channel. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * enable - true: Temperature sensor and V REFINT channel enabled + * (ch 16 and 17) + * false: Temperature sensor and V REFINT channel disabled + * (ch 16 and 17) + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#if defined(HAVE_IP_ADC_V1) +static void adc_ioc_enable_tvref_register(struct adc_dev_s *dev, + bool enable) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + +#ifdef HAVE_BASIC_ADC +# if defined(CONFIG_AT32_ADC1) + /* TSVREF bit is only available in the AT32_ADC1_CR2 register. */ + + if (priv->intf == 1) + { + if (enable) + { + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, 0, ADC_CR2_TSVREFE); + } + else + { + adc_modifyreg(priv, AT32_ADC_CR2_OFFSET, ADC_CR2_TSVREFE, 0); + } + } + + ainfo("AT32_ADC_CR2 value: 0x%08" PRIx32 "\n", + adc_getreg(priv, AT32_ADC_CR2_OFFSET)); +# endif /* CONFIG_AT32_ADC1 */ +#else /* !HAVE_BASIC_ADC */ + if (enable) + { + adccmn_modifyreg(priv, AT32_ADC_CCR_OFFSET, 0, ADC_CCR_TSVREFE); + } + else + { + adccmn_modifyreg(priv, AT32_ADC_CCR_OFFSET, ADC_CCR_TSVREFE, 0); + } + + ainfo("AT32_ADC_CCR value: 0x%08" PRIx32 "\n", + adccmn_getreg(priv, AT32_ADC_CCR_OFFSET)); +#endif +} +#endif /* HAVE_IP_ADC_V1 */ + +/**************************************************************************** + * Name: adc_resolution_set + ****************************************************************************/ + +#ifdef HAVE_ADC_RESOLUTION +static int adc_resolution_set(struct adc_dev_s *dev, uint8_t res) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + int ret = OK; + + /* Check input */ + + if (res > 3) + { + ret = -EINVAL; + goto errout; + } + + /* Modify appropriate register */ + +#if defined(HAVE_IP_ADC_V1) + adc_modifyreg(priv, AT32_ADC_CR1_OFFSET, ADC_CR1_RES_MASK, + res << ADC_CR1_RES_SHIFT); +#elif defined(HAVE_IP_ADC_V2) + adc_modifyreg(priv, AT32_ADC_CFGR1_OFFSET, ADC_CFGR1_RES_MASK, + res << ADC_CFGR1_RES_SHIFT); +#endif + +errout: + return ret; +} +#endif + +/**************************************************************************** + * Name: adc_extcfg_set + ****************************************************************************/ + +#ifdef ADC_HAVE_EXTCFG +static int adc_extcfg_set(struct at32_dev_s *priv, uint32_t extcfg) +{ + uint32_t exten = 0; + uint32_t extsel = 0; + uint32_t setbits = 0; + uint32_t clrbits = 0; + + /* Get EXTEN and EXTSEL from input */ + + exten = extcfg & ADC_EXTREG_EXTEN_MASK; + extsel = extcfg & ADC_EXTREG_EXTSEL_MASK; + + /* EXTSEL selection: These bits select the external event used + * to trigger the start of conversion of a regular group. NOTE: + * + * - The position with of the EXTSEL field varies from one AT32 MCU + * to another. + * - The width of the EXTSEL field varies from one AT32 MCU to another. + */ + + if (exten > 0) + { + setbits = extsel | exten; + clrbits = ADC_EXTREG_EXTEN_MASK | ADC_EXTREG_EXTSEL_MASK; + + ainfo("Initializing extsel = 0x%08" PRIx32 "\n", extsel); + + /* Write register */ + + adc_modifyreg(priv, AT32_ADC_EXTREG_OFFSET, clrbits, setbits); + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: adc_jextcfg_set + ****************************************************************************/ + +#ifdef ADC_HAVE_JEXTCFG +static int adc_jextcfg_set(struct at32_dev_s *priv, uint32_t jextcfg) +{ + uint32_t jexten = 0; + uint32_t jextsel = 0; + uint32_t setbits = 0; + uint32_t clrbits = 0; + + /* Get JEXTEN and JEXTSEL from input */ + + jexten = jextcfg & ADC_JEXTREG_JEXTEN_MASK; + jextsel = jextcfg & ADC_JEXTREG_JEXTSEL_MASK; + + /* JEXTSEL selection: These bits select the external event used + * to trigger the start of conversion of a injected group. NOTE: + * + * - The position with of the JEXTSEL field varies from one AT32 MCU + * to another. + * - The width of the JEXTSEL field varies from one AT32 MCU to another. + */ + + if (jexten > 0) + { + setbits = jexten | jextsel; + clrbits = ADC_JEXTREG_JEXTEN_MASK | ADC_JEXTREG_JEXTSEL_MASK; + + ainfo("Initializing jextsel = 0x%08" PRIx32 "\n", jextsel); + + /* Write register */ + + adc_modifyreg(priv, AT32_ADC_JEXTREG_OFFSET, clrbits, setbits); + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: adc_dumpregs + ****************************************************************************/ + +static void adc_dumpregs(struct at32_dev_s *priv) +{ + UNUSED(priv); + +#if defined(HAVE_IP_ADC_V2) + ainfo("ISR: 0x%08" PRIx32 " IER: 0x%08" PRIx32 + " CR: 0x%08" PRIx32 " CFGR1: 0x%08" PRIx32 "\n", + adc_getreg(priv, AT32_ADC_ISR_OFFSET), + adc_getreg(priv, AT32_ADC_IER_OFFSET), + adc_getreg(priv, AT32_ADC_CR_OFFSET), + adc_getreg(priv, AT32_ADC_CFGR1_OFFSET)); +#else + ainfo("SR: 0x%08" PRIx32 " CR1: 0x%08" PRIx32 + " CR2: 0x%08" PRIx32 "\n", + adc_getreg(priv, AT32_ADC_SR_OFFSET), + adc_getreg(priv, AT32_ADC_CR1_OFFSET), + adc_getreg(priv, AT32_ADC_CR2_OFFSET)); +#endif + + ainfo("SQR1: 0x%08" PRIx32 " SQR2: 0x%08" PRIx32 + " SQR3: 0x%08" PRIx32 "\n", + adc_getreg(priv, AT32_ADC_SQR1_OFFSET), + adc_getreg(priv, AT32_ADC_SQR2_OFFSET), + adc_getreg(priv, AT32_ADC_SQR3_OFFSET)); + + ainfo("SMPR1: 0x%08" PRIx32 " SMPR2: 0x%08" PRIx32 "\n", + adc_getreg(priv, AT32_ADC_SMPR1_OFFSET), + adc_getreg(priv, AT32_ADC_SMPR2_OFFSET)); + +#if defined(AT32_ADC_SQR4_OFFSET) + ainfo("SQR4: 0x%08" PRIx32 "\n", + adc_getreg(priv, AT32_ADC_SQR4_OFFSET)); +#endif + +#if defined(AT32_ADC_SQR5_OFFSET) + ainfo("SQR5: 0x%08" PRIx32 "\n", + adc_getreg(priv, AT32_ADC_SQR5_OFFSET)); +#endif + +#ifdef ADC_HAVE_INJECTED + ainfo("JSQR: 0x%08" PRIx32 "\n", adc_getreg(priv, AT32_ADC_JSQR_OFFSET)); +#endif + +#if defined(HAVE_IP_ADC_V2) || (defined(HAVE_IP_ADC_V1) && !defined(HAVE_BASIC_ADC)) + ainfo("CCR: 0x%08" PRIx32 "\n", + adccmn_getreg(priv, AT32_ADC_CCR_OFFSET)); +#endif +} + +/**************************************************************************** + * Name: adc_enable_vbat_channel + * + * Description: + * Enable/disable the Vbat voltage measurement channel. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * enable - true: Vbat input channel enabled (ch 18) + * false: Vbat input channel disabled (ch 18) + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef HAVE_ADC_VBAT +static void adc_enable_vbat_channel(struct adc_dev_s *dev, bool enable) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + + if (enable) + { + adccmn_modifyreg(priv, AT32_ADC_CCR_OFFSET, 0, ADC_CCR_VBATEN); + } + else + { + adccmn_modifyreg(priv, AT32_ADC_CCR_OFFSET, ADC_CCR_VBATEN, 0); + } + + ainfo("AT32_ADC_CCR value: 0x%08" PRIx32 "\n", + adccmn_getreg(priv, AT32_ADC_CCR_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: adc_ioc_change_sleep_between_opers + * + * Description: + * Changes PDI and PDD bits to save battery. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * cmd - command + * arg - arguments passed with command + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef HAVE_ADC_POWERDOWN +static int adc_ioc_change_sleep_between_opers(struct adc_dev_s *dev, + int cmd, bool arg) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + int ret = OK; + + adc_enable(priv, false); + + switch (cmd) + { + case IO_ENABLE_DISABLE_PDI: + adc_power_down_idle(priv, arg); + break; + + case IO_ENABLE_DISABLE_PDD: + adc_power_down_delay(priv, arg); + break; + + case IO_ENABLE_DISABLE_PDD_PDI: + adc_power_down_idle(priv, arg); + adc_power_down_delay(priv, arg); + break; + + default: + ainfo("unknown cmd: %d\n", cmd); + break; + } + + adc_enable(priv, true); + + return ret; +} +#endif + +/**************************************************************************** + * Name: adc_ioc_enable_awd_int + * + * Description: + * Turns ON/OFF ADC analog watchdog interrupt. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * arg - true: Turn ON interrupt + * false: Turn OFF interrupt + * + * Returned Value: + * + ****************************************************************************/ + +static void adc_ioc_enable_awd_int(struct at32_dev_s *priv, bool enable) +{ + if (enable) + { + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, 0, ADC_IER_AWD); + } + else + { + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, ADC_IER_AWD, 0); + } +} + +/**************************************************************************** + * Name: adc_ioc_enable_eoc_int + * + * Description: + * Turns ON/OFF ADC EOC interrupt. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * arg - true: Turn ON interrupt + * false: Turn OFF interrupt + * + * Returned Value: + * + ****************************************************************************/ + +static void adc_ioc_enable_eoc_int(struct at32_dev_s *priv, bool enable) +{ + if (enable) + { + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, 0, ADC_IER_EOC); + } + else + { + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, ADC_IER_EOC, 0); + } +} + +/**************************************************************************** + * Name: adc_ioc_enable_jeoc_int + * + * Description: + * Turns ON/OFF ADC injected channels interrupt. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * arg - true: Turn ON interrupt + * false: Turn OFF interrupt + * + * Returned Value: + * + ****************************************************************************/ + +static void adc_ioc_enable_jeoc_int(struct at32_dev_s *priv, + bool enable) +{ + if (enable) + { + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, 0, ADC_IER_JEOC); + } + else + { + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, ADC_IER_JEOC, 0); + } +} + +/**************************************************************************** + * Name: adc_ioc_enable_ovr_int + * + * Description: + * Turns ON/OFF ADC overrun interrupt. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * arg - true: Turn ON interrupt + * false: Turn OFF interrupt + * + * Returned Value: + * + ****************************************************************************/ + +static void adc_ioc_enable_ovr_int(struct at32_dev_s *priv, bool enable) +{ + if (enable) + { + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, 0, ADC_IER_OVR); + } + else + { + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, ADC_IER_OVR, 0); + } +} + +/**************************************************************************** + * Name: adc_ioc_change_ints + * + * Description: + * Turns ON/OFF ADC interrupts. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * cmd - command + * arg - arguments passed with command + * + * Returned Value: + * + ****************************************************************************/ + +static int adc_ioc_change_ints(struct adc_dev_s *dev, int cmd, bool arg) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + int ret = OK; + + switch (cmd) + { + case IO_ENABLE_DISABLE_AWDIE: + adc_ioc_enable_awd_int(priv, arg); + break; + + case IO_ENABLE_DISABLE_EOCIE: + adc_ioc_enable_eoc_int(priv, arg); + break; + + case IO_ENABLE_DISABLE_JEOCIE: + adc_ioc_enable_jeoc_int(priv, arg); + break; + + case IO_ENABLE_DISABLE_OVRIE: + adc_ioc_enable_ovr_int(priv, arg); + break; + + case IO_ENABLE_DISABLE_ALL_INTS: + adc_ioc_enable_awd_int(priv, arg); + adc_ioc_enable_eoc_int(priv, arg); + adc_ioc_enable_jeoc_int(priv, arg); + adc_ioc_enable_ovr_int(priv, arg); + break; + + default: + ainfo("unknown cmd: %d\n", cmd); + break; + } + + return ret; +} + +/**************************************************************************** + * Name: adc_enable_hsi + * + * Description: + * Enable/Disable HSI clock + * + * Input Parameters: + * enable - true : HSI clock for ADC enabled + * false : HSI clock for ADC disabled + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef HAVE_HSI_CONTROL +static void adc_enable_hsi(bool enable) +{ + if (enable) + { + /* Enable the HSI */ + + at32_modifyreg32(AT32_RCC_CR, 0, RCC_CR_HSION); + while ((getreg32(AT32_RCC_CR) & RCC_CR_HSIRDY) == 0); + } + else + { + /* Disable the HSI */ + + at32_modifyreg32(AT32_RCC_CR, RCC_CR_HSION, 0); + } +} +#endif + +/**************************************************************************** + * Name: adc_sqrbits + ****************************************************************************/ + +static uint32_t adc_sqrbits(struct at32_dev_s *priv, int first, + int last, int offset) +{ + uint32_t bits = 0; + int i; + + for (i = first - 1; + i < priv->rnchannels && i < last; + i++, offset += ADC_SQ_OFFSET) + { + bits |= (uint32_t)priv->r_chanlist[i] << offset; + } + + return bits; +} + +/**************************************************************************** + * Name: adc_set_ch + * + * Description: + * Sets the ADC channel. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * ch - ADC channel number + 1. 0 reserved for all configured channels + * + * Returned Value: + * int - errno + * + ****************************************************************************/ + +static int adc_set_ch(struct adc_dev_s *dev, uint8_t ch) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + uint32_t bits; + int i; + + if (ch == 0) + { + priv->current = 0; + priv->rnchannels = priv->cr_channels; + } + else + { + for (i = 0; i < priv->cr_channels && priv->r_chanlist[i] != ch - 1; + i++); + + if (i >= priv->cr_channels) + { + return -ENODEV; + } + + priv->current = i; + priv->rnchannels = 1; + } + +#ifdef AT32_ADC_SQR5_OFFSET + bits = adc_sqrbits(priv, ADC_SQR5_FIRST, ADC_SQR5_LAST, + ADC_SQR5_SQ_OFFSET); + adc_modifyreg(priv, AT32_ADC_SQR5_OFFSET, ~ADC_SQR5_RESERVED, bits); +#endif + +#ifdef AT32_ADC_SQR4_OFFSET + bits = adc_sqrbits(priv, ADC_SQR4_FIRST, ADC_SQR4_LAST, + ADC_SQR4_SQ_OFFSET); + adc_modifyreg(priv, AT32_ADC_SQR4_OFFSET, ~ADC_SQR4_RESERVED, bits); +#endif + + bits = adc_sqrbits(priv, ADC_SQR3_FIRST, ADC_SQR3_LAST, + ADC_SQR3_SQ_OFFSET); + adc_modifyreg(priv, AT32_ADC_SQR3_OFFSET, ~ADC_SQR3_RESERVED, bits); + + bits = adc_sqrbits(priv, ADC_SQR2_FIRST, ADC_SQR2_LAST, + ADC_SQR2_SQ_OFFSET); + adc_modifyreg(priv, AT32_ADC_SQR2_OFFSET, ~ADC_SQR2_RESERVED, bits); + + bits = ((uint32_t)priv->rnchannels - 1) << ADC_SQR1_L_SHIFT; + bits |= adc_sqrbits(priv, ADC_SQR1_FIRST, + ADC_SQR1_LAST, ADC_SQR1_SQ_OFFSET); + adc_modifyreg(priv, AT32_ADC_SQR1_OFFSET, ~ADC_SQR1_RESERVED, bits); + + return OK; +} + +#ifdef ADC_HAVE_INJECTED + +/**************************************************************************** + * Name: adc_inj_set_ch + ****************************************************************************/ + +static int adc_inj_set_ch(struct adc_dev_s *dev, uint8_t ch) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + uint32_t clrbits; + uint32_t setbits; + int i; + + /* Configure injected sequence length */ + + setbits = ADC_JSQR_JL(priv->cj_channels); + clrbits = ADC_JEXTREG_JEXTSEL_MASK | ADC_JSQR_JL_MASK; + + /* Configure injected channels */ + + for (i = 0 ; i < priv->cj_channels; i += 1) + { +#if defined(HAVE_IP_ADC_V1) + /* Injected channels sequence for for ADC IPv1: + * + * 1 2 3 4 + * IL=1: JSQR4, + * IL=2: JSQR3, JSQR4 + * IL=3: JSQR2, JSQR3, JSQR4 + * IL=4: JSQR1, JSQR2, JSQR3, JSQR4 + */ + + setbits |= (priv->j_chanlist[priv->cj_channels - 1 - i] << + (ADC_JSQR_JSQ4_SHIFT - ADC_JSQR_JSQ_SHIFT * i)); +#else + setbits |= priv->j_chanlist[i] << (ADC_JSQR_JSQ1_SHIFT + + ADC_JSQR_JSQ_SHIFT * i); +#endif + } + + /* Write register */ + + adc_modifyreg(priv, AT32_ADC_JSQR_OFFSET, clrbits, setbits); + + return OK; +} +#endif + +/**************************************************************************** + * Name: adc_ioctl + * + * Description: + * All ioctl calls will be routed through this method. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * cmd - command + * arg - arguments passed with command + * + * Returned Value: + * + ****************************************************************************/ + +static int adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + int ret = OK; + + switch (cmd) + { + case ANIOC_TRIGGER: + { + /* Start regular conversion if regular channels configured */ + + if (priv->anioc_trg & ANIOC_TRIGGER_REGULAR) + { + if (priv->cr_channels > 0) + { + adc_reg_startconv(priv, true); + } + } + +#ifdef ADC_HAVE_INJECTED + /* Start injected conversion if injected channels configured */ + + if (priv->anioc_trg & ANIOC_TRIGGER_INJECTED) + { + if (priv->cj_channels > 0) + { + adc_inj_startconv(priv, true); + } + } +#endif + + break; + } + + case ANIOC_GET_NCHANNELS: + { + /* Return the number of configured channels */ + + ret = priv->rnchannels; + } + break; + + case IO_TRIGGER_REG: + { + /* Start regular conversion if regular channels configured */ + + if (priv->cr_channels > 0) + { + adc_reg_startconv(priv, true); + } + + break; + } + +#ifdef ADC_HAVE_INJECTED + case IO_TRIGGER_INJ: + { + /* Start injected conversion if injected channels configured */ + + if (priv->cj_channels > 0) + { + adc_inj_startconv(priv, true); + } + + break; + } +#endif + + case IO_ENABLE_DISABLE_AWDIE: + case IO_ENABLE_DISABLE_EOCIE: + case IO_ENABLE_DISABLE_JEOCIE: + case IO_ENABLE_DISABLE_OVRIE: + case IO_ENABLE_DISABLE_ALL_INTS: + { + adc_ioc_change_ints(dev, cmd, *(bool *)arg); + break; + } + +#if defined(HAVE_IP_ADC_V1) + case IO_ENABLE_TEMPER_VOLT_CH: + { + adc_ioc_enable_tvref_register(dev, *(bool *)arg); + break; + } +#endif + +#ifdef HAVE_ADC_VBAT + case IO_ENABLE_DISABLE_VBAT_CH: + { + adc_enable_vbat_channel(dev, *(bool *)arg); + break; + } +#endif + +#ifdef HAVE_ADC_POWERDOWN + case IO_ENABLE_DISABLE_PDI: + case IO_ENABLE_DISABLE_PDD: + case IO_ENABLE_DISABLE_PDD_PDI: + { + adc_ioc_change_sleep_between_opers(dev, cmd, *(bool *)arg); + break; + } +#endif + + case IO_STOP_ADC: + { + adc_enable(priv, false); +#ifdef HAVE_HSI_CONTROL + adc_enable_hsi(false); +#endif + break; + } + + case IO_START_ADC: + { +#ifdef HAVE_HSI_CONTROL + adc_enable_hsi(true); +#endif + adc_enable(priv, true); + break; + } + + case IO_START_CONV: + { + uint8_t ch = ((uint8_t)arg); + + ret = adc_set_ch(dev, ch); + if (ret < 0) + { + return ret; + } + +#ifdef CONFIG_ADC + if (ch) + { + /* Clear fifo if upper-half driver enabled */ + + dev->ad_recv.af_head = 0; + dev->ad_recv.af_tail = 0; + } +#endif + + adc_reg_startconv(priv, true); + break; + } + + default: + { + aerr("ERROR: Unknown cmd: %d\n", cmd); + ret = -ENOTTY; + break; + } + } + + return ret; +} + +#ifndef CONFIG_AT32_ADC_NOIRQ + +/**************************************************************************** + * Name: adc_interrupt + * + * Description: + * Common ADC interrupt handler. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +static int adc_interrupt(struct adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev->ad_priv; + uint32_t regval; + uint32_t pending; + int32_t data; + + regval = adc_getreg(priv, AT32_ADC_ISR_OFFSET); + pending = regval & ADC_ISR_ALLINTS; + if (pending == 0) + { + return OK; + } + + /* Identifies the interruption AWD, OVR or EOC */ + + if ((regval & ADC_ISR_AWD) != 0) + { + awarn("WARNING: Analog Watchdog, Value converted out of range!\n"); + } + + if ((regval & ADC_ISR_OVR) != 0) + { + awarn("WARNING: Overrun has occurred!\n"); + } + + /* EOC: End of conversion */ + + if ((regval & ADC_ISR_EOC) != 0) + { + /* Read the converted value and clear EOC bit + * (It is cleared by reading the ADC_DR) + */ + + data = adc_getreg(priv, AT32_ADC_DR_OFFSET) & ADC_DR_RDATA_MASK; + + /* Verify that the upper-half driver has bound its callback functions */ + + if (priv->cb != NULL) + { + /* Give the ADC data to the ADC driver. The ADC receive() method + * accepts 3 parameters: + * + * 1) The first is the ADC device instance for this ADC block. + * 2) The second is the channel number for the data, and + * 3) The third is the converted data for the channel. + */ + + DEBUGASSERT(priv->cb->au_receive != NULL); + priv->cb->au_receive(dev, priv->r_chanlist[priv->current], data); + } + + /* Set the channel number of the next channel that will complete + * conversion. + */ + + priv->current++; + + if (priv->current >= priv->rnchannels) + { + /* Restart the conversion sequence from the beginning */ + + priv->current = 0; + } + } + + /* Clear pending interrupts */ + + adc_putreg(priv, AT32_ADC_ISR_OFFSET, pending); + + return OK; +} + +/**************************************************************************** + * Name: adc1_interrupt + * + * Description: + * ADC interrupt handler for the AT32 L15XX family. + * + * Input Parameters: + * irq - The IRQ number that generated the interrupt. + * context - Architecture specific register save information. + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(AT32_IRQ_ADC1) +static int adc1_interrupt(int irq, void *context, void *arg) +{ + adc_interrupt(&g_adcdev1); + + return OK; +} +#endif + +/**************************************************************************** + * Name: adc12_interrupt + * + * Description: + * ADC1/2 interrupt handler for the AT32 F1/F3 families. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(AT32_IRQ_ADC12) && \ + (defined(CONFIG_AT32_ADC1) || defined(CONFIG_AT32_ADC2)) +static int adc12_interrupt(int irq, void *context, void *arg) +{ +#ifdef CONFIG_AT32_ADC1 + adc_interrupt(&g_adcdev1); +#endif + +#ifdef CONFIG_AT32_ADC2 + adc_interrupt(&g_adcdev2); +#endif + + return OK; +} +#endif + +/**************************************************************************** + * Name: adc3_interrupt + * + * Description: + * ADC3 interrupt handler for the AT32 F1 family. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(AT32_IRQ_ADC3) && defined(CONFIG_AT32_ADC3) +static int adc3_interrupt(int irq, void *context, void *arg) +{ + adc_interrupt(&g_adcdev3); + + return OK; +} +#endif + +/**************************************************************************** + * Name: adc123_interrupt + * + * Description: + * ADC1/2/3 interrupt handler for the AT32 F2/F4 families. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(AT32_IRQ_ADC) +static int adc123_interrupt(int irq, void *context, void *arg) +{ +#ifdef CONFIG_AT32_ADC1 + adc_interrupt(&g_adcdev1); +#endif + +#ifdef CONFIG_AT32_ADC2 + adc_interrupt(&g_adcdev2); +#endif + +#ifdef CONFIG_AT32_ADC3 + adc_interrupt(&g_adcdev3); +#endif + + return OK; +} +#endif +#endif /* CONFIG_AT32_ADC_NOIRQ */ + +#ifdef CONFIG_AT32_ADC_LL_OPS + +/**************************************************************************** + * Name: adc_llops_setup + ****************************************************************************/ + +static int adc_llops_setup(struct at32_adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + return adc_setup(priv->dev); +} + +/**************************************************************************** + * Name: adc_llops_shutdown + ****************************************************************************/ + +static void adc_llops_shutdown(struct at32_adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + adc_shutdown(priv->dev); +} + +/**************************************************************************** + * Name: adc_intack + ****************************************************************************/ + +static void adc_intack(struct at32_adc_dev_s *dev, uint32_t source) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + /* Clear pending interrupts */ + +#ifdef HAVE_IP_ADC_V2 + /* Cleared by writing 1 to it */ + + adc_putreg(priv, AT32_ADC_ISR_OFFSET, (source & ADC_ISR_ALLINTS)); +#else + /* Cleared by writing 0 to it */ + + adc_modifyreg(priv, AT32_ADC_ISR_OFFSET, (source & ADC_ISR_ALLINTS), 0); +#endif +} + +/**************************************************************************** + * Name: adc_inten + ****************************************************************************/ + +static void adc_inten(struct at32_adc_dev_s *dev, uint32_t source) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + /* Enable interrupts */ + + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, 0, (source & ADC_IER_ALLINTS)); +} + +/**************************************************************************** + * Name: adc_intdis + ****************************************************************************/ + +static void adc_intdis(struct at32_adc_dev_s *dev, uint32_t source) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + /* Disable interrupts */ + + adc_modifyreg(priv, AT32_ADC_IER_OFFSET, (source & ADC_IER_ALLINTS), 0); +} + +/**************************************************************************** + * Name: adc_ackget + ****************************************************************************/ + +static uint32_t adc_intget(struct at32_adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + uint32_t regval; + uint32_t pending; + + regval = adc_getreg(priv, AT32_ADC_ISR_OFFSET); + pending = regval & ADC_ISR_ALLINTS; + + return pending; +} + +/**************************************************************************** + * Name: adc_regget + ****************************************************************************/ + +static uint32_t adc_regget(struct at32_adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + return adc_getreg(priv, AT32_ADC_DR_OFFSET) & ADC_DR_RDATA_MASK; +} + +/**************************************************************************** + * Name: adc_llops_reg_startconv + ****************************************************************************/ + +static void adc_llops_reg_startconv(struct at32_adc_dev_s *dev, + bool enable) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + adc_reg_startconv(priv, enable); +} + +/**************************************************************************** + * Name: adc_offset_set + ****************************************************************************/ + +#ifdef HAVE_IP_ADC_V2 +static int adc_offset_set(struct at32_adc_dev_s *dev, uint8_t ch, + uint8_t i, uint16_t offset) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + uint32_t regval = 0; + uint32_t reg = 0; + int ret = OK; + + if (i >= 4) + { + /* There are only four offset registers. */ + + ret = -E2BIG; + goto errout; + } + + reg = AT32_ADC_OFR1_OFFSET + i * 4; + + regval = ADC_OFR_OFFSETY_EN; + adc_putreg(priv, reg, regval); + + regval |= ADC_OFR_OFFSETY_CH(ch) | ADC_OFR_OFFSETY(offset); + adc_putreg(priv, reg, regval); + +errout: + return ret; +} +#else /* HAVE_IP_ADC_V1 */ +static int adc_offset_set(struct at32_adc_dev_s *dev, uint8_t ch, + uint8_t i, uint16_t offset) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + uint32_t reg = 0; + int ret = OK; + + /* WARNING: Offset only for injected channels! */ + + UNUSED(ch); + + if (i >= 4) + { + /* There are only four offset registers. */ + + ret = -E2BIG; + goto errout; + } + + reg = AT32_ADC_JOFR1_OFFSET + i * 4; + + adc_putreg(priv, reg, offset); + +errout: + return ret; +} +#endif + +/**************************************************************************** + * Name: adc_llops_extcfg_set + ****************************************************************************/ + +#ifdef ADC_HAVE_EXTCFG +static void adc_llops_extcfg_set(struct at32_adc_dev_s *dev, + uint32_t extcfg) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + adc_extcfg_set(priv, extcfg); +} +#endif + +/**************************************************************************** + * Name: adc_llops_jextcfg_set + ****************************************************************************/ + +#ifdef ADC_HAVE_JEXTCFG +static void adc_llops_jextcfg_set(struct at32_adc_dev_s *dev, + uint32_t jextcfg) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + adc_jextcfg_set(priv, jextcfg); +} +#endif + +/**************************************************************************** + * Name: adc_regbufregister + ****************************************************************************/ + +#ifdef ADC_HAVE_DMA +static int adc_regbufregister(struct at32_adc_dev_s *dev, + uint16_t *buffer, uint8_t len) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + at32_dmasetup(priv->dma, + priv->base + AT32_ADC_DR_OFFSET, + (uint32_t)buffer, + len, + ADC_DMA_CONTROL_WORD); + + /* No DMA callback */ + + at32_dmastart(priv->dma, NULL, dev, false); + + return OK; +} +#endif /* ADC_HAVE_DMA */ + +/**************************************************************************** + * Name: adc_injget + ****************************************************************************/ + +#ifdef ADC_HAVE_INJECTED +static uint32_t adc_injget(struct at32_adc_dev_s *dev, uint8_t chan) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + uint32_t regval = 0; + + if (chan > (priv->cj_channels - 1)) + { + /* REVISIT: return valute with MSB set to indicate error ? */ + + goto errout; + } + + regval = adc_getreg(priv, AT32_ADC_JDR1_OFFSET + 4 * (chan)) & + ADC_JDR_JDATA_MASK; + +errout: + return regval; +} + +/**************************************************************************** + * Name: adc_llops_inj_startconv + ****************************************************************************/ + +static void adc_llops_inj_startconv(struct at32_adc_dev_s *dev, + bool enable) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + adc_inj_startconv(priv, enable); +} + +#endif /* ADC_HAVE_INJECTED */ + +/**************************************************************************** + * Name: adc_sampletime_write + * + * Description: + * Writes previously defined values into ADC_SMPRx registers. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_ADC_CHANGE_SAMPLETIME +static void adc_sampletime_write(struct at32_adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + uint32_t value = 0; + uint8_t i; + uint8_t shift; + + /* Sampling time individually for each channel. + * It's different for families. + */ + + for (i = 0, shift = 0; i < priv->adc_channels; i++) + { + value |= priv->sample_rate[i] << (shift * 3); + switch (i) + { +#if defined(AT32_ADC_SMPR0_OFFSET) && defined(AT32_ADC_SMPR3_OFFSET) + case 9: + { + adc_putreg(priv, AT32_ADC_SMPR3_OFFSET, value); + shift = 0; + value = 0; + break; + } + + case 19: + { + adc_putreg(priv, AT32_ADC_SMPR2_OFFSET, value); + shift = 0; + value = 0; + break; + } + + case 29: + { + adc_putreg(priv, AT32_ADC_SMPR1_OFFSET, value); + shift = 0; + value = 0; + break; + } + + case (ADC_CHANNELS_NUMBER - 1): + { + adc_putreg(priv, AT32_ADC_SMPR0_OFFSET, value); + shift = 0; + value = 0; + break; + } + +#elif defined(AT32_ADC_SMPR1_OFFSET) && defined(AT32_ADC_SMPR2_OFFSET) + case (ADC_CHANNELS_NUMBER - 1): + { + adc_putreg(priv, AT32_ADC_SMPR2_OFFSET, value); + shift = 0; + value = 0; + break; + } + + case 9: + { + adc_putreg(priv, AT32_ADC_SMPR1_OFFSET, value); + shift = 0; + value = 0; + break; + } +#else +# error "Not supported SMPRx configuration" +#endif + + default: + { + shift++; + break; + } + } + } +} + +/**************************************************************************** + * Name: adc_sampletime_set + * + * Description: + * Changes sample times for specified channels. This method + * doesn't make any register writing. So, it's only stores the information. + * Values provided by user will be written in registers only on the next + * ADC peripheral start, as it was told to do in manual. However, before + * very first start, user can call this method and override default values + * either for every channels or for only some predefined by user channel(s) + * + * Input Parameters: + * dev - pointer to the adc device structure + * time_samples - pointe to the adc sample time configuration data + * + * Returned Value: + * None + * + ****************************************************************************/ + +void adc_sampletime_set(struct at32_adc_dev_s *dev, + struct adc_sample_time_s *time_samples) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + uint8_t ch_index; + uint8_t i; + + /* Check if user wants to assign the same value for all channels + * or just wants to change sample time values for certain channels + */ + + if (time_samples->all_same) + { + memset(priv->sample_rate, time_samples->all_ch_sample_time, + ADC_CHANNELS_NUMBER); + } + else + { + for (i = 0; i < time_samples->channels_nbr; i++) + { + ch_index = time_samples->channel[i].channel; + if (ch_index >= ADC_CHANNELS_NUMBER) + { + break; + } + + priv->sample_rate[ch_index] = time_samples->channel[i].sample_time; + } + } +} +#endif /* CONFIG_AT32_ADC_CHANGE_SAMPLETIME */ + +/**************************************************************************** + * Name: adc_llops_dumpregs + ****************************************************************************/ + +static void adc_llops_dumpregs(struct at32_adc_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + adc_dumpregs(priv); +} + +/**************************************************************************** + * Name: adc_llops_multicfg + * + * IMPORTANT: this interface is allowed only when the ADCs are disabled! + * + ****************************************************************************/ + +static int adc_llops_multicfg(struct at32_adc_dev_s *dev, uint8_t mode) +#if defined(HAVE_IP_ADC_V2) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + int ret = OK; + uint32_t setbits = 0; + uint32_t clrbits = 0; + + switch (mode) + { + case ADC_MULTIMODE_INDEP: + setbits = ADC_CCR_DUAL_IND; + break; + + case ADC_MULTIMODE_RSISM2: + setbits = ADC_CCR_DUAL_SIMALT; + break; + + case ADC_MULTIMODE_RSATM2: + setbits = ADC_CCR_DUAL_SIMALT; + break; + + case ADC_MULTIMODE_IMIS2: + setbits = ADC_CCR_DUAL_INTINJ; + break; + + case ADC_MULTIMODE_ISM2: + setbits = ADC_CCR_DUAL_INJECTED; + break; + + case ADC_MULTIMODE_RSM2: + setbits = ADC_CCR_DUAL_SIM; + break; + + case ADC_MULTIMODE_IM2: + setbits = ADC_CCR_DUAL_INTERLEAVE; + break; + + case ADC_MULTIMODE_ATM2: + setbits = ADC_CCR_DUAL_ALT; + break; + + default: + ret = -EINVAL; + goto errout; + } + + clrbits = ADC_CCR_DUAL_MASK; + adccmn_modifyreg(priv, AT32_ADC_CCR_OFFSET, clrbits, setbits); + +errout: + return ret; +} +#elif defined(HAVE_IP_ADC_V1) && !defined(HAVE_BASIC_ADC) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + int ret = OK; + uint32_t setbits = 0; + uint32_t clrbits = 0; + + switch (mode) + { + case ADC_MULTIMODE_INDEP: + setbits = ADC_CCR_MULTI_NONE; + break; + + case ADC_MULTIMODE_RSISM2: + setbits = ADC_CCR_MULTI_RSISM2; + break; + + case ADC_MULTIMODE_RSATM2: + setbits = ADC_CCR_MULTI_RSATM2; + break; + + case ADC_MULTIMODE_ISM2: + setbits = ADC_CCR_MULTI_ISM2; + break; + + case ADC_MULTIMODE_RSM2: + setbits = ADC_CCR_MULTI_ISM2; + break; + + case ADC_MULTIMODE_IM2: + setbits = ADC_CCR_MULTI_IM2; + break; + + case ADC_MULTIMODE_ATM2: + setbits = ADC_CCR_MULTI_ATM2; + break; + + case ADC_MULTIMODE_RSISM3: + setbits = ADC_CCR_MULTI_RSISM3; + break; + + case ADC_MULTIMODE_RSATM3: + setbits = ADC_CCR_MULTI_RSATM3; + break; + + case ADC_MULTIMODE_ISM3: + setbits = ADC_CCR_MULTI_ISM3; + break; + + case ADC_MULTIMODE_RSM3: + setbits = ADC_CCR_MULTI_ISM3; + break; + + case ADC_MULTIMODE_IM3: + setbits = ADC_CCR_MULTI_IM3; + break; + + case ADC_MULTIMODE_ATM3: + setbits = ADC_CCR_MULTI_ATM3; + break; + + case ADC_MULTIMODE_IMIS2: + case ADC_MULTIMODE_IMIS3: + default: + ret = -EINVAL; + goto errout; + } + + clrbits = ADC_CCR_MULTI_MASK; + adccmn_modifyreg(priv, AT32_ADC_CCR_OFFSET, clrbits, setbits); + +errout: + return ret; +} +#else /* ADV IPv1 BASIC */ +{ + if (mode != ADC_MULTIMODE_INDEP) + { + return -EINVAL; + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: adc_llops_enable + ****************************************************************************/ + +static void adc_llops_enable(struct at32_adc_dev_s *dev, bool enable) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + adc_enable(priv, enable); +} + +#endif /* CONFIG_AT32_ADC_LL_OPS */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_adcinitialize + * + * Description: + * Initialize the ADC. + * + * The logic allow initialize ADC regular and injected channels. + * + * The number of injected channels for given ADC is selected from Kconfig + * with CONFIG_AT32_ADCx_INJECTED_CHAN definitions + * + * The number of regular channels is obtained from the equation: + * + * cr_channels = channels - cj_channels + * + * where: + * cr_channels - regular channels + * cj_channels - injected channels + * channels - this function parameter + * + * The chanlist array store both regular channels and injected channels + * configuration so that regular channels are the first in order: + * + * # regular channels start from here + * chanlist[0] -> ADC_SQRx_SQ1 + * chanlist[1] -> ADC_SQRx_SQ2 + * ... + * # injected channels start from here + * chanlist[channels - (y - 1)] -> ADC_JSQR_JSQ1 + * ... + * chanlist[channels] -> ADC_JSQR_ISQy + * + * where: + * y = CONFIG_AT32_ADCx_INJECTED_CHAN, and y > 0 + * + * If CONFIG_AT32_ADCx_INJECTED_CHAN = 0, then all channels from chanlist + * are regular channels. + * + * Input Parameters: + * intf - Could be {1,2,3,4} for ADC1, ADC2, ADC3 + * chanlist - The list of channels (regular + injected) + * channels - Number of channels (regular + injected) + * + * Returned Value: + * Valid ADC device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct adc_dev_s *at32_adcinitialize(int intf, const uint8_t *chanlist, + int channels) +{ + struct adc_dev_s *dev; + struct at32_dev_s *priv; + uint8_t cr_channels = 0; + uint8_t cj_channels = 0; +#ifdef ADC_HAVE_INJECTED + uint8_t *j_chanlist = NULL; +#endif + + switch (intf) + { +#ifdef CONFIG_AT32_ADC1 + case 1: + { + ainfo("ADC1 selected\n"); + dev = &g_adcdev1; + cj_channels = CONFIG_AT32_ADC1_INJECTED_CHAN; + cr_channels = channels - cj_channels; +# ifdef ADC_HAVE_INJECTED + if (cj_channels > 0) + { + j_chanlist = (uint8_t *)chanlist + cr_channels; + } +# endif + break; + } + +#endif /* CONFIG_AT32_ADC1 */ +#ifdef CONFIG_AT32_ADC2 + case 2: + { + ainfo("ADC2 selected\n"); + dev = &g_adcdev2; + cj_channels = CONFIG_AT32_ADC2_INJECTED_CHAN; + cr_channels = channels - cj_channels; +# ifdef ADC_HAVE_INJECTED + if (cj_channels > 0) + { + j_chanlist = (uint8_t *)chanlist + cr_channels; + } +# endif + break; + } + +#endif /* CONFIG_AT32_ADC2 */ +#ifdef CONFIG_AT32_ADC3 + case 3: + { + ainfo("ADC3 selected\n"); + dev = &g_adcdev3; + cj_channels = CONFIG_AT32_ADC3_INJECTED_CHAN; + cr_channels = channels - cj_channels; +# ifdef ADC_HAVE_INJECTED + if (cj_channels > 0) + { + j_chanlist = (uint8_t *)chanlist + cr_channels; + } +# endif + break; + } + +#endif /* CONFIG_AT32_ADC3 */ + + default: + { + aerr("ERROR: No ADC interface defined\n"); + return NULL; + } + } + + /* Configure the selected ADC */ + + priv = (struct at32_dev_s *)dev->ad_priv; + + /* Configure regular channels */ + + DEBUGASSERT(cr_channels <= CONFIG_AT32_ADC_MAX_SAMPLES); + if (cr_channels > CONFIG_AT32_ADC_MAX_SAMPLES) + { + cr_channels = CONFIG_AT32_ADC_MAX_SAMPLES; + } + + priv->cr_channels = cr_channels; + memcpy(priv->r_chanlist, chanlist, cr_channels); + +#ifdef ADC_HAVE_INJECTED + /* Configure injected channels */ + + DEBUGASSERT(cj_channels <= ADC_INJ_MAX_SAMPLES); + if (cj_channels > ADC_INJ_MAX_SAMPLES) + { + cj_channels = ADC_INJ_MAX_SAMPLES; + } + + priv->cj_channels = cj_channels; + memcpy(priv->j_chanlist, j_chanlist, cj_channels); +#endif + +#ifdef CONFIG_AT32_ADC_CHANGE_SAMPLETIME + /* Assign default values for the sample time table */ + + memset(priv->sample_rate, ADC_SMPR_DEFAULT, ADC_CHANNELS_NUMBER); + priv->adc_channels = ADC_CHANNELS_NUMBER; +#endif + +#ifdef CONFIG_AT32_ADC_LL_OPS + /* Store reference to the upper-half ADC device */ + + priv->dev = dev; +#endif + +#ifdef ADC_HAVE_INJECTED + ainfo("intf: %d cr_channels: %d, cj_channels: %d\n", + intf, priv->cr_channels, priv->cj_channels); +#else + ainfo("intf: %d cr_channels: %d\n", intf, priv->cr_channels); +#endif + + return dev; +} + +#endif /* CONFIG_AT32_ADC */ diff --git a/arch/arm/src/at32/at32_adc.h b/arch/arm/src/at32/at32_adc.h new file mode 100644 index 0000000000..f7f1566c71 --- /dev/null +++ b/arch/arm/src/at32/at32_adc.h @@ -0,0 +1,1368 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_adc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_ADC_H +#define __ARCH_ARM_SRC_AT32_AT32_ADC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +#include "hardware/at32_adc.h" + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Generalized definitions for ADC *****************************************/ + +# define AT32_ADC_DMAREG_OFFSET AT32_ADC_CR2_OFFSET +# define ADC_DMAREG_DMA ADC_CR2_DMA +# define AT32_ADC_EXTREG_OFFSET AT32_ADC_CR2_OFFSET +# define ADC_EXTREG_EXTSEL_MASK ADC_CR2_EXTSEL_MASK +# define ADC_EXTREG_EXTSEL_SHIFT ADC_CR2_EXTSEL_SHIFT +# define AT32_ADC_JEXTREG_OFFSET AT32_ADC_CR2_OFFSET +# define ADC_JEXTREG_JEXTSEL_MASK ADC_CR2_JEXTSEL_MASK +# define ADC_EXTREG_JEXTSEL_SHIFT ADC_CR2_JEXTSEL_SHIFT +# define AT32_ADC_ISR_OFFSET AT32_ADC_SR_OFFSET +# define AT32_ADC_IER_OFFSET AT32_ADC_CR1_OFFSET +# define ADC_EXTREG_EXTEN_MASK ADC_CR2_EXTEN_MASK +# define ADC_EXTREG_EXTEN_NONE ADC_CR2_EXTEN_NONE +# define ADC_EXTREG_EXTEN_DEFAULT ADC_CR2_EXTEN_RISING +# define ADC_JEXTREG_JEXTEN_MASK ADC_CR2_JEXTEN_MASK +# define ADC_JEXTREG_JEXTEN_NONE ADC_CR2_JEXTEN_NONE +# define ADC_JEXTREG_JEXTEN_DEFAULT ADC_CR2_JEXTEN_RISING + +/* Configuration ************************************************************/ + +/* Timer devices may be used for different purposes. One special purpose is + * to control periodic ADC sampling. If CONFIG_AT32_TIMn is defined then + * CONFIG_AT32_TIMn_ADC must also be defined to indicate that timer "n" is + * intended to be used for that purpose. + */ + +/* For the AT32 F43xx line, timers 1-4, 6-8, 15, 20 may be used. */ + +#ifndef CONFIG_AT32_TIM1 +# undef CONFIG_AT32_TIM1_ADC +# undef CONFIG_AT32_TIM1_ADC1 +# undef CONFIG_AT32_TIM1_ADC2 +# undef CONFIG_AT32_TIM1_ADC3 +#endif + +#ifndef CONFIG_AT32_TIM2 +# undef CONFIG_AT32_TIM2_ADC +# undef CONFIG_AT32_TIM2_ADC1 +# undef CONFIG_AT32_TIM2_ADC2 +# undef CONFIG_AT32_TIM2_ADC3 +#endif + +#ifndef CONFIG_AT32_TIM3 +# undef CONFIG_AT32_TIM3_ADC +# undef CONFIG_AT32_TIM3_ADC1 +# undef CONFIG_AT32_TIM3_ADC2 +# undef CONFIG_AT32_TIM3_ADC3 +#endif + +#ifndef CONFIG_AT32_TIM4 +# undef CONFIG_AT32_TIM4_ADC +# undef CONFIG_AT32_TIM4_ADC1 +# undef CONFIG_AT32_TIM4_ADC2 +# undef CONFIG_AT32_TIM4_ADC3 +#endif + +#ifndef CONFIG_AT32_TIM5 +# undef CONFIG_AT32_TIM5_ADC +# undef CONFIG_AT32_TIM5_ADC1 +# undef CONFIG_AT32_TIM5_ADC2 +# undef CONFIG_AT32_TIM5_ADC3 +#endif + +#ifndef CONFIG_AT32_TIM8 +# undef CONFIG_AT32_TIM8_ADC +# undef CONFIG_AT32_TIM8_ADC1 +# undef CONFIG_AT32_TIM8_ADC2 +# undef CONFIG_AT32_TIM8_ADC3 +#endif + +#ifndef CONFIG_AT32_TIM6 +# undef CONFIG_AT32_TIM6_ADC +# undef CONFIG_AT32_TIM6_ADC1 +# undef CONFIG_AT32_TIM6_ADC2 +# undef CONFIG_AT32_TIM6_ADC3 +#endif + +#ifndef CONFIG_AT32_TIM7 +# undef CONFIG_AT32_TIM7_ADC +# undef CONFIG_AT32_TIM7_ADC1 +# undef CONFIG_AT32_TIM7_ADC2 +# undef CONFIG_AT32_TIM7_ADC3 +#endif + +#undef CONFIG_AT32_TIM9_ADC +#undef CONFIG_AT32_TIM9_ADC1 +#undef CONFIG_AT32_TIM9_ADC2 +#undef CONFIG_AT32_TIM9_ADC3 + +#undef CONFIG_AT32_TIM10_ADC +#undef CONFIG_AT32_TIM10_ADC1 +#undef CONFIG_AT32_TIM10_ADC2 +#undef CONFIG_AT32_TIM10_ADC3 + +#undef CONFIG_AT32_TIM11_ADC +#undef CONFIG_AT32_TIM11_ADC1 +#undef CONFIG_AT32_TIM11_ADC2 +#undef CONFIG_AT32_TIM11_ADC3 + +#undef CONFIG_AT32_TIM12_ADC +#undef CONFIG_AT32_TIM12_ADC1 +#undef CONFIG_AT32_TIM12_ADC2 +#undef CONFIG_AT32_TIM12_ADC3 + +#undef CONFIG_AT32_TIM13_ADC +#undef CONFIG_AT32_TIM13_ADC1 +#undef CONFIG_AT32_TIM13_ADC2 +#undef CONFIG_AT32_TIM13_ADC3 + +#undef CONFIG_AT32_TIM14_ADC +#undef CONFIG_AT32_TIM14_ADC1 +#undef CONFIG_AT32_TIM14_ADC2 +#undef CONFIG_AT32_TIM14_ADC3 + +#ifndef CONFIG_AT32_TIM20 +# undef CONFIG_AT32_TIM20_ADC +# undef CONFIG_AT32_TIM20_ADC1 +# undef CONFIG_AT32_TIM20_ADC2 +# undef CONFIG_AT32_TIM20_ADC3 + +#endif + +/* Up to 3 ADC interfaces are supported */ + +#if AT32_NADC < 3 +# undef CONFIG_AT32_ADC3 +#endif + +#if AT32_NADC < 2 +# undef CONFIG_AT32_ADC2 +#endif + +#if AT32_NADC < 1 +# undef CONFIG_AT32_ADC1 +#endif + +#if defined(CONFIG_AT32_ADC1) || defined(CONFIG_AT32_ADC2) || \ + defined(CONFIG_AT32_ADC3) + +/* DMA support */ + +#undef ADC_HAVE_DMA +#if defined(CONFIG_AT32_ADC1_DMA) || defined(CONFIG_AT32_ADC2_DMA) || \ + defined(CONFIG_AT32_ADC3_DMA) +# define ADC_HAVE_DMA 1 +#endif + +#ifdef CONFIG_AT32_ADC1_DMA +# define ADC1_HAVE_DMA 1 +#else +# undef ADC1_HAVE_DMA +#endif + +#ifdef CONFIG_AT32_ADC2_DMA +# define ADC2_HAVE_DMA 1 +#else +# undef ADC2_HAVE_DMA +#endif + +#ifdef CONFIG_AT32_ADC3_DMA +# define ADC3_HAVE_DMA 1 +#else +# undef ADC3_HAVE_DMA +#endif + +/* Injected channels support */ + +#if (defined(CONFIG_AT32_ADC1) && (CONFIG_AT32_ADC1_INJECTED_CHAN > 0)) || \ + (defined(CONFIG_AT32_ADC2) && (CONFIG_AT32_ADC2_INJECTED_CHAN > 0)) || \ + (defined(CONFIG_AT32_ADC3) && (CONFIG_AT32_ADC3_INJECTED_CHAN > 0)) +# define ADC_HAVE_INJECTED +#endif + +/* Timer configuration: If a timer trigger is specified, then get + * information about the timer. + * + */ + +#if defined(CONFIG_AT32_TIM1_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE AT32_TMR1_BASE +# define ADC1_TIMER_PCLK_FREQUENCY AT32_APB2_TIM1_CLKIN +#elif defined(CONFIG_AT32_TIM2_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE AT32_TMR2_BASE +# define ADC1_TIMER_PCLK_FREQUENCY AT32_APB1_TIM2_CLKIN +#elif defined(CONFIG_AT32_TIM3_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE AT32_TMR3_BASE +# define ADC1_TIMER_PCLK_FREQUENCY AT32_APB1_TIM3_CLKIN +#elif defined(CONFIG_AT32_TIM4_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE AT32_TMR4_BASE +# define ADC1_TIMER_PCLK_FREQUENCY AT32_APB1_TIM4_CLKIN +#elif defined(CONFIG_AT32_TIM5_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE AT32_TMR5_BASE +# define ADC1_TIMER_PCLK_FREQUENCY AT32_APB1_TIM5_CLKIN +#elif defined(CONFIG_AT32_TIM6_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE AT32_TMR6_BASE +# define ADC1_TIMER_PCLK_FREQUENCY AT32_APB1_TIM6_CLKIN +#elif defined(CONFIG_AT32_TIM7_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE AT32_TMR7_BASE +# define ADC1_TIMER_PCLK_FREQUENCY AT32_APB1_TIM7_CLKIN +#elif defined(CONFIG_AT32_TIM8_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE AT32_TMR8_BASE +# define ADC1_TIMER_PCLK_FREQUENCY AT32_APB2_TIM8_CLKIN +#elif defined(CONFIG_AT32_TIM9_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE AT32_TMR9_BASE +# define ADC1_TIMER_PCLK_FREQUENCY AT32_APB2_TIM9_CLKIN +#elif defined(CONFIG_AT32_TIM10_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE AT32_TMR10_BASE +# define ADC1_TIMER_PCLK_FREQUENCY AT32_APB2_TIM10_CLKIN +#elif defined(CONFIG_AT32_TIM20_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE AT32_TMR20_BASE +# define ADC1_TIMER_PCLK_FREQUENCY AT32_APB2_TIM20_CLKIN +#else +# undef ADC1_HAVE_TIMER +#endif + +#ifdef ADC1_HAVE_TIMER +# ifndef CONFIG_AT32_ADC1_SAMPLE_FREQUENCY +# error "CONFIG_AT32_ADC1_SAMPLE_FREQUENCY not defined" +# endif +# ifndef CONFIG_AT32_ADC1_TIMTRIG +# error "CONFIG_AT32_ADC1_TIMTRIG not defined" +# warning "Values 0:CC1 1:CC2 2:CC3 3:CC4 4:TRGO" +# endif +#endif + +#if defined(CONFIG_AT32_TIM1_ADC2) +# define ADC2_HAVE_TIMER 1 +# define ADC2_TIMER_BASE AT32_TMR1_BASE +# define ADC2_TIMER_PCLK_FREQUENCY AT32_APB2_TIM1_CLKIN +#elif defined(CONFIG_AT32_TIM2_ADC2) +# define ADC2_HAVE_TIMER 1 +# define ADC2_TIMER_BASE AT32_TMR2_BASE +# define ADC2_TIMER_PCLK_FREQUENCY AT32_APB1_TIM2_CLKIN +#elif defined(CONFIG_AT32_TIM3_ADC2) +# define ADC2_HAVE_TIMER 1 +# define ADC2_TIMER_BASE AT32_TMR3_BASE +# define ADC2_TIMER_PCLK_FREQUENCY AT32_APB1_TIM3_CLKIN +#elif defined(CONFIG_AT32_TIM4_ADC2) +# define ADC2_HAVE_TIMER 1 +# define ADC2_TIMER_BASE AT32_TMR4_BASE +# define ADC2_TIMER_PCLK_FREQUENCY AT32_APB1_TIM4_CLKIN +#elif defined(CONFIG_AT32_TIM5_ADC2) +# define ADC2_HAVE_TIMER 1 +# define ADC2_TIMER_BASE AT32_TMR5_BASE +# define ADC2_TIMER_PCLK_FREQUENCY AT32_APB1_TIM5_CLKIN +#elif defined(CONFIG_AT32_TIM6_ADC2) +# define ADC2_HAVE_TIMER 1 +# define ADC2_TIMER_BASE AT32_TMR6_BASE +# define ADC2_TIMER_PCLK_FREQUENCY AT32_APB1_TIM6_CLKIN +#elif defined(CONFIG_AT32_TIM8_ADC2) +# define ADC2_HAVE_TIMER 1 +# define ADC2_TIMER_BASE AT32_TMR8_BASE +# define ADC2_TIMER_PCLK_FREQUENCY AT32_APB2_TIM8_CLKIN +#elif defined(CONFIG_AT32_TIM20_ADC2) +# define ADC2_HAVE_TIMER 1 +# define ADC2_TIMER_BASE AT32_TMR20_BASE +# define ADC2_TIMER_PCLK_FREQUENCY AT32_APB2_TIM20_CLKIN +#else +# undef ADC2_HAVE_TIMER +#endif + +#ifdef ADC2_HAVE_TIMER +# ifndef CONFIG_AT32_ADC2_SAMPLE_FREQUENCY +# error "CONFIG_AT32_ADC2_SAMPLE_FREQUENCY not defined" +# endif +# ifndef CONFIG_AT32_ADC2_TIMTRIG +# error "CONFIG_AT32_ADC2_TIMTRIG not defined" +# warning "Values 0:CC1 1:CC2 2:CC3 3:CC4 4:TRGO" +# endif +#endif + +#if defined(CONFIG_AT32_TIM1_ADC3) +# define ADC3_HAVE_TIMER 1 +# define ADC3_TIMER_BASE AT32_TMR1_BASE +# define ADC3_TIMER_PCLK_FREQUENCY AT32_APB2_TIM1_CLKIN +#elif defined(CONFIG_AT32_TIM2_ADC3) +# define ADC3_HAVE_TIMER 1 +# define ADC3_TIMER_BASE AT32_TMR2_BASE +# define ADC3_TIMER_PCLK_FREQUENCY AT32_APB1_TIM2_CLKIN +#elif defined(CONFIG_AT32_TIM3_ADC3) +# define ADC3_HAVE_TIMER 1 +# define ADC3_TIMER_BASE AT32_TMR3_BASE +# define ADC3_TIMER_PCLK_FREQUENCY AT32_APB1_TIM3_CLKIN +#elif defined(CONFIG_AT32_TIM4_ADC3) +# define ADC3_HAVE_TIMER 1 +# define ADC3_TIMER_BASE AT32_TMR4_BASE +# define ADC3_TIMER_PCLK_FREQUENCY AT32_APB1_TIM4_CLKIN +#elif defined(CONFIG_AT32_TIM5_ADC3) +# define ADC3_HAVE_TIMER 1 +# define ADC3_TIMER_BASE AT32_TMR5_BASE +# define ADC3_TIMER_PCLK_FREQUENCY AT32_APB1_TIM5_CLKIN +#elif defined(CONFIG_AT32_TIM7_ADC3) +# define ADC3_HAVE_TIMER 1 +# define ADC3_TIMER_BASE AT32_TMR7_BASE +# define ADC3_TIMER_PCLK_FREQUENCY AT32_APB1_TIM7_CLKIN +#elif defined(CONFIG_AT32_TIM8_ADC3) +# define ADC3_HAVE_TIMER 1 +# define ADC3_TIMER_BASE AT32_TMR8_BASE +# define ADC3_TIMER_PCLK_FREQUENCY AT32_APB2_TIM8_CLKIN +#elif defined(CONFIG_AT32_TIM20_ADC3) +# define ADC3_HAVE_TIMER 1 +# define ADC3_TIMER_BASE AT32_TMR20_BASE +# define ADC3_TIMER_PCLK_FREQUENCY AT32_APB2_TIM20_CLKIN +#else +# undef ADC3_HAVE_TIMER +#endif + +#ifdef ADC3_HAVE_TIMER +# ifndef CONFIG_AT32_ADC3_SAMPLE_FREQUENCY +# error "CONFIG_AT32_ADC3_SAMPLE_FREQUENCY not defined" +# endif +# ifndef CONFIG_AT32_ADC3_TIMTRIG +# error "CONFIG_AT32_ADC3_TIMTRIG not defined" +# warning "Values 0:CC1 1:CC2 2:CC3 3:CC4 4:TRGO" +# endif +#endif + +#if defined(ADC1_HAVE_TIMER) || defined(ADC2_HAVE_TIMER) || \ + defined(ADC3_HAVE_TIMER) +# define ADC_HAVE_TIMER 1 +#else +# undef ADC_HAVE_TIMER +#endif + +/* NOTE: + * The following assumes that all possible combinations of timers and + * values are support EXTSEL. That is not so and it varies from one AT32 + * to another. But this (wrong) assumptions keeps the logic as simple as + * possible. If unsupported combination is used, an error will show up + * later during compilation although it may be difficult to track it back + * to this simplification. + * + */ + +# define ADC1_EXTSEL_T1CC1 ADC_CR2_EXTSEL_T1CC1 +# define ADC1_EXTSEL_T1CC2 ADC_CR2_EXTSEL_T1CC2 +# define ADC1_EXTSEL_T1CC3 ADC_CR2_EXTSEL_T1CC3 +# define ADC1_EXTSEL_T1CC4 ADC_CR2_EXTSEL_T1CC4 +# define ADC1_EXTSEL_T1TRGO ADC_CR2_EXTSEL_T1TRGO +# define ADC2_EXTSEL_T1CC1 ADC_CR2_EXTSEL_T1CC1 +# define ADC2_EXTSEL_T1CC2 ADC_CR2_EXTSEL_T1CC2 +# define ADC2_EXTSEL_T1CC3 ADC_CR2_EXTSEL_T1CC3 +# define ADC2_EXTSEL_T1CC4 ADC_CR2_EXTSEL_T1CC4 +# define ADC2_EXTSEL_T1TRGO ADC_CR2_EXTSEL_T1TRGO +# define ADC3_EXTSEL_T1CC1 ADC_CR2_EXTSEL_T1CC1 +# define ADC3_EXTSEL_T1CC2 ADC_CR2_EXTSEL_T1CC2 +# define ADC3_EXTSEL_T1CC3 ADC_CR2_EXTSEL_T1CC3 +# define ADC3_EXTSEL_T1CC4 ADC_CR2_EXTSEL_T1CC4 +# define ADC3_EXTSEL_T1TRGO ADC_CR2_EXTSEL_T1TRGO + +# define ADC1_EXTSEL_T2CC1 ADC_CR2_EXTSEL_T2CC1 +# define ADC1_EXTSEL_T2CC2 ADC_CR2_EXTSEL_T2CC2 +# define ADC1_EXTSEL_T2CC3 ADC_CR2_EXTSEL_T2CC3 +# define ADC1_EXTSEL_T2CC4 ADC_CR2_EXTSEL_T2CC4 +# define ADC1_EXTSEL_T2TRGO ADC_CR2_EXTSEL_T2TRGO +# define ADC2_EXTSEL_T2CC1 ADC_CR2_EXTSEL_T2CC1 +# define ADC2_EXTSEL_T2CC2 ADC_CR2_EXTSEL_T2CC2 +# define ADC2_EXTSEL_T2CC3 ADC_CR2_EXTSEL_T2CC3 +# define ADC2_EXTSEL_T2CC4 ADC_CR2_EXTSEL_T2CC4 +# define ADC2_EXTSEL_T2TRGO ADC_CR2_EXTSEL_T2TRGO +# define ADC3_EXTSEL_T2CC1 ADC_CR2_EXTSEL_T2CC1 +# define ADC3_EXTSEL_T2CC2 ADC_CR2_EXTSEL_T2CC2 +# define ADC3_EXTSEL_T2CC3 ADC_CR2_EXTSEL_T2CC3 +# define ADC3_EXTSEL_T2CC4 ADC_CR2_EXTSEL_T2CC4 +# define ADC3_EXTSEL_T2TRGO ADC_CR2_EXTSEL_T2TRGO + +# define ADC1_EXTSEL_T3CC1 ADC_CR2_EXTSEL_T3CC1 +# define ADC1_EXTSEL_T3CC2 ADC_CR2_EXTSEL_T3CC2 +# define ADC1_EXTSEL_T3CC3 ADC_CR2_EXTSEL_T3CC3 +# define ADC1_EXTSEL_T3CC4 ADC_CR2_EXTSEL_T3CC4 +# define ADC1_EXTSEL_T3TRGO ADC_CR2_EXTSEL_T3TRGO +# define ADC2_EXTSEL_T3CC1 ADC_CR2_EXTSEL_T3CC1 +# define ADC2_EXTSEL_T3CC2 ADC_CR2_EXTSEL_T3CC2 +# define ADC2_EXTSEL_T3CC3 ADC_CR2_EXTSEL_T3CC3 +# define ADC2_EXTSEL_T3CC4 ADC_CR2_EXTSEL_T3CC4 +# define ADC2_EXTSEL_T3TRGO ADC_CR2_EXTSEL_T3TRGO +# define ADC3_EXTSEL_T3CC1 ADC_CR2_EXTSEL_T3CC1 +# define ADC3_EXTSEL_T3CC2 ADC_CR2_EXTSEL_T3CC2 +# define ADC3_EXTSEL_T3CC3 ADC_CR2_EXTSEL_T3CC3 +# define ADC3_EXTSEL_T3CC4 ADC_CR2_EXTSEL_T3CC4 +# define ADC3_EXTSEL_T3TRGO ADC_CR2_EXTSEL_T3TRGO + +# define ADC1_EXTSEL_T4CC1 ADC_CR2_EXTSEL_T4CC1 +# define ADC1_EXTSEL_T4CC2 ADC_CR2_EXTSEL_T4CC2 +# define ADC1_EXTSEL_T4CC3 ADC_CR2_EXTSEL_T4CC3 +# define ADC1_EXTSEL_T4CC4 ADC_CR2_EXTSEL_T4CC4 +# define ADC1_EXTSEL_T4TRGO ADC_CR2_EXTSEL_T4TRGO +# define ADC2_EXTSEL_T4CC1 ADC_CR2_EXTSEL_T4CC1 +# define ADC2_EXTSEL_T4CC2 ADC_CR2_EXTSEL_T4CC2 +# define ADC2_EXTSEL_T4CC3 ADC_CR2_EXTSEL_T4CC3 +# define ADC2_EXTSEL_T4CC4 ADC_CR2_EXTSEL_T4CC4 +# define ADC2_EXTSEL_T4TRGO ADC_CR2_EXTSEL_T4TRGO +# define ADC3_EXTSEL_T4CC1 ADC_CR2_EXTSEL_T4CC1 +# define ADC3_EXTSEL_T4CC2 ADC_CR2_EXTSEL_T4CC2 +# define ADC3_EXTSEL_T4CC3 ADC_CR2_EXTSEL_T4CC3 +# define ADC3_EXTSEL_T4CC4 ADC_CR2_EXTSEL_T4CC4 +# define ADC3_EXTSEL_T4TRGO ADC_CR2_EXTSEL_T4TRGO + +# define ADC1_EXTSEL_T5CC1 ADC_CR2_EXTSEL_T5CC1 +# define ADC1_EXTSEL_T5CC2 ADC_CR2_EXTSEL_T5CC2 +# define ADC1_EXTSEL_T5CC3 ADC_CR2_EXTSEL_T5CC3 +# define ADC1_EXTSEL_T5CC4 ADC_CR2_EXTSEL_T5CC4 +# define ADC1_EXTSEL_T5TRGO ADC_CR2_EXTSEL_T5TRGO +# define ADC2_EXTSEL_T5CC1 ADC_CR2_EXTSEL_T5CC1 +# define ADC2_EXTSEL_T5CC2 ADC_CR2_EXTSEL_T5CC2 +# define ADC2_EXTSEL_T5CC3 ADC_CR2_EXTSEL_T5CC3 +# define ADC2_EXTSEL_T5CC4 ADC_CR2_EXTSEL_T5CC4 +# define ADC2_EXTSEL_T5TRGO ADC_CR2_EXTSEL_T5TRGO +# define ADC3_EXTSEL_T5CC1 ADC_CR2_EXTSEL_T5CC1 +# define ADC3_EXTSEL_T5CC2 ADC_CR2_EXTSEL_T5CC2 +# define ADC3_EXTSEL_T5CC3 ADC_CR2_EXTSEL_T5CC3 +# define ADC3_EXTSEL_T5CC4 ADC_CR2_EXTSEL_T5CC4 +# define ADC3_EXTSEL_T5TRGO ADC_CR2_EXTSEL_T5TRGO + +# define ADC1_EXTSEL_T6CC1 ADC_CR2_EXTSEL_T6CC1 +# define ADC1_EXTSEL_T6CC2 ADC_CR2_EXTSEL_T6CC2 +# define ADC1_EXTSEL_T6CC3 ADC_CR2_EXTSEL_T6CC3 +# define ADC1_EXTSEL_T6CC4 ADC_CR2_EXTSEL_T6CC4 +# define ADC1_EXTSEL_T6TRGO ADC_CR2_EXTSEL_T6TRGO +# define ADC2_EXTSEL_T6CC1 ADC_CR2_EXTSEL_T6CC1 +# define ADC2_EXTSEL_T6CC2 ADC_CR2_EXTSEL_T6CC2 +# define ADC2_EXTSEL_T6CC3 ADC_CR2_EXTSEL_T6CC3 +# define ADC2_EXTSEL_T6CC4 ADC_CR2_EXTSEL_T6CC4 +# define ADC2_EXTSEL_T6TRGO ADC_CR2_EXTSEL_T6TRGO +# define ADC3_EXTSEL_T6CC1 ADC_CR2_EXTSEL_T6CC1 +# define ADC3_EXTSEL_T6CC2 ADC_CR2_EXTSEL_T6CC2 +# define ADC3_EXTSEL_T6CC3 ADC_CR2_EXTSEL_T6CC3 +# define ADC3_EXTSEL_T6CC4 ADC_CR2_EXTSEL_T6CC4 +# define ADC3_EXTSEL_T6TRGO ADC_CR2_EXTSEL_T6TRGO + +# define ADC1_EXTSEL_T7CC1 ADC_CR2_EXTSEL_T7CC1 +# define ADC1_EXTSEL_T7CC2 ADC_CR2_EXTSEL_T7CC2 +# define ADC1_EXTSEL_T7CC3 ADC_CR2_EXTSEL_T7CC3 +# define ADC1_EXTSEL_T7CC4 ADC_CR2_EXTSEL_T7CC4 +# define ADC1_EXTSEL_T7TRGO ADC_CR2_EXTSEL_T7TRGO +# define ADC2_EXTSEL_T7CC1 ADC_CR2_EXTSEL_T7CC1 +# define ADC2_EXTSEL_T7CC2 ADC_CR2_EXTSEL_T7CC2 +# define ADC2_EXTSEL_T7CC3 ADC_CR2_EXTSEL_T7CC3 +# define ADC2_EXTSEL_T7CC4 ADC_CR2_EXTSEL_T7CC4 +# define ADC2_EXTSEL_T7TRGO ADC_CR2_EXTSEL_T7TRGO +# define ADC3_EXTSEL_T7CC1 ADC_CR2_EXTSEL_T7CC1 +# define ADC3_EXTSEL_T7CC2 ADC_CR2_EXTSEL_T7CC2 +# define ADC3_EXTSEL_T7CC3 ADC_CR2_EXTSEL_T7CC3 +# define ADC3_EXTSEL_T7CC4 ADC_CR2_EXTSEL_T7CC4 +# define ADC3_EXTSEL_T7TRGO ADC_CR2_EXTSEL_T7TRGO + +# define ADC1_EXTSEL_T8CC1 ADC_CR2_EXTSEL_T8CC1 +# define ADC1_EXTSEL_T8CC2 ADC_CR2_EXTSEL_T8CC2 +# define ADC1_EXTSEL_T8CC3 ADC_CR2_EXTSEL_T8CC3 +# define ADC1_EXTSEL_T8CC4 ADC_CR2_EXTSEL_T8CC4 +# define ADC1_EXTSEL_T8TRGO ADC_CR2_EXTSEL_T8TRGO +# define ADC2_EXTSEL_T8CC1 ADC_CR2_EXTSEL_T8CC1 +# define ADC2_EXTSEL_T8CC2 ADC_CR2_EXTSEL_T8CC2 +# define ADC2_EXTSEL_T8CC3 ADC_CR2_EXTSEL_T8CC3 +# define ADC2_EXTSEL_T8CC4 ADC_CR2_EXTSEL_T8CC4 +# define ADC2_EXTSEL_T8TRGO ADC_CR2_EXTSEL_T8TRGO +# define ADC3_EXTSEL_T8CC1 ADC_CR2_EXTSEL_T8CC1 +# define ADC3_EXTSEL_T8CC2 ADC_CR2_EXTSEL_T8CC2 +# define ADC3_EXTSEL_T8CC3 ADC_CR2_EXTSEL_T8CC3 +# define ADC3_EXTSEL_T8CC4 ADC_CR2_EXTSEL_T8CC4 +# define ADC3_EXTSEL_T8TRGO ADC_CR2_EXTSEL_T8TRGO + +# define ADC1_EXTSEL_T9CC1 ADC_CR2_EXTSEL_T9CC1 +# define ADC1_EXTSEL_T9CC2 ADC_CR2_EXTSEL_T9CC2 +# define ADC1_EXTSEL_T9CC3 ADC_CR2_EXTSEL_T9CC3 +# define ADC1_EXTSEL_T9CC4 ADC_CR2_EXTSEL_T9CC4 +# define ADC1_EXTSEL_T9TRGO ADC_CR2_EXTSEL_T9TRGO +# define ADC2_EXTSEL_T9CC1 ADC_CR2_EXTSEL_T9CC1 +# define ADC2_EXTSEL_T9CC2 ADC_CR2_EXTSEL_T9CC2 +# define ADC2_EXTSEL_T9CC3 ADC_CR2_EXTSEL_T9CC3 +# define ADC2_EXTSEL_T9CC4 ADC_CR2_EXTSEL_T9CC4 +# define ADC2_EXTSEL_T9TRGO ADC_CR2_EXTSEL_T9TRGO +# define ADC3_EXTSEL_T9CC1 ADC_CR2_EXTSEL_T9CC1 +# define ADC3_EXTSEL_T9CC2 ADC_CR2_EXTSEL_T9CC2 +# define ADC3_EXTSEL_T9CC3 ADC_CR2_EXTSEL_T9CC3 +# define ADC3_EXTSEL_T9CC4 ADC_CR2_EXTSEL_T9CC4 +# define ADC3_EXTSEL_T9TRGO ADC_CR2_EXTSEL_T9TRGO + +# define ADC1_EXTSEL_T10CC1 ADC_CR2_EXTSEL_T10CC1 +# define ADC1_EXTSEL_T10CC2 ADC_CR2_EXTSEL_T10CC2 +# define ADC1_EXTSEL_T10CC3 ADC_CR2_EXTSEL_T10CC3 +# define ADC1_EXTSEL_T10CC4 ADC_CR2_EXTSEL_T10CC4 +# define ADC1_EXTSEL_T10TRGO ADC_CR2_EXTSEL_T10TRGO +# define ADC2_EXTSEL_T10CC1 ADC_CR2_EXTSEL_T10CC1 +# define ADC2_EXTSEL_T10CC2 ADC_CR2_EXTSEL_T10CC2 +# define ADC2_EXTSEL_T10CC3 ADC_CR2_EXTSEL_T10CC3 +# define ADC2_EXTSEL_T10CC4 ADC_CR2_EXTSEL_T10CC4 +# define ADC2_EXTSEL_T10TRGO ADC_CR2_EXTSEL_T10TRGO +# define ADC3_EXTSEL_T10CC1 ADC_CR2_EXTSEL_T10CC1 +# define ADC3_EXTSEL_T10CC2 ADC_CR2_EXTSEL_T10CC2 +# define ADC3_EXTSEL_T10CC3 ADC_CR2_EXTSEL_T10CC3 +# define ADC3_EXTSEL_T10CC4 ADC_CR2_EXTSEL_T10CC4 +# define ADC3_EXTSEL_T10TRGO ADC_CR2_EXTSEL_T10TRGO + +# define ADC1_EXTSEL_T15CC1 ADC_CR2_EXTSEL_T15CC1 +# define ADC1_EXTSEL_T15CC2 ADC_CR2_EXTSEL_T15CC2 +# define ADC1_EXTSEL_T15CC3 ADC_CR2_EXTSEL_T15CC3 +# define ADC1_EXTSEL_T15CC4 ADC_CR2_EXTSEL_T15CC4 +# define ADC1_EXTSEL_T15TRGO ADC_CR2_EXTSEL_T15TRGO +# define ADC2_EXTSEL_T15CC1 ADC_CR2_EXTSEL_T15CC1 +# define ADC2_EXTSEL_T15CC2 ADC_CR2_EXTSEL_T15CC2 +# define ADC2_EXTSEL_T15CC3 ADC_CR2_EXTSEL_T15CC3 +# define ADC2_EXTSEL_T15CC4 ADC_CR2_EXTSEL_T15CC4 +# define ADC2_EXTSEL_T15TRGO ADC_CR2_EXTSEL_T15TRGO +# define ADC3_EXTSEL_T15CC1 ADC_CR2_EXTSEL_T15CC1 +# define ADC3_EXTSEL_T15CC2 ADC_CR2_EXTSEL_T15CC2 +# define ADC3_EXTSEL_T15CC3 ADC_CR2_EXTSEL_T15CC3 +# define ADC3_EXTSEL_T15CC4 ADC_CR2_EXTSEL_T15CC4 +# define ADC3_EXTSEL_T15TRGO ADC_CR2_EXTSEL_T15TRGO + +# define ADC1_EXTSEL_T20CC1 ADC_CR2_EXTSEL_T20CC1 +# define ADC1_EXTSEL_T20CC2 ADC_CR2_EXTSEL_T20CC2 +# define ADC1_EXTSEL_T20CC3 ADC_CR2_EXTSEL_T20CC3 +# define ADC1_EXTSEL_T20CC4 ADC_CR2_EXTSEL_T20CC4 +# define ADC1_EXTSEL_T20TRGO ADC_CR2_EXTSEL_T20TRGO +# define ADC2_EXTSEL_T20CC1 ADC_CR2_EXTSEL_T20CC1 +# define ADC2_EXTSEL_T20CC2 ADC_CR2_EXTSEL_T20CC2 +# define ADC2_EXTSEL_T20CC3 ADC_CR2_EXTSEL_T20CC3 +# define ADC2_EXTSEL_T20CC4 ADC_CR2_EXTSEL_T20CC4 +# define ADC2_EXTSEL_T20TRGO ADC_CR2_EXTSEL_T20TRGO +# define ADC3_EXTSEL_T20CC1 ADC_CR2_EXTSEL_T20CC1 +# define ADC3_EXTSEL_T20CC2 ADC_CR2_EXTSEL_T20CC2 +# define ADC3_EXTSEL_T20CC3 ADC_CR2_EXTSEL_T20CC3 +# define ADC3_EXTSEL_T20CC4 ADC_CR2_EXTSEL_T20CC4 +# define ADC3_EXTSEL_T20TRGO ADC_CR2_EXTSEL_T20TRGO + +/* EXTSEL configuration *****************************************************/ + +/* NOTE: + * this configuration if used only if CONFIG_AT32_TIMx_ADCy is selected. + * You can still connect the ADC with a timer trigger using the + * CONFIG_AT32_ADCx_EXTSEL option. + */ + +#if defined(CONFIG_AT32_TIM1_ADC1) +# if CONFIG_AT32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC1 +# elif CONFIG_AT32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC2 +# elif CONFIG_AT32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC3 +# elif CONFIG_AT32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC4 +# elif CONFIG_AT32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1TRGO +# else +# error "CONFIG_AT32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM2_ADC1) +# if CONFIG_AT32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T2CC1 +# elif CONFIG_AT32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T2CC2 +# elif CONFIG_AT32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T2CC3 +# elif CONFIG_AT32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T2CC4 +# elif CONFIG_AT32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T2TRGO +# else +# error "CONFIG_AT32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM3_ADC1) +# if CONFIG_AT32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T3CC1 +# elif CONFIG_AT32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T3CC2 +# elif CONFIG_AT32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T3CC3 +# elif CONFIG_AT32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T3CC4 +# elif CONFIG_AT32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T3TRGO +# else +# error "CONFIG_AT32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM4_ADC1) +# if CONFIG_AT32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T4CC1 +# elif CONFIG_AT32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T4CC2 +# elif CONFIG_AT32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T4CC3 +# elif CONFIG_AT32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T4CC4 +# elif CONFIG_AT32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T4TRGO +# else +# error "CONFIG_AT32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM5_ADC1) +# if CONFIG_AT32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T5CC1 +# elif CONFIG_AT32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T5CC2 +# elif CONFIG_AT32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T5CC3 +# elif CONFIG_AT32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T5CC4 +# elif CONFIG_AT32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T5TRGO +# else +# error "CONFIG_AT32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM6_ADC1) +# if CONFIG_AT32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T6CC1 +# elif CONFIG_AT32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T6CC2 +# elif CONFIG_AT32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T6CC3 +# elif CONFIG_AT32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T6CC4 +# elif CONFIG_AT32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T6TRGO +# else +# error "CONFIG_AT32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM7_ADC1) +# if CONFIG_AT32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T7CC1 +# elif CONFIG_AT32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T7CC2 +# elif CONFIG_AT32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T7CC3 +# elif CONFIG_AT32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T7CC4 +# elif CONFIG_AT32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T7TRGO +# else +# error "CONFIG_AT32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM8_ADC1) +# if CONFIG_AT32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T8CC1 +# elif CONFIG_AT32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T8CC2 +# elif CONFIG_AT32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T8CC3 +# elif CONFIG_AT32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T8CC4 +# elif CONFIG_AT32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T8TRGO +# else +# error "CONFIG_AT32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM9_ADC1) +# if CONFIG_AT32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T9CC1 +# elif CONFIG_AT32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T9CC2 +# elif CONFIG_AT32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T9CC3 +# elif CONFIG_AT32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T9CC4 +# elif CONFIG_AT32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T9TRGO +# else +# error "CONFIG_AT32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM10_ADC1) +# if CONFIG_AT32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T10CC1 +# elif CONFIG_AT32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T10CC2 +# elif CONFIG_AT32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T10CC3 +# elif CONFIG_AT32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T10CC4 +# elif CONFIG_AT32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T10TRGO +# else +# error "CONFIG_AT32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM20_ADC1) +# if CONFIG_AT32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T20CC1 +# elif CONFIG_AT32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T20CC2 +# elif CONFIG_AT32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T20CC3 +# elif CONFIG_AT32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T20CC4 +# elif CONFIG_AT32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T20TRGO +# else +# error "CONFIG_AT32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_HRTIM_ADC1_TRG1) +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_HRTTRG1 +#elif defined(CONFIG_AT32_HRTIM_ADC1_TRG3) +# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_HRTTRG3 +#endif + +#if defined(CONFIG_AT32_TIM1_ADC2) +# if CONFIG_AT32_ADC2_TIMTRIG == 0 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC1 +# elif CONFIG_AT32_ADC2_TIMTRIG == 1 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC2 +# elif CONFIG_AT32_ADC2_TIMTRIG == 2 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC3 +# elif CONFIG_AT32_ADC2_TIMTRIG == 3 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC4 +# elif CONFIG_AT32_ADC2_TIMTRIG == 4 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1TRGO +# else +# error "CONFIG_AT32_ADC2_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM2_ADC2) +# if CONFIG_AT32_ADC2_TIMTRIG == 0 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T2CC1 +# elif CONFIG_AT32_ADC2_TIMTRIG == 1 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T2CC2 +# elif CONFIG_AT32_ADC2_TIMTRIG == 2 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T2CC3 +# elif CONFIG_AT32_ADC2_TIMTRIG == 3 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T2CC4 +# elif CONFIG_AT32_ADC2_TIMTRIG == 4 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T2TRGO +# else +# error "CONFIG_AT32_ADC2_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM3_ADC2) +# if CONFIG_AT32_ADC2_TIMTRIG == 0 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T3CC1 +# elif CONFIG_AT32_ADC2_TIMTRIG == 1 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T3CC2 +# elif CONFIG_AT32_ADC2_TIMTRIG == 2 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T3CC3 +# elif CONFIG_AT32_ADC2_TIMTRIG == 3 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T3CC4 +# elif CONFIG_AT32_ADC2_TIMTRIG == 4 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T3TRGO +# else +# error "CONFIG_AT32_ADC2_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM4_ADC2) +# if CONFIG_AT32_ADC2_TIMTRIG == 0 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T4CC1 +# elif CONFIG_AT32_ADC2_TIMTRIG == 1 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T4CC2 +# elif CONFIG_AT32_ADC2_TIMTRIG == 2 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T4CC3 +# elif CONFIG_AT32_ADC2_TIMTRIG == 3 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T4CC4 +# elif CONFIG_AT32_ADC2_TIMTRIG == 4 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T4TRGO +# else +# error "CONFIG_AT32_ADC2_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM5_ADC2) +# if CONFIG_AT32_ADC2_TIMTRIG == 0 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T5CC1 +# elif CONFIG_AT32_ADC2_TIMTRIG == 1 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T5CC2 +# elif CONFIG_AT32_ADC2_TIMTRIG == 2 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T5CC3 +# elif CONFIG_AT32_ADC2_TIMTRIG == 3 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T5CC4 +# elif CONFIG_AT32_ADC2_TIMTRIG == 4 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T5TRGO +# else +# error "CONFIG_AT32_ADC2_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM6_ADC2) +# if CONFIG_AT32_ADC2_TIMTRIG == 0 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T6CC1 +# elif CONFIG_AT32_ADC2_TIMTRIG == 1 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T6CC2 +# elif CONFIG_AT32_ADC2_TIMTRIG == 2 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T6CC3 +# elif CONFIG_AT32_ADC2_TIMTRIG == 3 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T6CC4 +# elif CONFIG_AT32_ADC2_TIMTRIG == 4 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T6TRGO +# else +# error "CONFIG_AT32_ADC2_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM8_ADC2) +# if CONFIG_AT32_ADC2_TIMTRIG == 0 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T8CC1 +# elif CONFIG_AT32_ADC2_TIMTRIG == 1 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T8CC2 +# elif CONFIG_AT32_ADC2_TIMTRIG == 2 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T8CC3 +# elif CONFIG_AT32_ADC2_TIMTRIG == 3 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T8CC4 +# elif CONFIG_AT32_ADC2_TIMTRIG == 4 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T8TRGO +# else +# error "CONFIG_AT32_ADC2_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM20_ADC2) +# if CONFIG_AT32_ADC2_TIMTRIG == 0 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T20CC1 +# elif CONFIG_AT32_ADC2_TIMTRIG == 1 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T20CC2 +# elif CONFIG_AT32_ADC2_TIMTRIG == 2 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T20CC3 +# elif CONFIG_AT32_ADC2_TIMTRIG == 3 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T20CC4 +# elif CONFIG_AT32_ADC2_TIMTRIG == 4 +# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T20TRGO +# else +# error "CONFIG_AT32_ADC2_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_HRTIM_ADC2_TRG1) +# define ADC2_EXTSEL_VALUE ADC1_EXTSEL_HRTTRG1 +#elif defined(CONFIG_AT32_HRTIM_ADC1_TRG3) +# define ADC2_EXTSEL_VALUE ADC1_EXTSEL_HRTTRG3 +#endif + +#if defined(CONFIG_AT32_TIM1_ADC3) +# if CONFIG_AT32_ADC3_TIMTRIG == 0 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T1CC1 +# elif CONFIG_AT32_ADC3_TIMTRIG == 1 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T1CC2 +# elif CONFIG_AT32_ADC3_TIMTRIG == 2 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T1CC3 +# elif CONFIG_AT32_ADC3_TIMTRIG == 3 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T1CC4 +# elif CONFIG_AT32_ADC3_TIMTRIG == 4 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T1TRGO +# else +# error "CONFIG_AT32_ADC3_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM2_ADC3) +# if CONFIG_AT32_ADC3_TIMTRIG == 0 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T2CC1 +# elif CONFIG_AT32_ADC3_TIMTRIG == 1 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T2CC2 +# elif CONFIG_AT32_ADC3_TIMTRIG == 2 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T2CC3 +# elif CONFIG_AT32_ADC3_TIMTRIG == 3 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T2CC4 +# elif CONFIG_AT32_ADC3_TIMTRIG == 4 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T2TRGO +# else +# error "CONFIG_AT32_ADC3_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM3_ADC3) +# if CONFIG_AT32_ADC3_TIMTRIG == 0 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T3CC1 +# elif CONFIG_AT32_ADC3_TIMTRIG == 1 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T3CC2 +# elif CONFIG_AT32_ADC3_TIMTRIG == 2 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T3CC3 +# elif CONFIG_AT32_ADC3_TIMTRIG == 3 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T3CC4 +# elif CONFIG_AT32_ADC3_TIMTRIG == 4 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T3TRGO +# else +# error "CONFIG_AT32_ADC3_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM4_ADC3) +# if CONFIG_AT32_ADC3_TIMTRIG == 0 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T4CC1 +# elif CONFIG_AT32_ADC3_TIMTRIG == 1 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T4CC2 +# elif CONFIG_AT32_ADC3_TIMTRIG == 2 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T4CC3 +# elif CONFIG_AT32_ADC3_TIMTRIG == 3 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T4CC4 +# elif CONFIG_AT32_ADC3_TIMTRIG == 4 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T4TRGO +# else +# error "CONFIG_AT32_ADC3_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM5_ADC3) +# if CONFIG_AT32_ADC3_TIMTRIG == 0 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T5CC1 +# elif CONFIG_AT32_ADC3_TIMTRIG == 1 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T5CC2 +# elif CONFIG_AT32_ADC3_TIMTRIG == 2 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T5CC3 +# elif CONFIG_AT32_ADC3_TIMTRIG == 3 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T5CC4 +# elif CONFIG_AT32_ADC3_TIMTRIG == 4 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T5TRGO +# else +# error "CONFIG_AT32_ADC3_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM7_ADC3) +# if CONFIG_AT32_ADC3_TIMTRIG == 0 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T7CC1 +# elif CONFIG_AT32_ADC3_TIMTRIG == 1 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T7CC2 +# elif CONFIG_AT32_ADC3_TIMTRIG == 2 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T7CC3 +# elif CONFIG_AT32_ADC3_TIMTRIG == 3 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T7CC4 +# elif CONFIG_AT32_ADC3_TIMTRIG == 4 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T7TRGO +# else +# error "CONFIG_AT32_ADC3_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM8_ADC3) +# if CONFIG_AT32_ADC3_TIMTRIG == 0 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T8CC1 +# elif CONFIG_AT32_ADC3_TIMTRIG == 1 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T8CC2 +# elif CONFIG_AT32_ADC3_TIMTRIG == 2 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T8CC3 +# elif CONFIG_AT32_ADC3_TIMTRIG == 3 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T8CC4 +# elif CONFIG_AT32_ADC3_TIMTRIG == 4 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T8TRGO +# else +# error "CONFIG_AT32_ADC3_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_AT32_TIM20_ADC3) +# if CONFIG_AT32_ADC3_TIMTRIG == 0 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T20CC1 +# elif CONFIG_AT32_ADC3_TIMTRIG == 1 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T20CC2 +# elif CONFIG_AT32_ADC3_TIMTRIG == 2 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T20CC3 +# elif CONFIG_AT32_ADC3_TIMTRIG == 3 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T20CC4 +# elif CONFIG_AT32_ADC3_TIMTRIG == 4 +# define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T20TRGO +# else +# error "CONFIG_AT32_ADC3_TIMTRIG is out of range" +# endif +#endif + +/* Regular channels external trigger support */ + +#ifdef ADC1_EXTSEL_VALUE +# define ADC1_HAVE_EXTCFG 1 +# define ADC1_EXTCFG_VALUE (ADC1_EXTSEL_VALUE | ADC_EXTREG_EXTEN_DEFAULT) +#elif defined(CONFIG_AT32_ADC1_EXTSEL) +# define ADC1_HAVE_EXTCFG 1 +# define ADC1_EXTCFG_VALUE 0 +#else +# undef ADC1_HAVE_EXTCFG +#endif +#ifdef ADC2_EXTSEL_VALUE +# define ADC2_HAVE_EXTCFG 1 +# define ADC2_EXTCFG_VALUE (ADC2_EXTSEL_VALUE | ADC_EXTREG_EXTEN_DEFAULT) +#elif defined(CONFIG_AT32_ADC2_EXTSEL) +# define ADC2_HAVE_EXTCFG 1 +# define ADC2_EXTCFG_VALUE 0 +#else +# undef ADC2_HAVE_EXTCFG +#endif +#ifdef ADC3_EXTSEL_VALUE +# define ADC3_HAVE_EXTCFG 1 +# define ADC3_EXTCFG_VALUE (ADC3_EXTSEL_VALUE | ADC_EXTREG_EXTEN_DEFAULT) +#elif defined(CONFIG_AT32_ADC3_EXTSEL) +# define ADC3_HAVE_EXTCFG 1 +# define ADC3_EXTCFG_VALUE 0 +#else +# undef ADC3_HAVE_EXTCFG +#endif + +#if defined(ADC1_HAVE_EXTCFG) || defined(ADC2_HAVE_EXTCFG) || \ + defined(ADC3_HAVE_EXTCFG) || defined(ADC3_HAVE_EXTCFG) +# define ADC_HAVE_EXTCFG +#endif + +/* JEXTSEL configuration ****************************************************/ + +/* There is no automatic timer tirgger configuration from Kconfig for + * injected channels conversion. + */ + +/* Injected channels external trigger support */ + +#ifdef ADC1_JEXTSEL_VALUE +# define ADC1_HAVE_JEXTCFG 1 +# define ADC1_JEXTCFG_VALUE (ADC1_JEXTSEL_VALUE | ADC_JEXTREG_JEXTEN_DEFAULT) +#elif defined(CONFIG_AT32_ADC1_JEXTSEL) +# define ADC1_HAVE_JEXTCFG 1 +# define ADC1_JEXTCFG_VALUE 0 +#else +# undef ADC1_HAVE_JEXTCFG +#endif +#ifdef ADC2_JEXTSEL_VALUE +# define ADC2_HAVE_JEXTCFG 1 +# define ADC2_JEXTCFG_VALUE (ADC2_JEXTSEL_VALUE | ADC_JEXTREG_JEXTEN_DEFAULT) +#elif defined(CONFIG_AT32_ADC2_JEXTSEL) +# define ADC2_HAVE_JEXTCFG 1 +# define ADC2_JEXTCFG_VALUE 0 +#else +# undef ADC2_HAVE_JEXTCFG +#endif +#ifdef ADC3_JEXTSEL_VALUE +# define ADC3_HAVE_JEXTCFG 1 +# define ADC3_JEXTCFG_VALUE (ADC3_JEXTSEL_VALUE | ADC_JEXTREG_JEXTEN_DEFAULT) +#elif defined(CONFIG_AT32_ADC3_JEXTSEL) +# define ADC3_HAVE_JEXTCFG 1 +# define ADC3_JEXTCFG_VALUE 0 +#else +# undef ADC3_HAVE_JEXTCFG +#endif + +#if defined(ADC1_HAVE_JEXTCFG) || defined(ADC2_HAVE_JEXTCFG) || \ + defined(ADC3_HAVE_JEXTCFG) +# define ADC_HAVE_JEXTCFG +#endif + +/* ADC interrupts ***********************************************************/ + +# define ADC_ISR_EOC ADC_SR_EOC +# define ADC_IER_EOC ADC_CR1_EOCIE +# define ADC_ISR_AWD ADC_SR_AWD +# define ADC_IER_AWD ADC_CR1_AWDIE +# define ADC_ISR_JEOC ADC_SR_JEOC +# define ADC_IER_JEOC ADC_CR1_JEOCIE +# define ADC_ISR_JEOS 0 /* No JEOS */ +# define ADC_IER_JEOS 0 /* No JEOS */ +# define ADC_ISR_OVR ADC_SR_OVR +# define ADC_IER_OVR ADC_CR1_OVRIE + +#define ADC_ISR_ALLINTS (ADC_ISR_EOC | ADC_ISR_AWD | ADC_ISR_JEOC | \ + ADC_ISR_JEOS | ADC_ISR_OVR) +#define ADC_IER_ALLINTS (ADC_IER_EOC | ADC_IER_AWD | ADC_IER_JEOC | \ + ADC_IER_JEOS | ADC_IER_OVR) + +/* Low-level ops helpers ****************************************************/ + +#define AT32_ADC_INT_ACK(adc, source) \ + (adc)->llops->int_ack(adc, source) +#define AT32_ADC_INT_GET(adc) \ + (adc)->llops->int_get(adc) +#define AT32_ADC_INT_ENABLE(adc, source) \ + (adc)->llops->int_en(adc, source) +#define AT32_ADC_INT_DISABLE(adc, source) \ + (adc)->llops->int_dis(adc, source) +#define AT32_ADC_REGDATA_GET(adc) \ + (adc)->llops->val_get(adc) +#define AT32_ADC_REGBUF_REGISTER(adc, buffer, len) \ + (adc)->llops->regbuf_reg(adc, buffer, len) +#define AT32_ADC_REG_STARTCONV(adc, state) \ + (adc)->llops->reg_startconv(adc, state) +#define AT32_ADC_OFFSET_SET(adc, ch, i, o) \ + (adc)->llops->offset_set(adc, ch, i, o) +#define AT32_ADC_EXTCFG_SET(adc, c) \ + (adc)->llops->extcfg_set(adc, c) +#define AT32_ADC_INJ_STARTCONV(adc, state) \ + (adc)->llops->inj_startconv(adc, state) +#define AT32_ADC_INJDATA_GET(adc, chan) \ + (adc)->llops->inj_get(adc, chan) +#define AT32_ADC_JEXTCFG_SET(adc, c) \ + (adc)->llops->jextcfg_set(adc, c) +#define AT32_ADC_SAMPLETIME_SET(adc, time_samples) \ + (adc)->llops->stime_set(adc, time_samples) +#define AT32_ADC_SAMPLETIME_WRITE(adc) \ + (adc)->llops->stime_write(adc) +#define AT32_ADC_DUMP_REGS(adc) \ + (adc)->llops->dump_regs(adc) +#define AT32_ADC_SETUP(adc) \ + (adc)->llops->setup(adc) +#define AT32_ADC_SHUTDOWN(adc) \ + (adc)->llops->shutdown(adc) +#define AT32_ADC_MULTICFG(adc, mode) \ + (adc)->llops->multi_cfg(adc, mode) +#define AT32_ADC_ENABLE(adc, en) \ + (adc)->llops->enable(adc, en) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* On AT32F43xx devices,VBAT and temperature sensor are + * connected to the same ADC internal channel (ADC1_IN18). + * Only one conversion, either temperature sensor or VBAT, must be selected + * at a time. When both conversion are enabled simultaneously, + * only the VBAT conversion is performed. + */ + +enum adc_io_cmds_e +{ +#if defined(HAVE_IP_ADC_V1) + IO_ENABLE_TEMPER_VOLT_CH, +#endif +#ifdef HAVE_ADC_VBAT + IO_ENABLE_DISABLE_VBAT_CH, +#endif + IO_ENABLE_DISABLE_AWDIE, + IO_ENABLE_DISABLE_EOCIE, + IO_ENABLE_DISABLE_JEOCIE, + IO_ENABLE_DISABLE_OVRIE, + IO_ENABLE_DISABLE_ALL_INTS, + IO_STOP_ADC, + IO_START_ADC, + IO_START_CONV, + IO_TRIGGER_REG, +#ifdef ADC_HAVE_INJECTED + IO_TRIGGER_INJ, +#endif +#ifdef HAVE_ADC_POWERDOWN + IO_ENABLE_DISABLE_PDI, + IO_ENABLE_DISABLE_PDD, + IO_ENABLE_DISABLE_PDD_PDI +#endif +}; + +/* ADC resolution can be reduced in order to perform faster conversion */ + +enum at32_adc_resoluton_e +{ + ADC_RESOLUTION_12BIT = 0, /* 12 bit */ + ADC_RESOLUTION_10BIT = 1, /* 10 bit */ + ADC_RESOLUTION_8BIT = 2, /* 8 bit */ + ADC_RESOLUTION_6BIT = 3 /* 6 bit */ +}; + +/* ADC multi mode selection */ + +enum at32_adc_multimode_e +{ + /* Independent mode */ + + ADC_MULTIMODE_INDEP = 0, /* Independent mode */ + + /* Dual mode */ + + ADC_MULTIMODE_RSISM2 = 1, /* Dual combined regular sim. + injected sim. */ + ADC_MULTIMODE_RSATM2 = 2, /* Dual combined regular sim. + alternate trigger */ + ADC_MULTIMODE_IMIS2 = 3, /* Dual combined interl. mode + injected sim. */ + ADC_MULTIMODE_ISM2 = 4, /* Dual injected simultaneous mode only */ + ADC_MULTIMODE_RSM2 = 5, /* Dual degular simultaneous mode only */ + ADC_MULTIMODE_IM2 = 6, /* Dual interleaved mode only */ + ADC_MULTIMODE_ATM2 = 7, /* Dual alternate trigger mode only */ + + /* Triple mode */ + + ADC_MULTIMODE_RSISM3 = 8, /* Triple combined regular sim. + injected sim. */ + ADC_MULTIMODE_RSATM3 = 9, /* Triple combined regular sim. + alternate trigger */ + ADC_MULTIMODE_IMIS3 = 10, /* Triple combined interl. mode + injected sim. */ + ADC_MULTIMODE_ISM3 = 11, /* Triple injected simultaneous mode only */ + ADC_MULTIMODE_RSM3 = 12, /* Triple degular simultaneous mode only */ + ADC_MULTIMODE_IM3 = 13, /* Triple interleaved mode only */ + ADC_MULTIMODE_ATM3 = 14, /* Triple alternate trigger mode only */ +}; + +#ifdef CONFIG_AT32_ADC_LL_OPS + +#ifdef CONFIG_AT32_ADC_CHANGE_SAMPLETIME + +/* Channel and sample time pair */ + +typedef struct adc_channel_s +{ + uint8_t channel:5; + + /* Sampling time individually for each channel. + * It differs between families + */ + + uint8_t sample_time:3; +} adc_channel_t; + +/* This structure will be used while setting channels to specified by the + * "channel-sample time" pairs' values + */ + +struct adc_sample_time_s +{ + adc_channel_t *channel; /* Array of channels */ + uint8_t channels_nbr:5; /* Number of channels in array */ + bool all_same:1; /* All channels will get the + * same value of the sample time */ + uint8_t all_ch_sample_time:3; /* Sample time for all channels */ +}; +#endif /* CONFIG_AT32_ADC_CHANGE_SAMPLETIME */ + +/* This structure provides the publicly visible representation of the + * "lower-half" ADC driver structure. + */ + +struct at32_adc_dev_s +{ + /* Publicly visible portion of the "lower-half" ADC driver structure */ + + const struct at32_adc_ops_s *llops; + + /* Require cast-compatibility with private "lower-half" ADC structure */ +}; + +/* Low-level operations for ADC */ + +struct at32_adc_ops_s +{ + /* Low-level ADC setup */ + + int (*setup)(struct at32_adc_dev_s *dev); + + /* Low-level ADC shutdown */ + + void (*shutdown)(struct at32_adc_dev_s *dev); + + /* Acknowledge interrupts */ + + void (*int_ack)(struct at32_adc_dev_s *dev, uint32_t source); + + /* Get pending interrupts */ + + uint32_t (*int_get)(struct at32_adc_dev_s *dev); + + /* Enable interrupts */ + + void (*int_en)(struct at32_adc_dev_s *dev, uint32_t source); + + /* Disable interrupts */ + + void (*int_dis)(struct at32_adc_dev_s *dev, uint32_t source); + + /* Get current ADC data register */ + + uint32_t (*val_get)(struct at32_adc_dev_s *dev); + + /* Register buffer for ADC DMA transfer */ + + int (*regbuf_reg)(struct at32_adc_dev_s *dev, + uint16_t *buffer, uint8_t len); + + /* Start/stop regular conversion */ + + void (*reg_startconv)(struct at32_adc_dev_s *dev, bool state); + + /* Set offset for channel */ + + int (*offset_set)(struct at32_adc_dev_s *dev, uint8_t ch, uint8_t i, + uint16_t offset); + +#ifdef ADC_HAVE_EXTCFG + /* Configure the ADC external trigger for regular conversion */ + + void (*extcfg_set)(struct at32_adc_dev_s *dev, uint32_t extcfg); +#endif + +#ifdef ADC_HAVE_JEXTCFG + /* Configure the ADC external trigger for injected conversion */ + + void (*jextcfg_set)(struct at32_adc_dev_s *dev, uint32_t jextcfg); +#endif + +#ifdef ADC_HAVE_INJECTED + /* Get current ADC injected data register */ + + uint32_t (*inj_get)(struct at32_adc_dev_s *dev, uint8_t chan); + + /* Start/stop injected conversion */ + + void (*inj_startconv)(struct at32_adc_dev_s *dev, bool state); +#endif + +#ifdef CONFIG_AT32_ADC_CHANGE_SAMPLETIME + /* Set ADC sample time */ + + void (*stime_set)(struct at32_adc_dev_s *dev, + struct adc_sample_time_s *time_samples); + + /* Write ADC sample time */ + + void (*stime_write)(struct at32_adc_dev_s *dev); +#endif + + void (*dump_regs)(struct at32_adc_dev_s *dev); + + /* Configure ADC multi mode */ + + int (*multi_cfg)(struct at32_adc_dev_s *dev, uint8_t mode); + + /* Enable/disable ADC */ + + void (*enable)(struct at32_adc_dev_s *dev, bool enable); +}; + +#endif /* CONFIG_AT32_ADC_LL_OPS */ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: at32_adcinitialize + * + * Description: + * Initialize the ADC. See at32_adc.c for more details. + * + * Input Parameters: + * intf - Could be {1,2,3,4} for ADC1, ADC2, ADC3 + * chanlist - The list of channels (regular + injected) + * nchannels - Number of channels (regular + injected) + * + * Returned Value: + * Valid ADC device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct adc_dev_s; +struct adc_dev_s *at32_adcinitialize(int intf, const uint8_t *chanlist, + int channels); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* CONFIG_AT32_ADC1 || CONFIG_AT32_ADC2 || + * CONFIG_AT32_ADC3 + */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_ADC_H */ diff --git a/arch/arm/src/at32/at32_allocateheap.c b/arch/arm/src/at32/at32_allocateheap.c new file mode 100644 index 0000000000..7906f91d9c --- /dev/null +++ b/arch/arm/src/at32/at32_allocateheap.c @@ -0,0 +1,309 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_allocateheap.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "chip.h" + +#include "mpu.h" +#include "arm_internal.h" +#include "at32_mpuinit.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Internal SRAM is available in all members of the AT32 family. The + * following definitions must be provided to specify the size and + * location of internal(system) SRAM: + * + * CONFIG_RAM_END : End address (+1) of SRAM + * + * The F4 family also contains internal CCM SRAM. This SRAM is different + * because it cannot be used for DMA. So if DMA needed, then the following + * should be defined to exclude CCM SRAM from the heap: + * + * + * In addition to internal SRAM, external RAM may also be available through + * the FMC/FSMC. To use external RAM, the following things need to be present + * in the NuttX configuration file: + * + * CONFIG_AT32_FSMC=y : Enables the FSMC + * CONFIG_AT32_FMC=y : Enables the FMC + * CONFIG_AT32_EXTERNAL_RAM=y : Indicates external RAM is available via the + * FMC/FSMC (as opposed to an LCD or FLASH). + * CONFIG_HEAP2_BASE : The base address of the external RAM + * CONFIG_HEAP2_SIZE : The size of the external RAM + * CONFIG_MM_REGIONS : Must be set to a large enough value to + * include the external RAM (as determined by + * the rules provided below) + */ + +#if !defined(CONFIG_AT32_FSMC) && !defined(CONFIG_AT32_FMC) +# undef CONFIG_AT32_EXTERNAL_RAM +#endif + +/* For the AT32F43XXX family, all internal SRAM is in one contiguous + * block starting at g_idle_topstack and extending through CONFIG_RAM_END + * (my apologies for the bad naming). In addition, external FSMC SRAM + * may be available. + */ + +#if defined(CONFIG_AT32_AT32F43XX) + +/* Set the end of system SRAM */ + +# define SRAM1_END 0x20060000 + +/* Check if external FSMC SRAM is provided */ + +# ifdef CONFIG_AT32_EXTERNAL_RAM +# if CONFIG_MM_REGIONS < 2 +# warning "FSMC SRAM not included in the heap" +# undef CONFIG_AT32_EXTERNAL_RAM +# elif CONFIG_MM_REGIONS > 2 +# error "CONFIG_MM_REGIONS > 2 but I don't know what some of the region(s) are" +# undef CONFIG_MM_REGIONS +# define CONFIG_MM_REGIONS 2 +# endif +# elif CONFIG_MM_REGIONS > 1 +# error "CONFIG_MM_REGIONS > 1 but I don't know what the other region(s) are" +# endif + +#else +# error "Unsupported AT32 chip" +#endif + +/* If FSMC SRAM is going to be used as heap, then verify that the starting + * address and size of the external SRAM region has been provided in the + * configuration (as CONFIG_HEAP2_BASE and CONFIG_HEAP2_SIZE). + */ + +#ifdef CONFIG_AT32_EXTERNAL_RAM +# if !defined(CONFIG_HEAP2_BASE) || !defined(CONFIG_HEAP2_SIZE) +# error "CONFIG_HEAP2_BASE and CONFIG_HEAP2_SIZE must be provided" +# undef CONFIG_AT32_EXTERNAL_RAM +# endif +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_heap_color + * + * Description: + * Set heap memory to a known, non-zero state to checking heap usage. + * + ****************************************************************************/ + +#ifdef CONFIG_HEAP_COLORATION +static inline void up_heap_color(void *start, size_t size) +{ + memset(start, HEAP_COLOR, size); +} +#else +# define up_heap_color(start,size) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_allocate_heap + * + * Description: + * This function will be called to dynamically set aside the heap region. + * + * For the kernel build (CONFIG_BUILD_PROTECTED=y) with both kernel- and + * user-space heaps (CONFIG_MM_KERNEL_HEAP=y), this function provides the + * size of the unprotected, user-space heap. + * + * If a protected kernel-space heap is provided, the kernel heap must be + * allocated (and protected) by an analogous up_allocate_kheap(). + * + * The following memory map is assumed for the flat build: + * + * .data region. Size determined at link time. + * .bss region Size determined at link time. + * IDLE thread stack. Size determined by CONFIG_IDLETHREAD_STACKSIZE. + * Heap. Extends to the end of SRAM. + * + * The following memory map is assumed for the kernel build: + * + * Kernel .data region Size determined at link time + * Kernel .bss region Size determined at link time + * Kernel IDLE thread stack Size determined by + * CONFIG_IDLETHREAD_STACKSIZE + * Padding for alignment + * User .data region Size determined at link time + * User .bss region Size determined at link time + * Kernel heap Size determined by + * CONFIG_MM_KERNEL_HEAPSIZE + * User heap Extends to the end of SRAM + * + ****************************************************************************/ + +void up_allocate_heap(void **heap_start, size_t *heap_size) +{ +#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) + /* Get the unaligned size and position of the user-space heap. + * This heap begins after the user-space .bss section at an offset + * of CONFIG_MM_KERNEL_HEAPSIZE (subject to alignment). + */ + + uintptr_t ubase = (uintptr_t)USERSPACE->us_bssend + + CONFIG_MM_KERNEL_HEAPSIZE; + size_t usize = SRAM1_END - ubase; + int log2; + + DEBUGASSERT(ubase < (uintptr_t)SRAM1_END); + + /* Adjust that size to account for MPU alignment requirements. + * NOTE that there is an implicit assumption that the SRAM1_END + * is aligned to the MPU requirement. + */ + + log2 = (int)mpu_log2regionfloor(usize); + + usize = (1 << log2); + ubase = SRAM1_END - usize; + + /* Return the user-space heap settings */ + + board_autoled_on(LED_HEAPALLOCATE); + *heap_start = (void *)ubase; + *heap_size = usize; + + /* Colorize the heap for debug */ + + up_heap_color((void *)ubase, usize); + + /* Allow user-mode access to the user heap memory */ + + at32_mpu_uheap((uintptr_t)ubase, usize); +#else + + /* Return the heap settings */ + + board_autoled_on(LED_HEAPALLOCATE); + *heap_start = (void *)g_idle_topstack; + *heap_size = SRAM1_END - g_idle_topstack; + + /* Colorize the heap for debug */ + + up_heap_color(*heap_start, *heap_size); +#endif +} + +/**************************************************************************** + * Name: up_allocate_kheap + * + * Description: + * For the kernel build (CONFIG_BUILD_PROTECTED=y) with both kernel- and + * user-space heaps (CONFIG_MM_KERNEL_HEAP=y), this function allocates + * (and protects) the kernel-space heap. + * + ****************************************************************************/ + +#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) +void up_allocate_kheap(void **heap_start, size_t *heap_size) +{ + /* Get the unaligned size and position of the user-space heap. + * This heap begins after the user-space .bss section at an offset + * of CONFIG_MM_KERNEL_HEAPSIZE (subject to alignment). + */ + + uintptr_t ubase = (uintptr_t)USERSPACE->us_bssend + + CONFIG_MM_KERNEL_HEAPSIZE; + size_t usize = SRAM1_END - ubase; + int log2; + + DEBUGASSERT(ubase < (uintptr_t)SRAM1_END); + + /* Adjust that size to account for MPU alignment requirements. + * NOTE that there is an implicit assumption that the SRAM1_END + * is aligned to the MPU requirement. + */ + + log2 = (int)mpu_log2regionfloor(usize); + + usize = (1 << log2); + ubase = SRAM1_END - usize; + + /* Return the kernel heap settings (i.e., the part of the heap region + * that was not dedicated to the user heap). + */ + + *heap_start = (void *)USERSPACE->us_bssend; + *heap_size = ubase - (uintptr_t)USERSPACE->us_bssend; +} +#endif + +/**************************************************************************** + * Name: arm_addregion + * + * Description: + * Memory may be added in non-contiguous chunks. Additional chunks are + * added by calling this function. + * + ****************************************************************************/ + +#if CONFIG_MM_REGIONS > 1 +void arm_addregion(void) +{ +#ifdef CONFIG_AT32_EXTERNAL_RAM +#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) + + /* Allow user-mode access to the FSMC SRAM user heap memory */ + + at32_mpu_uheap((uintptr_t)CONFIG_HEAP2_BASE, CONFIG_HEAP2_SIZE); + +#endif + + /* Colorize the heap for debug */ + + up_heap_color((void *)CONFIG_HEAP2_BASE, CONFIG_HEAP2_SIZE); + + /* Add the external FSMC SRAM user heap region. */ + + kumm_addregion((void *)CONFIG_HEAP2_BASE, CONFIG_HEAP2_SIZE); +#endif +} +#endif diff --git a/arch/arm/src/at32/at32_can.c b/arch/arm/src/at32/at32_can.c new file mode 100644 index 0000000000..3470111a7d --- /dev/null +++ b/arch/arm/src/at32/at32_can.c @@ -0,0 +1,2535 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_can.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32.h" +#include "at32_rcc.h" +#include "at32_can.h" + +#if defined(CONFIG_CAN) && \ + (defined(CONFIG_AT32_CAN1) || defined(CONFIG_AT32_CAN2)) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Delays *******************************************************************/ + +/* Time out for INAK bit */ + +#define INAK_TIMEOUT 65535 + +/* Bit timing ***************************************************************/ + +#define CAN_BIT_QUANTA (CONFIG_AT32_CAN_TSEG1 + CONFIG_AT32_CAN_TSEG2 + 1) + +#ifndef CONFIG_DEBUG_CAN_INFO +# undef CONFIG_AT32_CAN_REGDEBUG +#endif + +/* CAN error interrupts */ + +#ifdef CONFIG_CAN_ERRORS +# define AT32_CAN_ERRINT (CAN_INTEN_ETRIEN | CAN_INTEN_EOIEN | \ + CAN_INTEN_BOIEN | CAN_INTEN_EPIEN | \ + CAN_INTEN_EAIEN) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct at32_can_s +{ + uint8_t port; /* CAN port number (1 or 2) */ + uint8_t canrx[2]; /* CAN RX FIFO 0/1 IRQ number */ + uint8_t cantx; /* CAN TX IRQ number */ +#ifdef CONFIG_CAN_ERRORS + uint8_t cansce; /* CAN SCE IRQ number */ +#endif + uint8_t filter; /* Filter number */ + uint32_t base; /* Base address of the CAN control registers */ + uint32_t fbase; /* Base address of the CAN filter registers */ + uint32_t baud; /* Configured baud */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* CAN Register access */ + +static uint32_t at32can_getreg(struct at32_can_s *priv, + int offset); +static uint32_t at32can_getfreg(struct at32_can_s *priv, + int offset); +static void at32can_putreg(struct at32_can_s *priv, int offset, + uint32_t value); +static void at32can_putfreg(struct at32_can_s *priv, int offset, + uint32_t value); +#ifdef CONFIG_AT32_CAN_REGDEBUG +static void at32can_dumpctrlregs(struct at32_can_s *priv, + const char *msg); +static void at32can_dumpmbregs(struct at32_can_s *priv, + const char *msg); +static void at32can_dumpfiltregs(struct at32_can_s *priv, + const char *msg); +#else +# define at32can_dumpctrlregs(priv,msg) +# define at32can_dumpmbregs(priv,msg) +# define at32can_dumpfiltregs(priv,msg) +#endif + +/* Filtering (todo) */ + +#ifdef CONFIG_CAN_EXTID +static int at32can_addextfilter(struct at32_can_s *priv, + struct canioc_extfilter_s *arg); +static int at32can_delextfilter(struct at32_can_s *priv, + int arg); +#endif +static int at32can_addstdfilter(struct at32_can_s *priv, + struct canioc_stdfilter_s *arg); +static int at32can_delstdfilter(struct at32_can_s *priv, + int arg); + +/* CAN driver methods */ + +static void at32can_reset(struct can_dev_s *dev); +static int at32can_setup(struct can_dev_s *dev); +static void at32can_shutdown(struct can_dev_s *dev); +static void at32can_rxint(struct can_dev_s *dev, bool enable); +static void at32can_txint(struct can_dev_s *dev, bool enable); +static int at32can_ioctl(struct can_dev_s *dev, int cmd, + unsigned long arg); +static int at32can_remoterequest(struct can_dev_s *dev, + uint16_t id); +static int at32can_send(struct can_dev_s *dev, + struct can_msg_s *msg); +static bool at32can_txready(struct can_dev_s *dev); +static bool at32can_txempty(struct can_dev_s *dev); + +#ifdef CONFIG_CAN_ERRORS +static void at32can_errint(struct can_dev_s *dev, bool enable); +#endif + +/* CAN interrupt handling */ + +static int at32can_rxinterrupt(struct can_dev_s *dev, int rxmb); +static int at32can_rx0interrupt(int irq, void *context, void *arg); +static int at32can_rx1interrupt(int irq, void *context, void *arg); +static int at32can_txinterrupt(int irq, void *context, void *arg); +#ifdef CONFIG_CAN_ERRORS +static int at32can_sceinterrupt(int irq, void *context, void *arg); +#endif + +/* Initialization */ + +static int at32can_enterinitmode(struct at32_can_s *priv); +static int at32can_exitinitmode(struct at32_can_s *priv); +static int at32can_bittiming(struct at32_can_s *priv); +static int at32can_cellinit(struct at32_can_s *priv); +static int at32can_filterinit(struct at32_can_s *priv); + +/* TX mailbox status */ + +static bool at32can_txmb0empty(uint32_t tsr_regval); +static bool at32can_txmb1empty(uint32_t tsr_regval); +static bool at32can_txmb2empty(uint32_t tsr_regval); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct can_ops_s g_canops = +{ + .co_reset = at32can_reset, + .co_setup = at32can_setup, + .co_shutdown = at32can_shutdown, + .co_rxint = at32can_rxint, + .co_txint = at32can_txint, + .co_ioctl = at32can_ioctl, + .co_remoterequest = at32can_remoterequest, + .co_send = at32can_send, + .co_txready = at32can_txready, + .co_txempty = at32can_txempty, +}; + +#ifdef CONFIG_AT32_CAN1 +static struct at32_can_s g_can1priv = +{ + .port = 1, + .canrx = + { + AT32_IRQ_CAN1RX0, + AT32_IRQ_CAN1RX1, + }, + .cantx = AT32_IRQ_CAN1TX, +#ifdef CONFIG_CAN_ERRORS + .cansce = AT32_IRQ_CAN1SCE, +#endif + .filter = 0, + .base = AT32_CAN1_BASE, + .fbase = AT32_CAN1_BASE, + .baud = CONFIG_AT32_CAN1_BAUD, +}; + +static struct can_dev_s g_can1dev = +{ + .cd_ops = &g_canops, + .cd_priv = &g_can1priv, +}; +#endif + +#ifdef CONFIG_AT32_CAN2 +static struct at32_can_s g_can2priv = +{ + .port = 2, + .canrx = + { + AT32_IRQ_CAN2RX0, + AT32_IRQ_CAN2RX1, + }, + .cantx = AT32_IRQ_CAN2TX, +#ifdef CONFIG_CAN_ERRORS + .cansce = AT32_IRQ_CAN2SCE, +#endif + .filter = CAN_NFILTERS / 2, + .base = AT32_CAN2_BASE, + .fbase = AT32_CAN1_BASE, + .baud = CONFIG_AT32_CAN2_BAUD, +}; + +static struct can_dev_s g_can2dev = +{ + .cd_ops = &g_canops, + .cd_priv = &g_can2priv, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32can_getreg + * Name: at32can_getfreg + * + * Description: + * Read the value of a CAN register or filter block register. + * + * Input Parameters: + * priv - A reference to the CAN block status + * offset - The offset to the register to read + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_REGDEBUG +static uint32_t at32can_vgetreg(uint32_t addr) +{ + static uint32_t prevaddr = 0; + static uint32_t preval = 0; + static uint32_t count = 0; + + /* Read the value from the register */ + + uint32_t val = getreg32(addr); + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (addr == prevaddr && val == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + caninfo("...\n"); + } + + return val; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + caninfo("[repeats %" PRIu32 " more times]\n", count - 3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + preval = val; + count = 1; + } + + /* Show the register value read */ + + caninfo("%08" PRIx32 "->%08" PRIx32 "\n", addr, val); + return val; +} + +static uint32_t at32can_getreg(struct at32_can_s *priv, int offset) +{ + return at32can_vgetreg(priv->base + offset); +} + +static uint32_t at32can_getfreg(struct at32_can_s *priv, int offset) +{ + return at32can_vgetreg(priv->fbase + offset); +} + +#else +static uint32_t at32can_getreg(struct at32_can_s *priv, int offset) +{ + return getreg32(priv->base + offset); +} + +static uint32_t at32can_getfreg(struct at32_can_s *priv, int offset) +{ + return getreg32(priv->fbase + offset); +} + +#endif + +/**************************************************************************** + * Name: at32can_putreg + * Name: at32can_putfreg + * + * Description: + * Set the value of a CAN register or filter block register. + * + * Input Parameters: + * priv - A reference to the CAN block status + * offset - The offset to the register to write + * value - The value to write to the register + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_REGDEBUG +static void at32can_vputreg(uint32_t addr, uint32_t value) +{ + /* Show the register value being written */ + + caninfo("%08" PRIx32 "->%08" PRIx32 "\n", addr, val); + + /* Write the value */ + + putreg32(value, addr); +} + +static void at32can_putreg(struct at32_can_s *priv, int offset, + uint32_t value) +{ + at32can_vputreg(priv->base + offset, value); +} + +static void at32can_putfreg(struct at32_can_s *priv, int offset, + uint32_t value) +{ + at32can_vputreg(priv->fbase + offset, value); +} + +#else +static void at32can_putreg(struct at32_can_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->base + offset); +} + +static void at32can_putfreg(struct at32_can_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->fbase + offset); +} +#endif + +/**************************************************************************** + * Name: at32can_dumpctrlregs + * + * Description: + * Dump the contents of all CAN control registers + * + * Input Parameters: + * priv - A reference to the CAN block status + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_REGDEBUG +static void at32can_dumpctrlregs(struct at32_can_s *priv, + const char *msg) +{ + if (msg) + { + caninfo("Control Registers: %s\n", msg); + } + else + { + caninfo("Control Registers:\n"); + } + + /* CAN control and status registers */ + + caninfo(" MCTRL: %08" PRIx32 " MSTS: %08" PRIx32 " \ + TSTS: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_MCTRL_OFFSET), + getreg32(priv->base + AT32_CAN_MSTS_OFFSET), + getreg32(priv->base + AT32_CAN_TSTS_OFFSET)); + + caninfo(" RF0: %08" PRIx32 " RF1: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_RF0_OFFSET), + getreg32(priv->base + AT32_CAN_RF1_OFFSET)); + + caninfo(" INTEN: %08" PRIx32 " ESTS: %08" PRIx32 " \ + BTMG: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_INTEN_OFFSET), + getreg32(priv->base + AT32_CAN_ESTS_OFFSET), + getreg32(priv->base + AT32_CAN_BTMG_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: at32can_dumpmbregs + * + * Description: + * Dump the contents of all CAN mailbox registers + * + * Input Parameters: + * priv - A reference to the CAN block status + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_REGDEBUG +static void at32can_dumpmbregs(struct at32_can_s *priv, + const char *msg) +{ + if (msg) + { + caninfo("Mailbox Registers: %s\n", msg); + } + else + { + caninfo("Mailbox Registers:\n"); + } + + /* CAN mailbox registers (3 TX and 2 RX) */ + + caninfo(" TMI0: %08" PRIx32 " TMC0: %08" PRIx32 " TMDTL0: %08" + PRIx32 " TMDTH0: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_TMI0_FFSET), + getreg32(priv->base + AT32_CAN_TMC0_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTL0_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTH0_OFFSET)); + + caninfo(" TMI1: %08" PRIx32 " TMC1: %08" PRIx32 " TMDTL1: %08" + PRIx32 " TMDTH1: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_TMI1_FFSET), + getreg32(priv->base + AT32_CAN_TMC1_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTL1_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTH1_OFFSET)); + + caninfo(" TMI2: %08" PRIx32 " TMC2: %08" PRIx32 " TMDTL2: %08" + PRIx32 " TMDTH2: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_TMI2_FFSET), + getreg32(priv->base + AT32_CAN_TMC2_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTL2_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTH2_OFFSET)); + + caninfo(" RFI0: %08" PRIx32 " RFC0: %08" PRIx32 " RFDTL0: %08" + PRIx32 " RFDTH0: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_RFI0_OFFSET), + getreg32(priv->base + AT32_CAN_RFC0_OFFSET), + getreg32(priv->base + AT32_CAN_RFDTL0_OFFSET), + getreg32(priv->base + AT32_CAN_RFDTH0_OFFSET)); + + caninfo(" RFI1: %08" PRIx32 " RFC1: %08" PRIx32 " RFDTL1: %08" + PRIx32 " RFDTH1: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_RFI1_OFFSET), + getreg32(priv->base + AT32_CAN_RFC1_OFFSET), + getreg32(priv->base + AT32_CAN_RFDTL1_OFFSET), + getreg32(priv->base + AT32_CAN_RFDTH1_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: at32can_dumpfiltregs + * + * Description: + * Dump the contents of all CAN filter registers + * + * Input Parameters: + * priv - A reference to the CAN block status + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_REGDEBUG +static void at32can_dumpfiltregs(struct at32_can_s *priv, + const char *msg) +{ + int i; + + if (msg) + { + caninfo("Filter Registers: %s\n", msg); + } + else + { + caninfo("Filter Registers:\n"); + } + + caninfo(" FCTRL: %08" PRIx32 " FMCFG: %08" PRIx32 " FSCFG: %08" + PRIx32 " FRF: %08" PRIx32 " FACFG: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_FCTRL_OFFSET), + getreg32(priv->base + AT32_CAN_FMCFG_OFFSET), + getreg32(priv->base + AT32_CAN_FSCFG_OFFSET), + getreg32(priv->base + AT32_CAN_FRF_OFFSET), + getreg32(priv->base + AT32_CAN_FACFG_OFFSET)); + + for (i = 0; i < CAN_NFILTERS; i++) + { + caninfo(" F%dR1: %08" PRIx32 " F%dR2: %08" PRIx32 "\n", + i, getreg32(priv->base + AT32_CAN_FBF_OFFSET(i, 1)), + i, getreg32(priv->base + AT32_CAN_FBF_OFFSET(i, 2))); + } +} +#endif + +/**************************************************************************** + * Name: at32can_reset + * + * Description: + * Reset the CAN device. Called early to initialize the hardware. This + * function is called, before at32can_setup() and on error conditions. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32can_reset(struct can_dev_s *dev) +{ + struct at32_can_s *priv = dev->cd_priv; + uint32_t regval; + uint32_t regbit = 0; + irqstate_t flags; + + caninfo("CAN%" PRIu8 "\n", priv->port); + + /* Get the bits in the AHB1RSTR register needed to reset this CAN device */ + +#ifdef CONFIG_AT32_CAN1 + if (priv->port == 1) + { + regbit = CRM_APB1RST_CAN1RST; + } + else +#endif +#ifdef CONFIG_AT32_CAN2 + if (priv->port == 2) + { + regbit = CRM_APB1RST_CAN1RST; + } + else +#endif + { + canerr("ERROR: Unsupported port %d\n", priv->port); + return; + } + + /* Disable interrupts momentarily to stop any ongoing CAN event processing + * and to prevent any concurrent access to the AHB1RSTR register. + */ + + flags = enter_critical_section(); + + /* Reset the CAN */ + + regval = getreg32(AT32_CRM_APB1RST); + regval |= regbit; + putreg32(regval, AT32_CRM_APB1RST); + + regval &= ~regbit; + putreg32(regval, AT32_CRM_APB1RST); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: at32can_setup + * + * Description: + * Configure the CAN. This method is called the first time that the CAN + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching CAN interrupts. + * All CAN interrupts are disabled upon return. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_setup(struct can_dev_s *dev) +{ + struct at32_can_s *priv = dev->cd_priv; + int ret; + +#ifdef CONFIG_CAN_ERRORS + ninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8 + " TX irq: %" PRIu8 " SCE irq: %" PRIu8 "\n", + priv->port, priv->canrx[0], priv->canrx[1], priv->cantx, + priv->cansce); +#else + ninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8 + " TX irq: %" PRIu8 "\n", + priv->port, priv->canrx[0], priv->canrx[1], priv->cantx); +#endif + + /* CAN cell initialization */ + + ret = at32can_cellinit(priv); + if (ret < 0) + { + canerr("ERROR: CAN%" PRId8 " cell initialization failed: %d\n", + priv->port, ret); + return ret; + } + + at32can_dumpctrlregs(priv, "After cell initialization"); + at32can_dumpmbregs(priv, NULL); + + /* CAN filter initialization */ + + ret = at32can_filterinit(priv); + if (ret < 0) + { + canerr("ERROR: CAN%" PRIu8 " filter initialization failed: %d\n", + priv->port, ret); + return ret; + } + + at32can_dumpfiltregs(priv, "After filter initialization"); + + /* Attach the CAN RX FIFO 0/1 interrupts and TX interrupts. + * The others are not used. + */ + + ret = irq_attach(priv->canrx[0], at32can_rx0interrupt, dev); + if (ret < 0) + { + canerr("ERROR: Failed to attach CAN%" PRIu8 " RX0 IRQ (%" PRIu8 ")", + priv->port, priv->canrx[0]); + return ret; + } + + ret = irq_attach(priv->canrx[1], at32can_rx1interrupt, dev); + if (ret < 0) + { + canerr("ERROR: Failed to attach CAN%" PRIu8 " RX1 IRQ (%" PRIu8 ")", + priv->port, priv->canrx[1]); + return ret; + } + + ret = irq_attach(priv->cantx, at32can_txinterrupt, dev); + if (ret < 0) + { + canerr("ERROR: Failed to attach CAN%" PRIu8 " TX IRQ (%" PRIu8 ")", + priv->port, priv->cantx); + return ret; + } + +#ifdef CONFIG_CAN_ERRORS + ret = irq_attach(priv->cansce, at32can_sceinterrupt, dev); + if (ret < 0) + { + nerr("ERROR: Failed to attach CAN%" PRIu8 " SCE IRQ (%" PRIu8 ")", + priv->port, priv->cansce); + return ret; + } + + /* Enable CAN error interrupts */ + + at32can_errint(dev, true); +#endif + + /* Enable the interrupts at the NVIC. Interrupts are still disabled in + * the CAN module. Since we coming out of reset here, there should be + * no pending interrupts. + */ + + up_enable_irq(priv->canrx[0]); + up_enable_irq(priv->canrx[1]); + up_enable_irq(priv->cantx); +#ifdef CONFIG_CAN_ERRORS + up_enable_irq(priv->cansce); +#endif + return OK; +} + +/**************************************************************************** + * Name: at32can_shutdown + * + * Description: + * Disable the CAN. This method is called when the CAN device is closed. + * This method reverses the operation the setup method. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32can_shutdown(struct can_dev_s *dev) +{ + struct at32_can_s *priv = dev->cd_priv; + + caninfo("CAN%" PRIu8 "\n", priv->port); + + /* Disable the RX FIFO 0/1, TX and SCE interrupts */ + + up_disable_irq(priv->canrx[0]); + up_disable_irq(priv->canrx[1]); + up_disable_irq(priv->cantx); +#ifdef CONFIG_CAN_ERRORS + up_disable_irq(priv->cansce); +#endif + + /* Detach the RX FIFO 0/1, TX and SCE interrupts */ + + irq_detach(priv->canrx[0]); + irq_detach(priv->canrx[1]); + irq_detach(priv->cantx); +#ifdef CONFIG_CAN_ERRORS + irq_detach(priv->cansce); +#endif + + /* And reset the hardware */ + + at32can_reset(dev); +} + +/**************************************************************************** + * Name: at32can_rxint + * + * Description: + * Call to enable or disable RX interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32can_rxint(struct can_dev_s *dev, bool enable) +{ + struct at32_can_s *priv = dev->cd_priv; + uint32_t regval; + + caninfo("CAN%" PRIu8 " rxint enable: %d\n", priv->port, enable); + + /* Enable/disable the FIFO 0/1 message pending interrupt */ + + regval = at32can_getreg(priv, AT32_CAN_INTEN_OFFSET); + if (enable) + { + regval |= CAN_INTEN_RF0MIEN | CAN_INTEN_RF1MIEN; + } + else + { + regval &= ~(CAN_INTEN_RF0MIEN | CAN_INTEN_RF1MIEN); + } + + at32can_putreg(priv, AT32_CAN_INTEN_OFFSET, regval); +} + +/**************************************************************************** + * Name: at32can_txint + * + * Description: + * Call to enable or disable TX interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32can_txint(struct can_dev_s *dev, bool enable) +{ + struct at32_can_s *priv = dev->cd_priv; + uint32_t regval; + + caninfo("CAN%" PRIu8 " txint enable: %d\n", priv->port, enable); + + /* Support only disabling the transmit mailbox interrupt */ + + if (!enable) + { + regval = at32can_getreg(priv, AT32_CAN_INTEN_OFFSET); + regval &= ~CAN_INTEN_TCIEN; + at32can_putreg(priv, AT32_CAN_INTEN_OFFSET, regval); + } +} + +#ifdef CONFIG_CAN_ERRORS +/**************************************************************************** + * Name: at32can_errint + * + * Description: + * Call to enable or disable CAN error interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32can_errint(struct can_dev_s *dev, bool enable) +{ + struct at32_can_s *priv = dev->cd_priv; + uint32_t regval = 0; + + caninfo("CAN%" PRIu8 " errint enable: %d\n", priv->port, enable); + + /* Enable/disable the transmit mailbox interrupt */ + + regval = at32can_getreg(priv, AT32_CAN_INTEN_OFFSET); + if (enable) + { + regval |= AT32_CAN_ERRINT; + } + else + { + regval &= ~AT32_CAN_ERRINT; + } + + at32can_putreg(priv, AT32_CAN_INTEN_OFFSET, regval); +} +#endif + +/**************************************************************************** + * Name: at32can_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_ioctl(struct can_dev_s *dev, int cmd, + unsigned long arg) +{ + struct at32_can_s *priv; + int ret = -ENOTTY; + + caninfo("cmd=%04x arg=%lu\n", cmd, arg); + + DEBUGASSERT(dev && dev->cd_priv); + priv = dev->cd_priv; + + /* Handle the command */ + + switch (cmd) + { + /* CANIOC_GET_BITTIMING: + * Description: Return the current bit timing settings + * Argument: A pointer to a write-able instance of struct + * canioc_bittiming_s in which current bit timing + * values will be returned. + * Returned Value: Zero (OK) is returned on success. Otherwise -1 + * (ERROR) is returned with the errno variable set + * to indicate the nature of the error. + * Dependencies: None + */ + + case CANIOC_GET_BITTIMING: + { + struct canioc_bittiming_s *bt = + (struct canioc_bittiming_s *)arg; + uint32_t regval; + uint32_t brp; + + DEBUGASSERT(bt != NULL); + regval = at32can_getreg(priv, AT32_CAN_BTMG_OFFSET); + bt->bt_sjw = ((regval & CAN_BTMG_RSAW_MASK) >> + CAN_BTMG_RSAW_SHIFT) + 1; + bt->bt_tseg1 = ((regval & CAN_BTMG_BTS1_MASK) >> + CAN_BTMG_BTS1_SHIFT) + 1; + bt->bt_tseg2 = ((regval & CAN_BTMG_BTS2_MASK) >> + CAN_BTMG_BTS2_SHIFT) + 1; + + brp = ((regval & CAN_BTMG_BRDIV_MASK) >> + CAN_BTMG_BRDIV_SHIFT) + 1; + bt->bt_baud = AT32_PCLK1_FREQUENCY / + (brp * (bt->bt_tseg1 + bt->bt_tseg2 + 1)); + ret = OK; + } + break; + + /* CANIOC_SET_BITTIMING: + * Description: Set new current bit timing values + * Argument: A pointer to a read-able instance of struct + * canioc_bittiming_s in which the new bit timing + * values are provided. + * Returned Value: Zero (OK) is returned on success. Otherwise -1 + * (ERROR)is returned with the errno variable set + * to indicate thenature of the error. + * Dependencies: None + * + * REVISIT: There is probably a limitation here: If there are + * multiple threads trying to send CAN packets, when one of these + * threads reconfigures the bitrate, the MCAN hardware will be reset + * and the context of operation will be lost. Hence, this IOCTL can + * only safely be executed in quiescent time periods. + */ + + case CANIOC_SET_BITTIMING: + { + const struct canioc_bittiming_s *bt = + (const struct canioc_bittiming_s *)arg; + uint32_t brp; + uint32_t can_bit_quanta; + uint32_t tmp; + uint32_t regval; + + DEBUGASSERT(bt != NULL); + DEBUGASSERT(bt->bt_baud < AT32_PCLK1_FREQUENCY); + DEBUGASSERT(bt->bt_sjw > 0 && bt->bt_sjw <= 4); + DEBUGASSERT(bt->bt_tseg1 > 0 && bt->bt_tseg1 <= 16); + DEBUGASSERT(bt->bt_tseg2 > 0 && bt->bt_tseg2 <= 8); + + regval = at32can_getreg(priv, AT32_CAN_BTMG_OFFSET); + + /* Extract bit timing data + * tmp is in clocks per bit time + */ + + tmp = AT32_PCLK1_FREQUENCY / bt->bt_baud; + + /* This value is dynamic as requested by user */ + + can_bit_quanta = bt->bt_tseg1 + bt->bt_tseg2 + 1; + + if (tmp < can_bit_quanta) + { + /* This timing is not possible */ + + ret = -EINVAL; + break; + } + + /* Otherwise, nquanta is can_bit_quanta, ts1 and ts2 are + * provided by the user and we calculate brp to achieve + * can_bit_quanta quanta in the bit times + */ + + else + { + brp = (tmp + (can_bit_quanta / 2)) / can_bit_quanta; + DEBUGASSERT(brp >= 1 && brp <= CAN_BTR_BRP_MAX); + } + + caninfo("TS1: %"PRIu8 " TS2: %" PRIu8 " BRP: %" PRIu32 "\n", + bt->bt_tseg1, bt->bt_tseg2, brp); + + /* Configure bit timing. */ + + regval &= ~(CAN_BTMG_BRDIV_MASK | CAN_BTMG_BTS1_MASK | + CAN_BTMG_BTS2_MASK | CAN_BTMG_RSAW_MASK); + regval |= ((brp - 1) << CAN_BTMG_BRDIV_SHIFT) | + ((bt->bt_tseg1 - 1) << CAN_BTMG_BTS1_SHIFT) | + ((bt->bt_tseg2 - 1) << CAN_BTMG_BTS2_SHIFT) | + ((bt->bt_sjw - 1) << CAN_BTMG_RSAW_SHIFT); + + /* Bit timing can only be configured in init mode. */ + + ret = at32can_enterinitmode(priv); + if (ret < 0) + { + break; + } + + at32can_putreg(priv, AT32_CAN_BTMG_OFFSET, regval); + + ret = at32can_exitinitmode(priv); + if (ret >= 0) + { + priv->baud = AT32_PCLK1_FREQUENCY / + (brp * (bt->bt_tseg1 + bt->bt_tseg2 + 1)); + } + } + break; + + /* CANIOC_GET_CONNMODES: + * Description: Get the current bus connection modes + * Argument: A pointer to a write-able instance of struct + * canioc_connmodes_s in which the new bus modes will + * be returned. + * Returned Value: Zero (OK) is returned on success. Otherwise -1 + * (ERROR)is returned with the errno variable set + * to indicate the nature of the error. + * Dependencies: None + */ + + case CANIOC_GET_CONNMODES: + { + struct canioc_connmodes_s *bm = + (struct canioc_connmodes_s *)arg; + uint32_t regval; + + DEBUGASSERT(bm != NULL); + + regval = at32can_getreg(priv, AT32_CAN_BTMG_OFFSET); + + bm->bm_loopback = ((regval & CAN_BTMG_LBEN) == CAN_BTMG_LBEN); + bm->bm_silent = ((regval & CAN_BTMG_LOEN) == CAN_BTMG_LOEN); + ret = OK; + break; + } + + /* CANIOC_SET_CONNMODES: + * Description: Set new bus connection modes values + * Argument: A pointer to a read-able instance of struct + * canioc_connmodes_s in which the new bus modes + * are provided. + * Returned Value: Zero (OK) is returned on success. Otherwise -1 + * (ERROR) is returned with the errno variable set + * to indicate the nature of the error. + * Dependencies: None + */ + + case CANIOC_SET_CONNMODES: + { + struct canioc_connmodes_s *bm = + (struct canioc_connmodes_s *)arg; + uint32_t regval; + + DEBUGASSERT(bm != NULL); + + regval = at32can_getreg(priv, AT32_CAN_BTMG_OFFSET); + + if (bm->bm_loopback) + { + regval |= CAN_BTMG_LBEN; + } + else + { + regval &= ~CAN_BTMG_LBEN; + } + + if (bm->bm_silent) + { + regval |= CAN_BTMG_LOEN; + } + else + { + regval &= ~CAN_BTMG_LOEN; + } + + /* This register can only be configured in init mode. */ + + ret = at32can_enterinitmode(priv); + if (ret < 0) + { + break; + } + + at32can_putreg(priv, AT32_CAN_BTMG_OFFSET, regval); + + ret = at32can_exitinitmode(priv); + } + break; + +#ifdef CONFIG_CAN_EXTID + /* CANIOC_ADD_EXTFILTER: + * Description: Add an address filter for a extended 29 bit + * address. + * Argument: A reference to struct canioc_extfilter_s + * Returned Value: A non-negative filter ID is returned on success. + * Otherwise -1 (ERROR) is returned with the errno + * variable set to indicate the nature of the error. + */ + + case CANIOC_ADD_EXTFILTER: + { + DEBUGASSERT(arg != 0); + ret = at32can_addextfilter(priv, + (struct canioc_extfilter_s *)arg); + } + break; + + /* CANIOC_DEL_EXTFILTER: + * Description: Remove an address filter for a standard 29 bit + * address. + * Argument: The filter index previously returned by the + * CANIOC_ADD_EXTFILTER command + * Returned Value: Zero (OK) is returned on success. Otherwise -1 + * (ERROR)is returned with the errno variable set + * to indicate the nature of the error. + */ + + case CANIOC_DEL_EXTFILTER: + { +#if 0 /* Unimplemented */ + DEBUGASSERT(arg <= priv->config->nextfilters); +#endif + ret = at32can_delextfilter(priv, (int)arg); + } + break; +#endif + + /* CANIOC_ADD_STDFILTER: + * Description: Add an address filter for a standard 11 bit + * address. + * Argument: A reference to struct canioc_stdfilter_s + * Returned Value: A non-negative filter ID is returned on success. + * Otherwise -1 (ERROR) is returned with the errno + * variable set to indicate the nature of the error. + */ + + case CANIOC_ADD_STDFILTER: + { + DEBUGASSERT(arg != 0); + ret = at32can_addstdfilter(priv, + (struct canioc_stdfilter_s *)arg); + } + break; + + /* CANIOC_DEL_STDFILTER: + * Description: Remove an address filter for a standard 11 bit + * address. + * Argument: The filter index previously returned by the + * CANIOC_ADD_STDFILTER command + * Returned Value: Zero (OK) is returned on success. Otherwise -1 + * (ERROR) is returned with the errno variable set + * to indicate the nature of the error. + */ + + case CANIOC_DEL_STDFILTER: + { +#if 0 /* Unimplemented */ + DEBUGASSERT(arg <= priv->config->nstdfilters); +#endif + ret = at32can_delstdfilter(priv, (int)arg); + } + break; + + case CANIOC_SET_NART: + { + uint32_t regval; + + ret = at32can_enterinitmode(priv); + if (ret != 0) + { + return ret; + } + + regval = at32can_getreg(priv, AT32_CAN_MCTRL_OFFSET); + if (arg == 1) + { + regval |= CAN_MCTRL_PRSFEN; + } + else + { + regval &= ~CAN_MCTRL_PRSFEN; + } + + at32can_putreg(priv, AT32_CAN_MCTRL_OFFSET, regval); + return at32can_exitinitmode(priv); + } + break; + + case CANIOC_SET_ABOM: + { + uint32_t regval; + + ret = at32can_enterinitmode(priv); + if (ret != 0) + { + return ret; + } + + regval = at32can_getreg(priv, AT32_CAN_MCTRL_OFFSET); + if (arg == 1) + { + regval |= CAN_MCTRL_AEBOEN; + } + else + { + regval &= ~CAN_MCTRL_AEBOEN; + } + + at32can_putreg(priv, AT32_CAN_MCTRL_OFFSET, regval); + return at32can_exitinitmode(priv); + } + break; + + /* Unsupported/unrecognized command */ + + default: + canerr("ERROR: Unrecognized command: %04x\n", cmd); + break; + } + + return ret; +} + +/**************************************************************************** + * Name: at32can_remoterequest + * + * Description: + * Send a remote request + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_remoterequest(struct can_dev_s *dev, uint16_t id) +{ +#warning "Remote request not implemented" + return -ENOSYS; +} + +/**************************************************************************** + * Name: at32can_send + * + * Description: + * Send one can message. + * + * One CAN-message consists of a maximum of 10 bytes. A message is + * composed of at least the first 2 bytes (when there are no data bytes). + * + * Byte 0: Bits 0-7: Bits 3-10 of the 11-bit CAN identifier + * Byte 1: Bits 5-7: Bits 0-2 of the 11-bit CAN identifier + * Bit 4: Remote Transmission Request (RTR) + * Bits 0-3: Data Length Code (DLC) + * Bytes 2-10: CAN data + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_send(struct can_dev_s *dev, + struct can_msg_s *msg) +{ + struct at32_can_s *priv = dev->cd_priv; + uint8_t *ptr; + uint32_t regval; + uint32_t tmp; + int dlc; + int txmb; + + caninfo("CAN%" PRIu8 " ID: %" PRIu32 " DLC: %" PRIu8 "\n", + priv->port, (uint32_t)msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc); + + /* Select one empty transmit mailbox */ + + regval = at32can_getreg(priv, AT32_CAN_TSTS_OFFSET); + if (at32can_txmb0empty(regval)) + { + txmb = 0; + } + else if (at32can_txmb1empty(regval)) + { + txmb = 1; + } + else if (at32can_txmb2empty(regval)) + { + txmb = 2; + } + else + { + canerr("ERROR: No available mailbox\n"); + return -EBUSY; + } + + /* Clear TXRQ, RTR, IDE, EXID, and STID fields */ + + regval = at32can_getreg(priv, AT32_CAN_TMI_OFFSET(txmb)); + regval &= ~(CAN_TMI_TMSR | CAN_TMI_TMFRSEL | CAN_TMI_TMIDSEL | + CAN_TMI_TMEID_MASK | CAN_TMI_TMSID_TMEID_MASK); + at32can_putreg(priv, AT32_CAN_TMI_OFFSET(txmb), regval); + + /* Set up the ID, standard 11-bit or extended 29-bit. */ + +#ifdef CONFIG_CAN_EXTID + regval &= ~CAN_TMI_TMEID_MASK; + if (msg->cm_hdr.ch_extid) + { + DEBUGASSERT(msg->cm_hdr.ch_id < (1 << 29)); + regval |= (msg->cm_hdr.ch_id << CAN_TMI_TMEID_SHIFT) | CAN_TMI_TMIDSEL; + } + else + { + DEBUGASSERT(msg->cm_hdr.ch_id < (1 << 11)); + regval |= msg->cm_hdr.ch_id << CAN_TMI_TMSID_TMEID_SHIFT; + } + +#else + regval |= (((uint32_t) msg->cm_hdr.ch_id << CAN_TMI_TMSID_TMEID_SHIFT) & + CAN_TMI_TMSID_TMEID_MASK); + +#endif + +#ifdef CONFIG_CAN_USE_RTR + regval |= (msg->cm_hdr.ch_rtr ? CAN_TMI_TMFRSEL : 0); +#endif + + at32can_putreg(priv, AT32_CAN_TMI_OFFSET(txmb), regval); + + /* Set up the DLC */ + + dlc = msg->cm_hdr.ch_dlc; + regval = at32can_getreg(priv, AT32_CAN_TMC_OFFSET(txmb)); + regval &= ~(CAN_TMC_TMDTBL_MASK | CAN_TMC_TMTSTEN); + regval |= (uint32_t)dlc << CAN_TMC_TMDTBL_SHIFT; + at32can_putreg(priv, AT32_CAN_TMC_OFFSET(txmb), regval); + + /* Set up the data fields */ + + ptr = msg->cm_data; + regval = 0; + + if (dlc > 0) + { + tmp = (uint32_t)*ptr++; + regval = tmp << CAN_TMDTL_TMDT0_SHIFT; + + if (dlc > 1) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTL_TMDT1_SHIFT; + + if (dlc > 2) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTL_TMDT2_SHIFT; + + if (dlc > 3) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTL_TMDT3_SHIFT; + } + } + } + } + + at32can_putreg(priv, AT32_CAN_TMDTL_OFFSET(txmb), regval); + + regval = 0; + if (dlc > 4) + { + tmp = (uint32_t)*ptr++; + regval = tmp << CAN_TMDTH_TMDT4_SHIFT; + + if (dlc > 5) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTH_TMDT5_SHIFT; + + if (dlc > 6) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTH_TMDT6_SHIFT; + + if (dlc > 7) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTH_TMDT7_SHIFT; + } + } + } + } + + at32can_putreg(priv, AT32_CAN_TMDTH_OFFSET(txmb), regval); + + /* Enable the transmit mailbox empty interrupt (may already be enabled) */ + + regval = at32can_getreg(priv, AT32_CAN_INTEN_OFFSET); + regval |= CAN_INTEN_TCIEN; + at32can_putreg(priv, AT32_CAN_INTEN_OFFSET, regval); + + /* Request transmission */ + + regval = at32can_getreg(priv, AT32_CAN_TMI_OFFSET(txmb)); + regval |= CAN_TMI_TMSR; /* Transmit Mailbox Request */ + at32can_putreg(priv, AT32_CAN_TMI_OFFSET(txmb), regval); + + at32can_dumpmbregs(priv, "After send"); + return OK; +} + +/**************************************************************************** + * Name: at32can_txready + * + * Description: + * Return true if the CAN hardware can accept another TX message. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * True if the CAN hardware is ready to accept another TX message. + * + ****************************************************************************/ + +static bool at32can_txready(struct can_dev_s *dev) +{ + struct at32_can_s *priv = dev->cd_priv; + uint32_t regval; + + /* Return true if any mailbox is available */ + + regval = at32can_getreg(priv, AT32_CAN_TSTS_OFFSET); + caninfo("CAN%" PRIu8 " TSTS: %08" PRIx32 "\n", priv->port, regval); + + return at32can_txmb0empty(regval) || at32can_txmb1empty(regval) || + at32can_txmb2empty(regval); +} + +/**************************************************************************** + * Name: at32can_txempty + * + * Description: + * Return true if all message have been sent. If for example, the CAN + * hardware implements FIFOs, then this would mean the transmit FIFO is + * empty. This method is called when the driver needs to make sure that + * all characters are "drained" from the TX hardware before calling + * co_shutdown(). + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * True if there are no pending TX transfers in the CAN hardware. + * + ****************************************************************************/ + +static bool at32can_txempty(struct can_dev_s *dev) +{ + struct at32_can_s *priv = dev->cd_priv; + uint32_t regval; + + /* Return true if all mailboxes are available */ + + regval = at32can_getreg(priv, AT32_CAN_TSTS_OFFSET); + caninfo("CAN%" PRIu8 " TSTS: %08" PRIx32 "\n", priv->port, regval); + + return at32can_txmb0empty(regval) && at32can_txmb1empty(regval) && + at32can_txmb2empty(regval); +} + +/**************************************************************************** + * Name: at32can_rxinterrupt + * + * Description: + * CAN RX FIFO 0/1 interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * rxmb - The RX mailbox number. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_rxinterrupt(struct can_dev_s *dev, int rxmb) +{ + struct at32_can_s *priv; + struct can_hdr_s hdr; + uint8_t data[CAN_MAXDATALEN]; + uint32_t regval; + int npending; + int ret; + + DEBUGASSERT(dev != NULL && dev->cd_priv != NULL); + priv = dev->cd_priv; + + /* Verify that a message is pending in the FIFO */ + + regval = at32can_getreg(priv, AT32_CAN_RF_OFFSET(rxmb)); + npending = (regval & CAN_RF_RFMN_MASK) >> CAN_RF_RFMN_SHIFT; + if (npending < 1) + { + canwarn("WARNING: No messages pending\n"); + return OK; + } + + if (rxmb == 0) + { + at32can_dumpmbregs(priv, "RX0 interrupt"); + } + else + { + at32can_dumpmbregs(priv, "RX1 interrupt"); + } + + /* Get the CAN identifier. */ + + regval = at32can_getreg(priv, AT32_CAN_RFI_OFFSET(rxmb)); + +#ifdef CONFIG_CAN_EXTID + if ((regval & CAN_RDI_RFIDI) != 0) + { + hdr.ch_id = \ + (regval & CAN_RDI_RFEID_MASK) >> CAN_RDI_RFEID_SHIFT; + hdr.ch_extid = true; + } + else + { + hdr.ch_id = \ + (regval & CAN_RDI_RFSID_RFEID_MASK) >> CAN_RDI_RFSID_RFEID_SHIFT; + hdr.ch_extid = false; + } +#else + if ((regval & CAN_RDI_RFIDI) != 0) + { + canerr("ERROR: Received message with extended identifier. Dropped\n"); + ret = -ENOSYS; + goto errout; + } + + hdr.ch_id = \ + (regval & CAN_RDI_RFSID_RFEID_MASK) >> CAN_RDI_RFSID_RFEID_SHIFT; +#endif + + /* Clear the error indication and unused bits */ + +#ifdef CONFIG_CAN_ERRORS + hdr.ch_error = 0; /* Error reporting not supported */ +#endif + hdr.ch_unused = 0; + + /* Extract the RTR bit */ + + hdr.ch_rtr = (regval & CAN_RDI_RFFRI) != 0; + + /* Get the DLC */ + + regval = at32can_getreg(priv, AT32_CAN_RFC_OFFSET(rxmb)); + hdr.ch_dlc = (regval & CAN_RFC_RFDTL_MASK) >> CAN_RFC_RFDTL_SHIFT; + + /* Save the message data */ + + regval = at32can_getreg(priv, AT32_CAN_RFDTL_OFFSET(rxmb)); + data[0] = (regval & CAN_RFDTL_RFDT0_MASK) >> CAN_RFDTL_RFDT0_SHIFT; + data[1] = (regval & CAN_RFDTL_RFDT1_MASK) >> CAN_RFDTL_RFDT1_SHIFT; + data[2] = (regval & CAN_RFDTL_RFDT2_MASK) >> CAN_RFDTL_RFDT2_SHIFT; + data[3] = (regval & CAN_RFDTL_RFDT3_MASK) >> CAN_RFDTL_RFDT3_SHIFT; + + regval = at32can_getreg(priv, AT32_CAN_RFDTH_OFFSET(rxmb)); + data[4] = (regval & CAN_RFDTH_RFDT4_MASK) >> CAN_RFDTH_RFDT4_SHIFT; + data[5] = (regval & CAN_RFDTH_RFDT5_MASK) >> CAN_RFDTH_RFDT5_SHIFT; + data[6] = (regval & CAN_RFDTH_RFDT6_MASK) >> CAN_RFDTH_RFDT6_SHIFT; + data[7] = (regval & CAN_RFDTH_RFDT7_MASK) >> CAN_RFDTH_RFDT7_SHIFT; + + /* Provide the data to the upper half driver */ + + ret = can_receive(dev, &hdr, data); + + /* Release the FIFO */ + +#ifndef CONFIG_CAN_EXTID +errout: +#endif + regval = at32can_getreg(priv, AT32_CAN_RF_OFFSET(rxmb)); + regval |= CAN_RF_RFR; + at32can_putreg(priv, AT32_CAN_RF_OFFSET(rxmb), regval); + return ret; +} + +/**************************************************************************** + * Name: at32can_rx0interrupt + * + * Description: + * CAN RX FIFO 0 interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_rx0interrupt(int irq, void *context, void *arg) +{ + struct can_dev_s *dev = (struct can_dev_s *)arg; + return at32can_rxinterrupt(dev, 0); +} + +/**************************************************************************** + * Name: at32can_rx1interrupt + * + * Description: + * CAN RX FIFO 1 interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_rx1interrupt(int irq, void *context, void *arg) +{ + struct can_dev_s *dev = (struct can_dev_s *)arg; + return at32can_rxinterrupt(dev, 1); +} + +/**************************************************************************** + * Name: at32can_txinterrupt + * + * Description: + * CAN TX mailbox complete interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_txinterrupt(int irq, void *context, void *arg) +{ + struct can_dev_s *dev = (struct can_dev_s *)arg; + struct at32_can_s *priv; + uint32_t regval; + + DEBUGASSERT(dev != NULL && dev->cd_priv != NULL); + priv = dev->cd_priv; + + /* Get the transmit status */ + + regval = at32can_getreg(priv, AT32_CAN_TSTS_OFFSET); + + /* Check for RQCP0: Request completed mailbox 0 */ + + if ((regval & CAN_TSTS_TM0TCF) != 0) + { + /* Writing '1' to RCP0 clears RCP0 and all the status bits (TXOK0, + * ALST0 and TERR0) for Mailbox 0. + */ + + at32can_putreg(priv, AT32_CAN_TSTS_OFFSET, CAN_TSTS_TM0TCF); + + /* Tell the upper half that the transfer is finished. */ + + can_txdone(dev); + } + + /* Check for RQCP1: Request completed mailbox 1 */ + + if ((regval & CAN_TSTS_TM1TCF) != 0) + { + /* Writing '1' to RCP1 clears RCP1 and all the status bits (TXOK1, + * ALST1 and TERR1) for Mailbox 1. + */ + + at32can_putreg(priv, AT32_CAN_TSTS_OFFSET, CAN_TSTS_TM1TCF); + + /* Tell the upper half that the transfer is finished. */ + + can_txdone(dev); + } + + /* Check for RQCP2: Request completed mailbox 2 */ + + if ((regval & CAN_TSTS_TM2TCF) != 0) + { + /* Writing '1' to RCP2 clears RCP2 and all the status bits (TXOK2, + * ALST2 and TERR2) for Mailbox 2. + */ + + at32can_putreg(priv, AT32_CAN_TSTS_OFFSET, CAN_TSTS_TM2TCF); + + /* Tell the upper half that the transfer is finished. */ + + can_txdone(dev); + } + + return OK; +} + +#ifdef CONFIG_CAN_ERRORS +/**************************************************************************** + * Name: at32can_sceinterrupt + * + * Description: + * CAN status change interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_sceinterrupt(int irq, void *context, void *arg) +{ + struct can_dev_s *dev = (struct can_dev_s *)arg; + struct at32_can_s *priv = NULL; + struct can_hdr_s hdr; + uint32_t regval = 0; + uint16_t errbits = 0; + uint8_t data[CAN_ERROR_DLC]; + int ret = OK; + + DEBUGASSERT(dev != NULL && dev->cd_priv != NULL); + priv = dev->cd_priv; + + /* Check Error Interrupt flag */ + + regval = at32can_getreg(priv, AT32_CAN_MSTS_OFFSET); + if (regval & CAN_MSTS_EOIF) + { + /* Encode error bits */ + + errbits = 0; + memset(data, 0, sizeof(data)); + + /* Get Error statur register */ + + regval = at32can_getreg(priv, AT32_CAN_ESTS_OFFSET); + + if (regval & CAN_ESTS_EAF) + { + /* Error warning flag */ + + data[1] |= (CAN_ERROR1_RXWARNING | CAN_ERROR1_TXWARNING); + errbits |= CAN_ERROR_CONTROLLER; + } + + if (regval & CAN_ESTS_EPF) + { + /* Error passive flag */ + + data[1] |= (CAN_ERROR1_RXPASSIVE | CAN_ERROR1_TXPASSIVE); + errbits |= CAN_ERROR_CONTROLLER; + } + + if (regval & CAN_ESTS_BOF) + { + /* Bus-off flag */ + + errbits |= CAN_ERROR_BUSOFF; + } + + /* Last error code */ + + if (regval & CAN_ESTS_ETR_MASK) + { + if (regval & CAN_ESTS_ETR_STUFF) + { + /* Stuff Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_STUFF; + } + else if (regval & CAN_ESTS_ETR_FORM) + { + /* Format Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_FORM; + } + else if (regval & CAN_ESTS_ETR_ACK) + { + /* Acknowledge Error */ + + errbits |= CAN_ERROR_NOACK; + } + else if (regval & CAN_ESTS_ETR_BREC) + { + /* Bit recessive Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_BIT1; + } + else if (regval & CAN_ESTS_ETR_BDOM) + { + /* Bit dominant Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_BIT0; + } + else if (regval & CAN_ESTS_ETR_CRC) + { + /* Receive CRC Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[3] |= CAN_ERROR3_CRCSEQ; + } + } + + /* Get transmit status register */ + + regval = at32can_getreg(priv, AT32_CAN_TSTS_OFFSET); + + if (regval & CAN_TSTS_TM0ALF || regval & CAN_TSTS_TM1ALF || + regval & CAN_TSTS_TM2ALF) + { + /* Lost arbitration Error */ + + errbits |= CAN_ERROR_LOSTARB; + } + + /* Clear TSR register */ + + at32can_putreg(priv, AT32_CAN_TSTS_OFFSET, regval); + + /* Clear ERRI flag */ + + at32can_putreg(priv, AT32_CAN_MSTS_OFFSET, CAN_MSTS_EOIF); + } + + /* TODO: RX overflow and TX overflow */ + + /* Report a CAN error */ + + if (errbits != 0) + { + canerr("ERROR: errbits = %08" PRIx16 "\n", errbits); + + /* Format the CAN header for the error report. */ + + hdr.ch_id = errbits; + hdr.ch_dlc = CAN_ERROR_DLC; + hdr.ch_rtr = 0; + hdr.ch_error = 1; +#ifdef CONFIG_CAN_EXTID + hdr.ch_extid = 0; +#endif + hdr.ch_unused = 0; + + /* And provide the error report to the upper half logic */ + + ret = can_receive(dev, &hdr, data); + if (ret < 0) + { + canerr("ERROR: can_receive failed: %d\n", ret); + } + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: at32can_bittiming + * + * Description: + * Set the CAN bit timing register (BTR) based on the configured BAUD. + * + * "The bit timing logic monitors the serial bus-line and performs sampling + * and adjustment of the sample point by synchronizing on the start-bit edge + * and resynchronizing on the following edges. + * + * "Its operation may be explained simply by splitting nominal bit time into + * three segments as follows: + * + * 1. "Synchronization segment (SYNC_SEG): a bit change is expected to occur + * within this time segment. It has a fixed length of one time quantum + * (1 x tCAN). + * 2. "Bit segment 1 (BS1): defines the location of the sample point. It + * includes the PROP_SEG and PHASE_SEG1 of the CAN standard. Its duration + * is programmable between 1 and 16 time quanta but may be automatically + * lengthened to compensate for positive phase drifts due to differences + * in the frequency of the various nodes of the network. + * 3. "Bit segment 2 (BS2): defines the location of the transmit point. It + * represents the PHASE_SEG2 of the CAN standard. Its duration is + * programmable between 1 and 8 time quanta but may also be automatically + * shortened to compensate for negative phase drifts." + * + * Pictorially: + * + * |<----------------- NOMINAL BIT TIME ----------------->| + * |<- SYNC_SEG ->|<------ BS1 ------>|<------ BS2 ------>| + * |<---- Tq ---->|<----- Tbs1 ------>|<----- Tbs2 ------>| + * + * Where + * Tbs1 is the duration of the BS1 segment + * Tbs2 is the duration of the BS2 segment + * Tq is the "Time Quantum" + * + * Relationships: + * + * baud = 1 / bit_time + * bit_time = Tq + Tbs1 + Tbs2 + * Tbs1 = Tq * ts1 + * Tbs2 = Tq * ts2 + * Tq = brp * Tpclk1 + * baud = Fpclk1 / (brp * (1 + ts1 + ts2)) + * + * Where: + * Tpclk1 is the period of the APB1 clock (PCLK1). + * + * Input Parameters: + * priv - A reference to the CAN block status + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_bittiming(struct at32_can_s *priv) +{ + uint32_t tmp; + uint32_t brp; + uint32_t ts1; + uint32_t ts2; + + caninfo("CAN%" PRIu8 " PCLK1: %lu baud: %" PRIu32 "\n", + priv->port, (unsigned long) AT32_PCLK1_FREQUENCY, priv->baud); + + /* Try to get CAN_BIT_QUANTA quanta in one bit_time. + * + * bit_time = Tq*(ts1 + ts2 + 1) + * nquanta = bit_time / Tq + * nquanta = (ts1 + ts2 + 1) + * + * bit_time = brp * Tpclk1 * (ts1 + ts2 + 1) + * nquanta = bit_time / brp / Tpclk1 + * = PCLK1 / baud / brp + * brp = PCLK1 / baud / nquanta; + * + * Example: + * PCLK1 = 42,000,000 baud = 1,000,000 nquanta = 14 : brp = 3 + * PCLK1 = 42,000,000 baud = 700,000 nquanta = 14 : brp = 4 + */ + + tmp = AT32_PCLK1_FREQUENCY / priv->baud; + if (tmp < CAN_BIT_QUANTA) + { + /* At the smallest brp value (1), there are already too few bit times + * (PCLCK1 / baud) to meet our goal. brp must be one and we need + * make some reasonable guesses about ts1 and ts2. + */ + + brp = 1; + + /* In this case, we have to guess a good value for ts1 and ts2 */ + + ts1 = (tmp - 1) >> 1; + ts2 = tmp - ts1 - 1; + if (ts1 == ts2 && ts1 > 1 && ts2 < CAN_BTR_TSEG2_MAX) + { + ts1--; + ts2++; + } + } + + /* Otherwise, nquanta is CAN_BIT_QUANTA, ts1 is CONFIG_AT32_CAN_TSEG1, + * ts2 is CONFIG_AT32_CAN_TSEG2 and we calculate brp to achieve + * CAN_BIT_QUANTA quanta in the bit time + */ + + else + { + ts1 = CONFIG_AT32_CAN_TSEG1; + ts2 = CONFIG_AT32_CAN_TSEG2; + brp = (tmp + (CAN_BIT_QUANTA / 2)) / CAN_BIT_QUANTA; + DEBUGASSERT(brp >= 1 && brp <= CAN_BTR_BRP_MAX); + } + + caninfo("TS1: %" PRIu32 " TS2: %" PRIu32 " BRP: %" PRIu32 "\n", + ts1, ts2, brp); + + /* Configure bit timing. This also does the following, less obvious + * things. Unless loopback mode is enabled, it: + * + * - Disables silent mode. + * - Disables loopback mode. + * + * NOTE that for the time being, SJW is set to 1 just because I don't + * know any better. + */ + + tmp = ((brp - 1) << CAN_BTMG_BRDIV_SHIFT) | \ + ((ts1 - 1) << CAN_BTMG_BTS1_SHIFT) | \ + ((ts2 - 1) << CAN_BTMG_BTS2_SHIFT) | \ + ((1 - 1) << CAN_BTMG_RSAW_SHIFT); + +#ifdef CONFIG_CAN_LOOPBACK + /* tmp |= (CAN_BTMG_LBEN | CAN_BTMG_LOEN); */ + + tmp |= CAN_BTMG_LBEN; +#endif + + at32can_putreg(priv, AT32_CAN_BTMG_OFFSET, tmp); + return OK; +} + +/**************************************************************************** + * Name: at32can_enterinitmode + * + * Description: + * Put the CAN cell in Initialization mode. This only disconnects the CAN + * peripheral, no registers are changed. The initialization mode is + * required to change the baud rate. + * + * Input Parameters: + * priv - A pointer to the private data structure for this CAN block + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32can_enterinitmode(struct at32_can_s *priv) +{ + uint32_t regval; + volatile uint32_t timeout; + + caninfo("CAN%" PRIu8 "\n", priv->port); + + /* Enter initialization mode */ + + regval = at32can_getreg(priv, AT32_CAN_MCTRL_OFFSET); + regval |= CAN_MCTRL_FZEN; + at32can_putreg(priv, AT32_CAN_MCTRL_OFFSET, regval); + + /* Wait until initialization mode is acknowledged */ + + for (timeout = INAK_TIMEOUT; timeout > 0; timeout--) + { + regval = at32can_getreg(priv, AT32_CAN_MSTS_OFFSET); + if ((regval & CAN_MSTS_FZC) != 0) + { + /* We are in initialization mode */ + + break; + } + } + + /* Check for a timeout */ + + if (timeout < 1) + { + canerr("ERROR: Timed out waiting to enter initialization mode\n"); + return -ETIMEDOUT; + } + + return OK; +} + +/**************************************************************************** + * Name: at32can_exitinitmode + * + * Description: + * Put the CAN cell out of the Initialization mode (to Normal mode) + * + * Input Parameters: + * priv - A pointer to the private data structure for this CAN block + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32can_exitinitmode(struct at32_can_s *priv) +{ + uint32_t regval; + volatile uint32_t timeout; + + /* Exit Initialization mode, enter Normal mode */ + + regval = at32can_getreg(priv, AT32_CAN_MCTRL_OFFSET); + regval &= ~CAN_MCTRL_FZEN; + at32can_putreg(priv, AT32_CAN_MCTRL_OFFSET, regval); + + /* Wait until the initialization mode exit is acknowledged */ + + for (timeout = INAK_TIMEOUT; timeout > 0; timeout--) + { + regval = at32can_getreg(priv, AT32_CAN_MSTS_OFFSET); + if ((regval & CAN_MSTS_FZC) == 0) + { + /* We are out of initialization mode */ + + break; + } + } + + /* Check for a timeout */ + + if (timeout < 1) + { + canerr("ERROR: Timed out waiting to exit initialization mode: %08" + PRIx32 "\n", regval); + return -ETIMEDOUT; + } + + return OK; +} + +/**************************************************************************** + * Name: at32can_cellinit + * + * Description: + * CAN cell initialization + * + * Input Parameters: + * priv - A pointer to the private data structure for this CAN block + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32can_cellinit(struct at32_can_s *priv) +{ + uint32_t regval; + int ret; + + caninfo("CAN%" PRIu8 "\n", priv->port); + + /* Exit from sleep mode */ + + regval = at32can_getreg(priv, AT32_CAN_MCTRL_OFFSET); + regval &= ~CAN_MCTRL_DZEN; + at32can_putreg(priv, AT32_CAN_MCTRL_OFFSET, regval); + + ret = at32can_enterinitmode(priv); + if (ret != 0) + { + return ret; + } + + /* Disable the following modes: + * + * - Time triggered communication mode + * - Automatic bus-off management + * - Automatic wake-up mode + * - No automatic retransmission + * - Receive FIFO locked mode + * + * Enable: + * + * - Transmit FIFO priority + */ + + regval = at32can_getreg(priv, AT32_CAN_MCTRL_OFFSET); + regval &= ~(CAN_MCTRL_MDRSEL | CAN_MCTRL_PRSFEN | CAN_MCTRL_AEDEN | + CAN_MCTRL_AEBOEN | CAN_MCTRL_TTCEN); + regval |= CAN_MCTRL_MMSSR; + at32can_putreg(priv, AT32_CAN_MCTRL_OFFSET, regval); + + /* Configure bit timing. */ + + ret = at32can_bittiming(priv); + if (ret < 0) + { + canerr("ERROR: Failed to set bit timing: %d\n", ret); + return ret; + } + + return at32can_exitinitmode(priv); +} + +/**************************************************************************** + * Name: at32can_filterinit + * + * Description: + * CAN filter initialization. CAN filters are not currently used by this + * driver. The CAN filters can be configured in a different way: + * + * 1. As a match of specific IDs in a list (IdList mode), or as + * 2. And ID and a mask (IdMask mode). + * + * Filters can also be configured as: + * + * 3. 16- or 32-bit. The advantage of 16-bit filters is that you get + * more filters; The advantage of 32-bit filters is that you get + * finer control of the filtering. + * + * One filter is set up for each CAN. The filter resources are shared + * between the two CAN modules: CAN1 uses only filter 0 (but reserves + * 0 through CAN_NFILTERS/2-1); CAN2 uses only filter CAN_NFILTERS/2 + * (but reserves CAN_NFILTERS/2 through CAN_NFILTERS-1). + * + * 32-bit IdMask mode is configured. However, both the ID and the MASK + * are set to zero thus suppressing all filtering because anything masked + * with zero matches zero. + * + * Input Parameters: + * priv - A pointer to the private data structure for this CAN block + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32can_filterinit(struct at32_can_s *priv) +{ + uint32_t regval; + uint32_t bitmask; + + caninfo("CAN%" PRIu8 " filter: %" PRIu8 "\n", priv->port, priv->filter); + + /* Get the bitmask associated with the filter used by this CAN block */ + + bitmask = (uint32_t)1 << priv->filter; + + /* Enter filter initialization mode */ + + regval = at32can_getfreg(priv, AT32_CAN_FCTRL_OFFSET); + regval |= CAN_FCTRL_FCS; + at32can_putfreg(priv, AT32_CAN_FCTRL_OFFSET, regval); + + /* Disable the filter */ + + regval = at32can_getfreg(priv, AT32_CAN_FACFG_OFFSET); + regval &= ~bitmask; + at32can_putfreg(priv, AT32_CAN_FACFG_OFFSET, regval); + + /* Select the 32-bit scale for the filter */ + + regval = at32can_getfreg(priv, AT32_CAN_FSCFG_OFFSET); + regval |= bitmask; + at32can_putfreg(priv, AT32_CAN_FSCFG_OFFSET, regval); + + /* There are 14 or 28 filter banks (depending) on the device. + * Each filter bank is composed of two 32-bit registers, CAN_FiR: + */ + + at32can_putfreg(priv, AT32_CAN_FBF_OFFSET(priv->filter, 1), 0); + at32can_putfreg(priv, AT32_CAN_FBF_OFFSET(priv->filter, 2), 0); + + /* Set Id/Mask mode for the filter */ + + regval = at32can_getfreg(priv, AT32_CAN_FMCFG_OFFSET); + regval &= ~bitmask; + at32can_putfreg(priv, AT32_CAN_FMCFG_OFFSET, regval); + + /* Assign FIFO 0 for the filter */ + + regval = at32can_getfreg(priv, AT32_CAN_FRF_OFFSET); + regval &= ~bitmask; + at32can_putfreg(priv, AT32_CAN_FRF_OFFSET, regval); + + /* Enable the filter */ + + regval = at32can_getfreg(priv, AT32_CAN_FACFG_OFFSET); + regval |= bitmask; + at32can_putfreg(priv, AT32_CAN_FACFG_OFFSET, regval); + + /* Exit filter initialization mode */ + + regval = at32can_getfreg(priv, AT32_CAN_FCTRL_OFFSET); + regval &= ~CAN_FCTRL_FCS; + at32can_putfreg(priv, AT32_CAN_FCTRL_OFFSET, regval); + return OK; +} + +/**************************************************************************** + * Name: at32can_addextfilter + * + * Description: + * Add a filter for extended CAN IDs + * + * Input Parameters: + * priv - A pointer to the private data structure for this CAN block + * arg - A pointer to a structure describing the filter + * + * Returned Value: + * A non-negative filter ID is returned on success. + * Otherwise -1 (ERROR) is returned with the errno + * set to indicate the nature of the error. + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_EXTID +static int at32can_addextfilter(struct at32_can_s *priv, + struct canioc_extfilter_s *arg) +{ + return -ENOTTY; +} +#endif + +/**************************************************************************** + * Name: at32can_delextfilter + * + * Description: + * Remove a filter for extended CAN IDs + * + * Input Parameters: + * priv - A pointer to the private data structure for this CAN block + * arg - The filter index previously returned by the + * CANIOC_ADD_EXTFILTER command + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise -1 (ERROR) + * returned with the errno variable set to indicate the + * of the error. + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_EXTID +static int at32can_delextfilter(struct at32_can_s *priv, int arg) +{ + return -ENOTTY; +} +#endif + +/**************************************************************************** + * Name: at32can_addstdfilter + * + * Description: + * Add a filter for standard CAN IDs + * + * Input Parameters: + * priv - A pointer to the private data structure for this CAN block + * arg - A pointer to a structure describing the filter + * + * Returned Value: + * A non-negative filter ID is returned on success. + * Otherwise -1 (ERROR) is returned with the errno + * set to indicate the nature of the error. + * + ****************************************************************************/ + +static int at32can_addstdfilter(struct at32_can_s *priv, + struct canioc_stdfilter_s *arg) +{ + return -ENOTTY; +} + +/**************************************************************************** + * Name: at32can_delstdfilter + * + * Description: + * Remove a filter for standard CAN IDs + * + * Input Parameters: + * priv - A pointer to the private data structure for this CAN block + * arg - The filter index previously returned by the + * CANIOC_ADD_STDFILTER command + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise -1 (ERROR) + * returned with the errno variable set to indicate the + * of the error. + * + ****************************************************************************/ + +static int at32can_delstdfilter(struct at32_can_s *priv, int arg) +{ + return -ENOTTY; +} + +/**************************************************************************** + * Name: at32can_txmb0empty + * + * Input Parameters: + * tsr_regval - value of CAN transmit status register + * + * Returned Value: + * Returns true if mailbox 0 is empty and can be used for sending. + * + ****************************************************************************/ + +static bool at32can_txmb0empty(uint32_t tsr_regval) +{ + return (tsr_regval & CAN_TSTS_TM0EF) != 0 && + (tsr_regval & CAN_TSTS_TM0TCF) == 0; +} + +/**************************************************************************** + * Name: at32can_txmb1empty + * + * Input Parameters: + * tsr_regval - value of CAN transmit status register + * + * Returned Value: + * Returns true if mailbox 1 is empty and can be used for sending. + * + ****************************************************************************/ + +static bool at32can_txmb1empty(uint32_t tsr_regval) +{ + return (tsr_regval & CAN_TSTS_TM1EF) != 0 && + (tsr_regval & CAN_TSTS_TM1TCF) == 0; +} + +/**************************************************************************** + * Name: at32can_txmb2empty + * + * Input Parameters: + * tsr_regval - value of CAN transmit status register + * + * Returned Value: + * Returns true if mailbox 2 is empty and can be used for sending. + * + ****************************************************************************/ + +static bool at32can_txmb2empty(uint32_t tsr_regval) +{ + return (tsr_regval & CAN_TSTS_TM2EF) != 0 && + (tsr_regval & CAN_TSTS_TM2TCF) == 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_caninitialize + * + * Description: + * Initialize the selected CAN port + * + * Input Parameters: + * Port number (for hardware that has multiple CAN interfaces) + * + * Returned Value: + * Valid CAN device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct can_dev_s *at32_caninitialize(int port) +{ + struct can_dev_s *dev = NULL; + + caninfo("CAN%" PRIu8 "\n", port); + + /* NOTE: Peripherical clocking for CAN1 and/or CAN2 was already provided + * by at32_clockconfig() early in the reset sequence. + */ + +#ifdef CONFIG_AT32_CAN1 + if (port == 1) + { + /* Select the CAN1 device structure */ + + dev = &g_can1dev; + + /* Configure CAN1 pins. The ambiguous settings in the at32*_pinmap.h + * file must have been disambiguated in the board.h file. + */ + + at32_configgpio(GPIO_CAN1_RX); + at32_configgpio(GPIO_CAN1_TX); + } + else +#endif +#ifdef CONFIG_AT32_CAN2 + if (port == 2) + { + /* Select the CAN2 device structure */ + + dev = &g_can2dev; + + /* Configure CAN2 pins. The ambiguous settings in the at32*_pinmap.h + * file must have been disambiguated in the board.h file. + */ + + at32_configgpio(GPIO_CAN2_RX); + at32_configgpio(GPIO_CAN2_TX); + } + else +#endif + { + canerr("ERROR: Unsupported port %d\n", port); + return NULL; + } + + return dev; +} + +#endif /* CONFIG_CAN && (CONFIG_AT32_CAN1 || CONFIG_AT32_CAN2) */ diff --git a/arch/arm/src/at32/at32_can.h b/arch/arm/src/at32/at32_can.h new file mode 100644 index 0000000000..c5c44ba7a8 --- /dev/null +++ b/arch/arm/src/at32/at32_can.h @@ -0,0 +1,152 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_can.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_CAN_H +#define __ARCH_ARM_SRC_AT32_AT32_CAN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" +#include "hardware/at32_can.h" + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Up to 2 CAN interfaces are supported */ + +#if AT32_NCAN < 2 +# undef CONFIG_AT32_CAN2 +#endif + +#if AT32_NCAN < 1 +# undef CONFIG_AT32_CAN1 +#endif + +/* CAN BAUD */ + +#if defined(CONFIG_AT32_CAN1) && !defined(CONFIG_AT32_CAN1_BAUD) +# error "CONFIG_AT32_CAN1_BAUD is not defined" +#endif + +#if defined(CONFIG_AT32_CAN2) && !defined(CONFIG_AT32_CAN2_BAUD) +# error "CONFIG_AT32_CAN2_BAUD is not defined" +#endif + +/* User-defined TSEG1 and TSEG2 settings may be used. + * + * CONFIG_AT32_CAN_TSEG1 = the number of CAN time quanta in segment 1 + * CONFIG_AT32_CAN_TSEG2 = the number of CAN time quanta in segment 2 + * CAN_BIT_QUANTA = The number of CAN time quanta in on bit time + */ + +#ifndef CONFIG_AT32_CAN_TSEG1 +# define CONFIG_AT32_CAN_TSEG1 13 +#endif + +#if CONFIG_AT32_CAN_TSEG1 < 1 || CONFIG_AT32_CAN_TSEG1 > CAN_BTR_TSEG1_MAX +# error "CONFIG_AT32_CAN_TSEG1 is out of range" +#endif + +#ifndef CONFIG_AT32_CAN_TSEG2 +# define CONFIG_AT32_CAN_TSEG2 2 +#endif + +#if CONFIG_AT32_CAN_TSEG2 < 1 || CONFIG_AT32_CAN_TSEG2 > CAN_BTR_TSEG2_MAX +# error "CONFIG_AT32_CAN_TSEG2 is out of range" +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_CHARDRIVER + +/**************************************************************************** + * Name: at32_caninitialize + * + * Description: + * Initialize the selected CAN port as character device + * + * Input Parameters: + * Port number (for hardware that has multiple CAN interfaces) + * + * Returned Value: + * Valid CAN device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct can_dev_s; +struct can_dev_s *at32_caninitialize(int port); +#endif + +#ifdef CONFIG_AT32_CAN_SOCKET + +/**************************************************************************** + * Name: at32_cansockinitialize + * + * Description: + * Initialize the selected CAN port as SocketCAN interface + * + * Input Parameters: + * Port number (for hardware that has multiple CAN interfaces) + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int at32_cansockinitialize(int port); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_CAN_H */ diff --git a/arch/arm/src/at32/at32_can_sock.c b/arch/arm/src/at32/at32_can_sock.c new file mode 100644 index 0000000000..72a84a1d82 --- /dev/null +++ b/arch/arm/src/at32/at32_can_sock.c @@ -0,0 +1,2484 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_can_sock.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32.h" +#include "at32_rcc.h" +#include "at32_can.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Delays *******************************************************************/ + +/* Time out for INAK bit */ + +#define INAK_TIMEOUT 65535 + +/* Bit timing ***************************************************************/ + +#define CAN_BIT_QUANTA (CONFIG_AT32_CAN_TSEG1 + CONFIG_AT32_CAN_TSEG2 + 1) + +#ifndef CONFIG_DEBUG_CAN_INFO +# undef CONFIG_AT32_CAN_REGDEBUG +#endif + +/* Pool configuration *******************************************************/ + +#define POOL_SIZE (1) + +/* Work queue support is required. */ + +#if !defined(CONFIG_SCHED_WORKQUEUE) +# error Work queue support is required +#endif + +/* The low priority work queue is preferred. If it is not enabled, LPWORK + * will be the same as HPWORK. + * + * NOTE: However, the network should NEVER run on the high priority work + * queue! That queue is intended only to service short back end interrupt + * processing that never suspends. Suspending the high priority work queue + * may bring the system to its knees! + */ + +#define CANWORK LPWORK + +/* CAN error interrupts */ + +#ifdef CONFIG_NET_CAN_ERRORS +# define AT32_CAN_ERRINT (CAN_INTEN_ETRIEN | CAN_INTEN_EOIEN | \ + CAN_INTEN_BOIEN | CAN_INTEN_EPIEN | \ + CAN_INTEN_EAIEN) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct at32_can_s +{ + uint8_t port; /* CAN port number (1 or 2) */ + uint8_t canrx[2]; /* CAN RX FIFO 0/1 IRQ number */ + uint8_t cantx; /* CAN TX IRQ number */ +#ifdef CONFIG_NET_CAN_ERRORS + uint8_t cansce; /* CAN SCE IRQ number */ +#endif + uint8_t filter; /* Filter number */ + uint32_t base; /* Base address of the CAN control registers */ + uint32_t fbase; /* Base address of the CAN filter registers */ + uint32_t baud; /* Configured baud */ + + bool bifup; /* true:ifup false:ifdown */ + struct net_driver_s dev; /* Interface understood by the network */ + + struct work_s irqwork; /* For deferring interrupt work to the wq */ + struct work_s pollwork; /* For deferring poll work to the work wq */ + + /* A pointers to the list of TX/RX descriptors */ + + struct can_frame *txdesc; + struct can_frame *rxdesc; + + /* TX/RX pool */ + + uint8_t tx_pool[sizeof(struct can_frame)*POOL_SIZE]; + uint8_t rx_pool[sizeof(struct can_frame)*POOL_SIZE]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* CAN Register access */ + +static uint32_t at32can_getreg(struct at32_can_s *priv, + int offset); +static uint32_t at32can_getfreg(struct at32_can_s *priv, + int offset); +static void at32can_putreg(struct at32_can_s *priv, int offset, + uint32_t value); +static void at32can_putfreg(struct at32_can_s *priv, int offset, + uint32_t value); +#ifdef CONFIG_AT32_CAN_REGDEBUG +static void at32can_dumpctrlregs(struct at32_can_s *priv, + const char *msg); +static void at32can_dumpmbregs(struct at32_can_s *priv, + const char *msg); +static void at32can_dumpfiltregs(struct at32_can_s *priv, + const char *msg); +#else +# define at32can_dumpctrlregs(priv,msg) +# define at32can_dumpmbregs(priv,msg) +# define at32can_dumpfiltregs(priv,msg) +#endif + +/* CAN interrupt enable functions */ + +static void at32can_rx0int(struct at32_can_s *priv, bool enable); +static void at32can_rx1int(struct at32_can_s *priv, bool enable); +static void at32can_txint(struct at32_can_s *priv, bool enable); +#ifdef CONFIG_NET_CAN_ERRORS +static void at32can_errint(struct at32_can_s *priv, bool enable); +#endif + +/* Common TX logic */ + +static int at32can_transmit(struct at32_can_s *priv); +static bool at32can_txready(struct at32_can_s *priv); +static int at32can_txpoll(struct net_driver_s *dev); + +/* CAN RX interrupt handling */ + +static int at32can_rxinterrupt_work(struct at32_can_s *priv, + int rxmb); + +static void at32can_rx0interrupt_work(void *arg); +static void at32can_rx1interrupt_work(void *arg); +static int at32can_rxinterrupt(struct at32_can_s *priv, int rxmb); + +static int at32can_rx0interrupt(int irq, void *context, void *arg); +static int at32can_rx1interrupt(int irq, void *context, void *arg); + +/* CAN TX interrupt handling */ + +static int at32can_txinterrupt(int irq, void *context, void *arg); +static void at32can_txdone_work(void *arg); +static void at32can_txdone(struct at32_can_s *priv); + +#ifdef CONFIG_NET_CAN_ERRORS +/* CAN errors interrupt handling */ + +static void at32can_sceinterrupt_work(void *arg); +static int at32can_sceinterrupt(int irq, void *context, void *arg); +#endif + +/* Initialization */ + +static int at32can_setup(struct at32_can_s *priv); +static void at32can_shutdown(struct at32_can_s *priv); +static void at32can_reset(struct at32_can_s *priv); +static int at32can_enterinitmode(struct at32_can_s *priv); +static int at32can_exitinitmode(struct at32_can_s *priv); +static int at32can_bittiming(struct at32_can_s *priv); +static int at32can_cellinit(struct at32_can_s *priv); +static int at32can_filterinit(struct at32_can_s *priv); + +/* TX mailbox status */ + +static bool at32can_txmb0empty(uint32_t tsr_regval); +static bool at32can_txmb1empty(uint32_t tsr_regval); +static bool at32can_txmb2empty(uint32_t tsr_regval); + +/* NuttX callback functions */ + +static int at32can_ifup(struct net_driver_s *dev); +static int at32can_ifdown(struct net_driver_s *dev); + +static void at32can_txavail_work(void *arg); +static int at32can_txavail(struct net_driver_s *dev); + +#ifdef CONFIG_NETDEV_IOCTL +static int at32can_netdev_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN1 + +static struct at32_can_s g_can1priv = +{ + .port = 1, + .canrx = + { + AT32_IRQ_CAN1RX0, + AT32_IRQ_CAN1RX1, + }, + .cantx = AT32_IRQ_CAN1TX, +#ifdef CONFIG_NET_CAN_ERRORS + .cansce = AT32_IRQ_CAN1SCE, +#endif + .filter = 0, + .base = AT32_CAN1_BASE, + .fbase = AT32_CAN1_BASE, + .baud = CONFIG_AT32_CAN1_BAUD, +}; + +#endif + +#ifdef CONFIG_AT32_CAN2 + +static struct at32_can_s g_can2priv = +{ + .port = 2, + .canrx = + { + AT32_IRQ_CAN2RX0, + AT32_IRQ_CAN2RX1, + }, + .cantx = AT32_IRQ_CAN2TX, +#ifdef CONFIG_NET_CAN_ERRORS + .cansce = AT32_IRQ_CAN2SCE, +#endif + .filter = CAN_NFILTERS / 2, + .base = AT32_CAN2_BASE, + .fbase = AT32_CAN1_BASE, + .baud = CONFIG_AT32_CAN2_BAUD, +}; + +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32can_getreg + * Name: at32can_getfreg + * + * Description: + * Read the value of a CAN register or filter block register. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_REGDEBUG +static uint32_t at32can_vgetreg(uint32_t addr) +{ + static uint32_t prevaddr = 0; + static uint32_t preval = 0; + static uint32_t count = 0; + + /* Read the value from the register */ + + uint32_t val = getreg32(addr); + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (addr == prevaddr && val == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + ninfo("...\n"); + } + + return val; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + ninfo("[repeats %" PRIu32 " more times]\n", count - 3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + preval = val; + count = 1; + } + + /* Show the register value read */ + + ninfo("%08" PRIx32 "->%08" PRIx32 "\n", addr, val); + return val; +} + +static uint32_t at32can_getreg(struct at32_can_s *priv, int offset) +{ + return at32can_vgetreg(priv->base + offset); +} + +static uint32_t at32can_getfreg(struct at32_can_s *priv, int offset) +{ + return at32can_vgetreg(priv->fbase + offset); +} + +#else +static uint32_t at32can_getreg(struct at32_can_s *priv, int offset) +{ + return getreg32(priv->base + offset); +} + +static uint32_t at32can_getfreg(struct at32_can_s *priv, int offset) +{ + return getreg32(priv->fbase + offset); +} + +#endif + +/**************************************************************************** + * Name: at32can_putreg + * Name: at32can_putfreg + * + * Description: + * Set the value of a CAN register or filter block register. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_REGDEBUG +static void at32can_vputreg(uint32_t addr, uint32_t value) +{ + /* Show the register value being written */ + + ninfo("%08" PRIx32 "->%08" PRIx32 "\n", addr, val); + + /* Write the value */ + + putreg32(value, addr); +} + +static void at32can_putreg(struct at32_can_s *priv, int offset, + uint32_t value) +{ + at32can_vputreg(priv->base + offset, value); +} + +static void at32can_putfreg(struct at32_can_s *priv, int offset, + uint32_t value) +{ + at32can_vputreg(priv->fbase + offset, value); +} + +#else +static void at32can_putreg(struct at32_can_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->base + offset); +} + +static void at32can_putfreg(struct at32_can_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->fbase + offset); +} +#endif + +/**************************************************************************** + * Name: at32can_dumpctrlregs + * + * Description: + * Dump the contents of all CAN control registers + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * msg - message + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_REGDEBUG +static void at32can_dumpctrlregs(struct at32_can_s *priv, + const char *msg) +{ + if (msg) + { + ninfo("Control Registers: %s\n", msg); + } + else + { + ninfo("Control Registers:\n"); + } + + /* CAN control and status registers */ + + caninfo(" MCTRL: %08" PRIx32 " MSTS: %08" PRIx32 " \ + TSTS: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_MCTRL_OFFSET), + getreg32(priv->base + AT32_CAN_MSTS_OFFSET), + getreg32(priv->base + AT32_CAN_TSTS_OFFSET)); + + caninfo(" RF0: %08" PRIx32 " RF1: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_RF0_OFFSET), + getreg32(priv->base + AT32_CAN_RF1_OFFSET)); + + caninfo(" INTEN: %08" PRIx32 " ESTS: %08" PRIx32 " \ + BTMG: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_INTEN_OFFSET), + getreg32(priv->base + AT32_CAN_ESTS_OFFSET), + getreg32(priv->base + AT32_CAN_BTMG_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: at32can_dumpmbregs + * + * Description: + * Dump the contents of all CAN mailbox registers + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * msg - message + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_REGDEBUG +static void at32can_dumpmbregs(struct at32_can_s *priv, + const char *msg) +{ + if (msg) + { + ninfo("Mailbox Registers: %s\n", msg); + } + else + { + ninfo("Mailbox Registers:\n"); + } + + /* CAN mailbox registers (3 TX and 2 RX) */ + + caninfo(" TMI0: %08" PRIx32 " TMC0: %08" PRIx32 " TMDTL0: %08" + PRIx32 " TMDTH0: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_TMI0_FFSET), + getreg32(priv->base + AT32_CAN_TMC0_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTL0_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTH0_OFFSET)); + + caninfo(" TMI1: %08" PRIx32 " TMC1: %08" PRIx32 " TMDTL1: %08" + PRIx32 " TMDTH1: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_TMI1_FFSET), + getreg32(priv->base + AT32_CAN_TMC1_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTL1_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTH1_OFFSET)); + + caninfo(" TMI2: %08" PRIx32 " TMC2: %08" PRIx32 " TMDTL2: %08" + PRIx32 " TMDTH2: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_TMI2_FFSET), + getreg32(priv->base + AT32_CAN_TMC2_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTL2_OFFSET), + getreg32(priv->base + AT32_CAN_TMDTH2_OFFSET)); + + caninfo(" RFI0: %08" PRIx32 " RFC0: %08" PRIx32 " RFDTL0: %08" + PRIx32 " RFDTH0: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_RFI0_OFFSET), + getreg32(priv->base + AT32_CAN_RFC0_OFFSET), + getreg32(priv->base + AT32_CAN_RFDTL0_OFFSET), + getreg32(priv->base + AT32_CAN_RFDTH0_OFFSET)); + + caninfo(" RFI1: %08" PRIx32 " RFC1: %08" PRIx32 " RFDTL1: %08" + PRIx32 " RFDTH1: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_RFI1_OFFSET), + getreg32(priv->base + AT32_CAN_RFC1_OFFSET), + getreg32(priv->base + AT32_CAN_RFDTL1_OFFSET), + getreg32(priv->base + AT32_CAN_RFDTH1_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: at32can_dumpfiltregs + * + * Description: + * Dump the contents of all CAN filter registers + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * msg - message + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_REGDEBUG +static void at32can_dumpfiltregs(struct at32_can_s *priv, + const char *msg) +{ + int i; + + if (msg) + { + ninfo("Filter Registers: %s\n", msg); + } + else + { + ninfo("Filter Registers:\n"); + } + + caninfo(" FCTRL: %08" PRIx32 " FMCFG: %08" PRIx32 " FSCFG: %08" + PRIx32 " FRF: %08" PRIx32 " FACFG: %08" PRIx32 "\n", + getreg32(priv->base + AT32_CAN_FCTRL_OFFSET), + getreg32(priv->base + AT32_CAN_FMCFG_OFFSET), + getreg32(priv->base + AT32_CAN_FSCFG_OFFSET), + getreg32(priv->base + AT32_CAN_FRF_OFFSET), + getreg32(priv->base + AT32_CAN_FACFG_OFFSET)); + + for (i = 0; i < CAN_NFILTERS; i++) + { + caninfo(" F%dR1: %08" PRIx32 " F%dR2: %08" PRIx32 "\n", + i, getreg32(priv->base + AT32_CAN_FBF_OFFSET(i, 1)), + i, getreg32(priv->base + AT32_CAN_FBF_OFFSET(i, 2))); + } +} +#endif + +/**************************************************************************** + * Name: at32can_rx0int + * + * Description: + * Call to enable or disable RX0 interrupts. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32can_rx0int(struct at32_can_s *priv, bool enable) +{ + uint32_t regval = 0; + + ninfo("CAN%" PRIu8 "RX0 enable: %d\n", priv->port, enable); + + /* Enable/disable the FIFO 0 message pending interrupt */ + + regval = at32can_getreg(priv, AT32_CAN_INTEN_OFFSET); + if (enable) + { + regval |= CAN_INTEN_RF0MIEN; + } + else + { + regval &= ~CAN_INTEN_RF0MIEN; + } + + at32can_putreg(priv, AT32_CAN_INTEN_OFFSET, regval); +} + +/**************************************************************************** + * Name: at32can_rx1int + * + * Description: + * Call to enable or disable RX1 interrupts. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32can_rx1int(struct at32_can_s *priv, bool enable) +{ + uint32_t regval = 0; + + ninfo("CAN%" PRIu8 "RX1 enable: %d\n", priv->port, enable); + + /* Enable/disable the FIFO 1 message pending interrupt */ + + regval = at32can_getreg(priv, AT32_CAN_INTEN_OFFSET); + if (enable) + { + regval |= CAN_INTEN_RF1MIEN; + } + else + { + regval &= ~CAN_INTEN_RF1MIEN; + } + + at32can_putreg(priv, AT32_CAN_INTEN_OFFSET, regval); +} + +/**************************************************************************** + * Name: at32can_txint + * + * Description: + * Call to enable or disable TX interrupts. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32can_txint(struct at32_can_s *priv, bool enable) +{ + uint32_t regval = 0; + + ninfo("CAN%" PRIu8 " txint enable: %d\n", priv->port, enable); + + /* Enable/disable the transmit mailbox interrupt */ + + regval = at32can_getreg(priv, AT32_CAN_INTEN_OFFSET); + if (enable) + { + regval |= CAN_INTEN_TCIEN; + } + else + { + regval &= ~CAN_INTEN_TCIEN; + } + + at32can_putreg(priv, AT32_CAN_INTEN_OFFSET, regval); +} + +#ifdef CONFIG_NET_CAN_ERRORS +/**************************************************************************** + * Name: at32can_txint + * + * Description: + * Call to enable or disable CAN SCE interrupts. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32can_errint(struct at32_can_s *priv, bool enable) +{ + uint32_t regval = 0; + + /* Enable/disable the transmit mailbox interrupt */ + + regval = at32can_getreg(priv, AT32_CAN_INTEN_OFFSET); + if (enable) + { + regval |= AT32_CAN_ERRINT; + } + else + { + regval &= ~AT32_CAN_ERRINT; + } + + at32can_putreg(priv, AT32_CAN_INTEN_OFFSET, regval); +} +#endif + +/**************************************************************************** + * Function: at32can_ifup + * + * Description: + * NuttX Callback: Bring up the Ethernet interface when an IP address is + * provided + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int at32can_ifup(struct net_driver_s *dev) +{ + struct at32_can_s *priv = (struct at32_can_s *)dev->d_private; + + /* Setup CAN */ + + at32can_setup(priv); + + /* Enable interrupts */ + + at32can_rx0int(priv, true); + at32can_rx1int(priv, true); + at32can_txint(priv, true); +#ifdef CONFIG_NET_CAN_ERRORS + at32can_errint(priv, true); +#endif + + /* Enable the interrupts at the NVIC */ + + up_enable_irq(priv->canrx[0]); + up_enable_irq(priv->canrx[1]); + up_enable_irq(priv->cantx); +#ifdef CONFIG_NET_CAN_ERRORS + up_enable_irq(priv->cansce); +#endif + + priv->bifup = true; + + priv->txdesc = (struct can_frame *)priv->tx_pool; + priv->rxdesc = (struct can_frame *)priv->rx_pool; + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + + return OK; +} + +/**************************************************************************** + * Function: at32can_ifdown + * + * Description: + * NuttX Callback: Stop the interface. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int at32can_ifdown(struct net_driver_s *dev) +{ + struct at32_can_s *priv = (struct at32_can_s *)dev->d_private; + + /* Disable CAN interrupts */ + + at32can_shutdown(priv); + + /* Reset CAN */ + + at32can_reset(priv); + + return OK; +} + +/**************************************************************************** + * Name: at32can_txready + * + * Description: + * Return true if the CAN hardware can accept another TX message. + * + ****************************************************************************/ + +static bool at32can_txready(struct at32_can_s *priv) +{ + uint32_t regval; + + /* Return true if any mailbox is available */ + + regval = at32can_getreg(priv, AT32_CAN_TSTS_OFFSET); + ninfo("CAN%" PRIu8 " TSR: %08" PRIx32 "\n", priv->port, regval); + + return (at32can_txmb0empty(regval) || at32can_txmb1empty(regval) || + at32can_txmb2empty(regval)); +} + +/**************************************************************************** + * Name: at32can_transmit + * + * Description: + * Start hardware transmission. Called either from the txdone interrupt + * handling or from watchdog based polling. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int at32can_transmit(struct at32_can_s *priv) +{ + struct can_frame *frame = (struct can_frame *)priv->dev.d_buf; + uint8_t *ptr; + uint32_t regval; + uint32_t tmp; + int dlc; + int txmb; + + ninfo("CAN%" PRIu8 " ID: %" PRIu32 " DLC: %" PRIu8 "\n", + priv->port, (uint32_t)frame->can_id, frame->can_dlc); + + /* Select one empty transmit mailbox */ + + regval = at32can_getreg(priv, AT32_CAN_TSTS_OFFSET); + if (at32can_txmb0empty(regval)) + { + txmb = 0; + } + else if (at32can_txmb1empty(regval)) + { + txmb = 1; + } + else if (at32can_txmb2empty(regval)) + { + txmb = 2; + } + else + { + canerr("ERROR: No available mailbox\n"); + return -EBUSY; + } + + /* Clear TXRQ, RTR, IDE, EXID, and STID fields */ + + regval = at32can_getreg(priv, AT32_CAN_TMI_OFFSET(txmb)); + regval &= ~(CAN_TMI_TMSR | CAN_TMI_TMFRSEL | CAN_TMI_TMIDSEL | + CAN_TMI_TMEID_MASK | CAN_TMI_TMSID_TMEID_MASK); + at32can_putreg(priv, AT32_CAN_TMI_OFFSET(txmb), regval); + + /* Set up the ID, standard 11-bit or extended 29-bit. */ + +#ifdef CONFIG_NET_CAN_EXTID + regval &= ~CAN_TIR_EXID_MASK; + if (frame->can_id & CAN_EFF_FLAG) + { + DEBUGASSERT(frame->can_id < (1 << 29)); + regval |= (frame->can_id << CAN_TMI_TMEID_SHIFT) | CAN_TMI_TMIDSEL; + } + else + { + DEBUGASSERT(frame->can_id < (1 << 11)); + regval |= frame->can_id << CAN_TMI_TMSID_TMEID_SHIFT; + } + +#else + regval |= (((uint32_t) frame->can_id << CAN_TMI_TMSID_TMEID_SHIFT) & + CAN_TMI_TMSID_TMEID_MASK); + +#endif + +#ifdef CONFIG_CAN_USE_RTR + regval |= ((frame->can_id & CAN_RTR_FLAG) ? CAN_TMI_TMFRSEL : 0); +#endif + + at32can_putreg(priv, AT32_CAN_TMI_OFFSET(txmb), regval); + + /* Set up the DLC */ + + dlc = frame->can_dlc; + regval = at32can_getreg(priv, AT32_CAN_TMC_OFFSET(txmb)); + regval &= ~(CAN_TMC_TMDTBL_MASK | CAN_TMC_TMTSTEN); + regval |= (uint32_t)dlc << CAN_TMC_TMDTBL_SHIFT; + at32can_putreg(priv, AT32_CAN_TMC_OFFSET(txmb), regval); + + /* Set up the data fields */ + + ptr = frame->data; + regval = 0; + + if (dlc > 0) + { + tmp = (uint32_t)*ptr++; + regval = tmp << CAN_TMDTL_TMDT0_SHIFT; + + if (dlc > 1) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTL_TMDT1_SHIFT; + + if (dlc > 2) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTL_TMDT2_SHIFT; + + if (dlc > 3) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTL_TMDT3_SHIFT; + } + } + } + } + + at32can_putreg(priv, AT32_CAN_TMDTL_OFFSET(txmb), regval); + + regval = 0; + if (dlc > 4) + { + tmp = (uint32_t)*ptr++; + regval = tmp << CAN_TMDTH_TMDT4_SHIFT; + + if (dlc > 5) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTH_TMDT5_SHIFT; + + if (dlc > 6) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTH_TMDT6_SHIFT; + + if (dlc > 7) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TMDTH_TMDT7_SHIFT; + } + } + } + } + + at32can_putreg(priv, AT32_CAN_TMDTH_OFFSET(txmb), regval); + + /* Enable the transmit mailbox empty interrupt (may already be enabled) */ + + regval = at32can_getreg(priv, AT32_CAN_INTEN_OFFSET); + regval |= CAN_INTEN_TCIEN; + at32can_putreg(priv, AT32_CAN_INTEN_OFFSET, regval); + + /* Request transmission */ + + regval = at32can_getreg(priv, AT32_CAN_TMI_OFFSET(txmb)); + regval |= CAN_TMI_TMSR; /* Transmit Mailbox Request */ + at32can_putreg(priv, AT32_CAN_TMI_OFFSET(txmb), regval); + + at32can_dumpmbregs(priv, "After send"); + return OK; +} + +/**************************************************************************** + * Function: at32can_txpoll + * + * Description: + * The transmitter is available, check if the network has any outgoing + * packets ready to send. This is a callback from devif_poll(). + * devif_poll() may be called: + * + * 1. When the preceding TX packet send is complete, + * 2. When the preceding TX packet send timesout and the interface is reset + * 3. During normal TX polling + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int at32can_txpoll(struct net_driver_s *dev) +{ + struct at32_can_s *priv = (struct at32_can_s *)dev->d_private; + + /* If the polling resulted in data that should be sent out on the network, + * the field d_len is set to a value > 0. + */ + + if (priv->dev.d_len > 0) + { + at32can_txdone(priv); + + /* Send the packet */ + + at32can_transmit(priv); + + /* Check if there is room in the device to hold another packet. If + * not, return a non-zero value to terminate the poll. + */ + + if (at32can_txready(priv) == false) + { + return -EBUSY; + } + } + + /* If zero is returned, the polling will continue until all connections + * have been examined. + */ + + return 0; +} + +/**************************************************************************** + * Function: at32can_txavail_work + * + * Description: + * Perform an out-of-cycle poll on the worker thread. + * + * Input Parameters: + * arg - Reference to the NuttX driver state structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * Called on the higher priority worker thread. + * + ****************************************************************************/ + +static void at32can_txavail_work(void *arg) +{ + struct at32_can_s *priv = (struct at32_can_s *)arg; + + /* Ignore the notification if the interface is not yet up */ + + net_lock(); + if (priv->bifup) + { + /* Check if there is room in the hardware to hold another outgoing + * packet. + */ + + if (at32can_txready(priv)) + { + /* No, there is space for another transfer. Poll the network for + * new XMIT data. + */ + + devif_poll(&priv->dev, at32can_txpoll); + } + } + + net_unlock(); +} + +/**************************************************************************** + * Function: at32can_txavail + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called in normal user mode + * + ****************************************************************************/ + +static int at32can_txavail(struct net_driver_s *dev) +{ + struct at32_can_s *priv = (struct at32_can_s *)dev->d_private; + + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&priv->pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + at32can_txavail_work(priv); + } + + return OK; +} + +/**************************************************************************** + * Function: at32can_ioctl + * + * Description: + * PHY ioctl command handler + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * cmd - ioctl command + * arg - Argument accompanying the command + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int at32can_netdev_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg) +{ +#if 0 + struct at32_can_s *priv = (struct at32_can_s *)dev->d_private; +#endif + int ret = OK; + + switch (cmd) + { + /* TODO */ + + default: + ret = -ENOTTY; + break; + } + + return ret; +} +#endif /* CONFIG_NETDEV_IOCTL */ + +/**************************************************************************** + * Name: at32can_rxinterrupt_work + * + * Description: + * CAN RX FIFO 0/1 interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * rxmb - The RX mailbox number. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_rxinterrupt_work(struct at32_can_s *priv, int rxmb) +{ + struct can_frame *frame = (struct can_frame *)priv->rxdesc; + uint32_t regval; + int ret = OK; + + DEBUGASSERT(priv != NULL); + + if (rxmb == 0) + { + at32can_dumpmbregs(priv, "RX0 interrupt"); + } + else + { + at32can_dumpmbregs(priv, "RX1 interrupt"); + } + + /* Get the CAN identifier. */ + + regval = at32can_getreg(priv, AT32_CAN_RFI_OFFSET(rxmb)); + +#ifdef CONFIG_NET_CAN_EXTID + if ((regval & CAN_RDI_RFIDI) != 0) + { + frame->can_id = (regval & CAN_RDI_RFEID_MASK) >> CAN_RDI_RFEID_SHIFT; + frame->can_id |= CAN_EFF_FLAG; + } + else + { + frame->can_id = \ + (regval & CAN_RDI_RFSID_RFEID_MASK) >> CAN_RDI_RFSID_RFEID_SHIFT; + } +#else + if ((regval & CAN_RDI_RFIDI) != 0) + { + nerr("ERROR: Received message with extended identifier. Dropped\n"); + ret = -ENOSYS; + goto errout; + } + + frame->can_id = \ + (regval & CAN_RDI_RFSID_RFEID_MASK) >> CAN_RDI_RFSID_RFEID_SHIFT; +#endif + + /* Extract the RTR bit */ + + if ((regval & CAN_RDI_RFFRI) != 0) + { + frame->can_id |= CAN_RTR_FLAG; + } + + /* Get the DLC */ + + regval = at32can_getreg(priv, AT32_CAN_RFC_OFFSET(rxmb)); + frame->can_dlc = (regval & CAN_RFC_RFDTL_MASK) >> CAN_RFC_RFDTL_SHIFT; + + /* Save the message data */ + + regval = at32can_getreg(priv, AT32_CAN_RFDTL_OFFSET(rxmb)); + frame->data[0] = (regval & CAN_RFDTL_RFDT0_MASK) >> CAN_RFDTL_RFDT0_SHIFT; + frame->data[1] = (regval & CAN_RFDTL_RFDT1_MASK) >> CAN_RFDTL_RFDT1_SHIFT; + frame->data[2] = (regval & CAN_RFDTL_RFDT2_MASK) >> CAN_RFDTL_RFDT2_SHIFT; + frame->data[3] = (regval & CAN_RFDTL_RFDT3_MASK) >> CAN_RFDTL_RFDT3_SHIFT; + + regval = at32can_getreg(priv, AT32_CAN_RFDTH_OFFSET(rxmb)); + frame->data[4] = (regval & CAN_RFDTH_RFDT4_MASK) >> CAN_RFDTH_RFDT4_SHIFT; + frame->data[5] = (regval & CAN_RFDTH_RFDT5_MASK) >> CAN_RFDTH_RFDT5_SHIFT; + frame->data[6] = (regval & CAN_RFDTH_RFDT6_MASK) >> CAN_RFDTH_RFDT6_SHIFT; + frame->data[7] = (regval & CAN_RFDTH_RFDT7_MASK) >> CAN_RFDTH_RFDT7_SHIFT; + + /* Copy the buffer pointer to priv->dev.. Set amount of data + * in priv->dev.d_len + */ + + priv->dev.d_len = sizeof(struct can_frame); + priv->dev.d_buf = (uint8_t *)frame; + + /* Send to socket interface */ + + NETDEV_RXPACKETS(&priv->dev); + + can_input(&priv->dev); + + /* Point the packet buffer back to the next Tx buffer that will be + * used during the next write. If the write queue is full, then + * this will point at an active buffer, which must not be written + * to. This is OK because devif_poll won't be called unless the + * queue is not full. + */ + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + + /* Release the FIFO */ + +#ifndef CONFIG_NET_CAN_EXTID +errout: +#endif + regval = at32can_getreg(priv, AT32_CAN_RF_OFFSET(rxmb)); + regval |= CAN_RF_RFR; + at32can_putreg(priv, AT32_CAN_RF_OFFSET(rxmb), regval); + + /* Re-enable CAN RX interrupts */ + + if (rxmb == 0) + { + at32can_rx0int(priv, true); + } + else if (rxmb == 1) + { + at32can_rx1int(priv, true); + } + else + { + DEBUGPANIC(); + } + + return ret; +} + +/**************************************************************************** + * Name: at32can_rx0interrupt_work + ****************************************************************************/ + +static void at32can_rx0interrupt_work(void *arg) +{ + struct at32_can_s *priv = (struct at32_can_s *)arg; + at32can_rxinterrupt_work(priv, 0); +} + +/**************************************************************************** + * Name: at32can_rx1interrupt_work + ****************************************************************************/ + +static void at32can_rx1interrupt_work(void *arg) +{ + struct at32_can_s *priv = (struct at32_can_s *)arg; + at32can_rxinterrupt_work(priv, 1); +} + +/**************************************************************************** + * Name: at32can_rxinterrupt + * + * Description: + * CAN RX FIFO common interrupt handler + * + ****************************************************************************/ + +static int at32can_rxinterrupt(struct at32_can_s *priv, int rxmb) +{ + uint32_t regval = 0; + int npending = 0; + + /* Verify that a message is pending in the FIFO */ + + regval = at32can_getreg(priv, AT32_CAN_RF_OFFSET(rxmb)); + npending = (regval & CAN_RF_RFMN_MASK) >> CAN_RF_RFMN_SHIFT; + if (npending < 1) + { + nwarn("WARNING: No messages pending\n"); + return OK; + } + + /* Disable further CAN RX interrupts and schedule to perform the + * interrupt processing on the worker thread + */ + + if (rxmb == 0) + { + at32can_rx0int(priv, false); + work_queue(CANWORK, &priv->irqwork, + at32can_rx0interrupt_work, priv, 0); + } + else if (rxmb == 1) + { + at32can_rx1int(priv, false); + work_queue(CANWORK, &priv->irqwork, + at32can_rx1interrupt_work, priv, 0); + } + else + { + DEBUGPANIC(); + } + + return OK; +} + +/**************************************************************************** + * Name: at32can_rx0interrupt + * + * Description: + * CAN RX FIFO 0 interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_rx0interrupt(int irq, void *context, void *arg) +{ + struct at32_can_s *priv = (struct at32_can_s *)arg; + return at32can_rxinterrupt(priv, 0); +} + +/**************************************************************************** + * Name: at32can_rx1interrupt + * + * Description: + * CAN RX FIFO 1 interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_rx1interrupt(int irq, void *context, void *arg) +{ + struct at32_can_s *priv = (struct at32_can_s *)arg; + return at32can_rxinterrupt(priv, 1); +} + +/**************************************************************************** + * Name: at32can_txinterrupt + * + * Description: + * CAN TX mailbox complete interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_txinterrupt(int irq, void *context, void *arg) +{ + struct at32_can_s *priv = (struct at32_can_s *)arg; + uint32_t regval; + + DEBUGASSERT(priv != NULL); + + /* Get the transmit status */ + + regval = at32can_getreg(priv, AT32_CAN_TSTS_OFFSET); + + /* Check for RQCP0: Request completed mailbox 0 */ + + if ((regval & CAN_TSTS_TM0TCF) != 0) + { + /* Writing '1' to RCP0 clears RCP0 and all the status bits (TXOK0, + * ALST0 and TERR0) for Mailbox 0. + */ + + at32can_putreg(priv, AT32_CAN_TSTS_OFFSET, CAN_TSTS_TM0TCF); + + /* Tell the upper half that the transfer is finished. */ + + /* Disable further TX CAN interrupts. here can be no race + * condition here. + */ + + at32can_txint(priv, false); + work_queue(CANWORK, &priv->irqwork, at32can_txdone_work, priv, 0); + } + + /* Check for RQCP1: Request completed mailbox 1 */ + + if ((regval & CAN_TSTS_TM1TCF) != 0) + { + /* Writing '1' to RCP1 clears RCP1 and all the status bits (TXOK1, + * ALST1 and TERR1) for Mailbox 1. + */ + + at32can_putreg(priv, AT32_CAN_TSTS_OFFSET, CAN_TSTS_TM1TCF); + + /* Tell the upper half that the transfer is finished. */ + + /* Disable further TX CAN interrupts. here can be no race + * condition here. + */ + + at32can_txint(priv, false); + work_queue(CANWORK, &priv->irqwork, at32can_txdone_work, priv, 0); + } + + /* Check for RQCP2: Request completed mailbox 2 */ + + if ((regval & CAN_TSTS_TM2TCF) != 0) + { + /* Writing '1' to RCP2 clears RCP2 and all the status bits (TXOK2, + * ALST2 and TERR2) for Mailbox 2. + */ + + at32can_putreg(priv, AT32_CAN_TSTS_OFFSET, CAN_TSTS_TM2TCF); + + /* Disable further TX CAN interrupts. here can be no race + * condition here. + */ + + at32can_txint(priv, false); + work_queue(CANWORK, &priv->irqwork, at32can_txdone_work, priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: at32can_txdone_work + ****************************************************************************/ + +static void at32can_txdone_work(void *arg) +{ + struct at32_can_s *priv = (struct at32_can_s *)arg; + + at32can_txdone(priv); + + /* There should be space for a new TX in any event. Poll the network for + * new XMIT data + */ + + net_lock(); + devif_poll(&priv->dev, at32can_txpoll); + net_unlock(); +} + +/**************************************************************************** + * Name: at32can_txdone + ****************************************************************************/ + +static void at32can_txdone(struct at32_can_s *priv) +{ + at32can_txint(priv, true); + + NETDEV_TXDONE(&priv->dev); +} + +#ifdef CONFIG_NET_CAN_ERRORS + +/**************************************************************************** + * Name: at32can_sceinterrupt_work + * + * Description: + * CAN status change interrupt work + * + * Input Parameters: + * arg - reference to the driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32can_sceinterrupt_work(void *arg) +{ + struct at32_can_s *priv = (struct at32_can_s *)arg; + struct can_frame *frame = (struct can_frame *)priv->rxdesc; + uint32_t regval = 0; + uint16_t errbits = 0; + uint8_t data[CAN_ERR_DLC]; + + DEBUGASSERT(priv != NULL); + + /* Check Error Interrupt flag */ + + regval = at32can_getreg(priv, AT32_CAN_MSTS_OFFSET); + if (regval & CAN_MSTS_EOIF) + { + /* Encode error bits */ + + errbits = 0; + memset(data, 0, sizeof(data)); + + /* Get Error statur register */ + + regval = at32can_getreg(priv, AT32_CAN_ESTS_OFFSET); + + if (regval & CAN_ESTS_EAF) + { + /* Error warning flag */ + + data[1] |= (CAN_ERR_CRTL_RX_WARNING | CAN_ERR_CRTL_TX_WARNING); + errbits |= CAN_ERR_CRTL; + } + + if (regval & CAN_ESTS_EPF) + { + /* Error passive flag */ + + data[1] |= (CAN_ERR_CRTL_RX_PASSIVE | CAN_ERR_CRTL_TX_PASSIVE); + errbits |= CAN_ERR_CRTL; + } + + if (regval & CAN_ESTS_BOF) + { + /* Bus-off flag */ + + errbits |= CAN_ERR_BUSOFF; + } + + /* Last error code */ + + if (regval & CAN_ESTS_ETR_MASK) + { + if (regval & CAN_ESTS_ETR_STUFF) + { + /* Stuff Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_STUFF; + } + else if (regval & CAN_ESTS_ETR_FORM) + { + /* Format Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_FORM; + } + else if (regval & CAN_ESTS_ETR_ACK) + { + /* Acknowledge Error */ + + errbits |= CAN_ERR_ACK; + } + else if (regval & CAN_ESTS_ETR_BREC) + { + /* Bit recessive Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_BIT1; + } + else if (regval & CAN_ESTS_ETR_BDOM) + { + /* Bit dominant Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_BIT0; + } + else if (regval & CAN_ESTS_ETR_CRC) + { + /* Receive CRC Error */ + + errbits |= CAN_ERR_PROT; + data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; + } + } + + /* Get transmit status register */ + + regval = at32can_getreg(priv, AT32_CAN_TSTS_OFFSET); + + if (regval & CAN_TSTS_TM0ALF || regval & CAN_TSTS_TM1ALF || + regval & CAN_TSTS_TM2ALF) + { + /* Lost arbitration Error */ + + errbits |= CAN_ERR_LOSTARB; + } + + /* Clear TSR register */ + + at32can_putreg(priv, AT32_CAN_TSTS_OFFSET, regval); + + /* Clear ERRI flag */ + + at32can_putreg(priv, AT32_CAN_MSTS_OFFSET, CAN_MSTS_EOIF); + } + + /* Report a CAN error */ + + if (errbits != 0) + { + canerr("ERROR: errbits = %08" PRIx16 "\n", errbits); + + /* Copy frame */ + + frame->can_id = errbits; + frame->can_dlc = CAN_ERR_DLC; + + memcpy(frame->data, data, CAN_ERR_DLC); + + net_lock(); + + /* Copy the buffer pointer to priv->dev.. Set amount of data + * in priv->dev.d_len + */ + + priv->dev.d_len = sizeof(struct can_frame); + priv->dev.d_buf = (uint8_t *)frame; + + /* Send to socket interface */ + + NETDEV_ERRORS(&priv->dev); + + can_input(&priv->dev); + + /* Point the packet buffer back to the next Tx buffer that will be + * used during the next write. If the write queue is full, then + * this will point at an active buffer, which must not be written + * to. This is OK because devif_poll won't be called unless the + * queue is not full. + */ + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + net_unlock(); + } + + /* Re-enable CAN SCE interrupts */ + + at32can_errint(priv, true); +} + +/**************************************************************************** + * Name: at32can_sceinterrupt + * + * Description: + * CAN status change interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_sceinterrupt(int irq, void *context, void *arg) +{ + struct at32_can_s *priv = (struct at32_can_s *)arg; + + /* Disable further CAN SCE interrupts and schedule to perform the + * interrupt processing on the worker thread + */ + + at32can_errint(priv, false); + work_queue(CANWORK, &priv->irqwork, + at32can_sceinterrupt_work, priv, 0); + + return OK; +} +#endif + +/**************************************************************************** + * Name: at32can_bittiming + * + * Description: + * Set the CAN bit timing register (BTR) based on the configured BAUD. + * + * "The bit timing logic monitors the serial bus-line and performs sampling + * and adjustment of the sample point by synchronizing on the start-bit edge + * and resynchronizing on the following edges. + * + * "Its operation may be explained simply by splitting nominal bit time into + * three segments as follows: + * + * 1. "Synchronization segment (SYNC_SEG): a bit change is expected to occur + * within this time segment. It has a fixed length of one time quantum + * (1 x tCAN). + * 2. "Bit segment 1 (BS1): defines the location of the sample point. It + * includes the PROP_SEG and PHASE_SEG1 of the CAN standard. Its duration + * is programmable between 1 and 16 time quanta but may be automatically + * lengthened to compensate for positive phase drifts due to differences + * in the frequency of the various nodes of the network. + * 3. "Bit segment 2 (BS2): defines the location of the transmit point. It + * represents the PHASE_SEG2 of the CAN standard. Its duration is + * programmable between 1 and 8 time quanta but may also be automatically + * shortened to compensate for negative phase drifts." + * + * Pictorially: + * + * |<----------------- NOMINAL BIT TIME ----------------->| + * |<- SYNC_SEG ->|<------ BS1 ------>|<------ BS2 ------>| + * |<---- Tq ---->|<----- Tbs1 ------>|<----- Tbs2 ------>| + * + * Where + * Tbs1 is the duration of the BS1 segment + * Tbs2 is the duration of the BS2 segment + * Tq is the "Time Quantum" + * + * Relationships: + * + * baud = 1 / bit_time + * bit_time = Tq + Tbs1 + Tbs2 + * Tbs1 = Tq * ts1 + * Tbs2 = Tq * ts2 + * Tq = brp * Tpclk1 + * baud = Fpclk1 / (brp * (1 + ts1 + ts2)) + * + * Where: + * Tpclk1 is the period of the APB1 clock (PCLK1). + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32can_bittiming(struct at32_can_s *priv) +{ + uint32_t tmp; + uint32_t brp; + uint32_t ts1; + uint32_t ts2; + + ninfo("CAN%" PRIu8 " PCLK1: %lu baud: %" PRIu32 "\n", + priv->port, (unsigned long) AT32_PCLK1_FREQUENCY, priv->baud); + + /* Try to get CAN_BIT_QUANTA quanta in one bit_time. + * + * bit_time = Tq*(ts1 + ts2 + 1) + * nquanta = bit_time / Tq + * nquanta = (ts1 + ts2 + 1) + * + * bit_time = brp * Tpclk1 * (ts1 + ts2 + 1) + * nquanta = bit_time / brp / Tpclk1 + * = PCLK1 / baud / brp + * brp = PCLK1 / baud / nquanta; + * + * Example: + * PCLK1 = 144,000,000 baud = 500,000 nquanta = 13 : brp = 2 + */ + + tmp = AT32_PCLK1_FREQUENCY / priv->baud; + if (tmp < CAN_BIT_QUANTA) + { + /* At the smallest brp value (1), there are already too few bit times + * (PCLCK1 / baud) to meet our goal. brp must be one and we need + * make some reasonable guesses about ts1 and ts2. + */ + + brp = 1; + + /* In this case, we have to guess a good value for ts1 and ts2 */ + + ts1 = (tmp - 1) >> 1; + ts2 = tmp - ts1 - 1; + if (ts1 == ts2 && ts1 > 1 && ts2 < CAN_BTR_TSEG2_MAX) + { + ts1--; + ts2++; + } + } + + /* Otherwise, nquanta is CAN_BIT_QUANTA, ts1 is CONFIG_AT32_CAN_TSEG1, + * ts2 is CONFIG_AT32_CAN_TSEG2 and we calculate brp to achieve + * CAN_BIT_QUANTA quanta in the bit time + */ + + else + { + ts1 = CONFIG_AT32_CAN_TSEG1; + ts2 = CONFIG_AT32_CAN_TSEG2; + brp = (tmp + (CAN_BIT_QUANTA / 2)) / CAN_BIT_QUANTA; + DEBUGASSERT(brp >= 1 && brp <= CAN_BTR_BRP_MAX); + } + + ninfo("TS1: %" PRIu32 " TS2: %" PRIu32 " BRP: %" PRIu32 "\n", + ts1, ts2, brp); + + /* Configure bit timing. This also does the following, less obvious + * things. Unless loopback mode is enabled, it: + * + * - Disables silent mode. + * - Disables loopback mode. + * + * NOTE that for the time being, SJW is set to 1 just because I don't + * know any better. + */ + + tmp = ((brp - 1) << CAN_BTMG_BRDIV_SHIFT) | \ + ((ts1 - 1) << CAN_BTMG_BTS1_SHIFT) | \ + ((ts2 - 1) << CAN_BTMG_BTS2_SHIFT) | \ + ((1 - 1) << CAN_BTMG_RSAW_SHIFT); + +#ifdef CONFIG_CAN_LOOPBACK + /* tmp |= (CAN_BTMG_LBEN | CAN_BTMG_LOEN); */ + + tmp |= CAN_BTMG_LBEN; +#endif + + at32can_putreg(priv, AT32_CAN_BTMG_OFFSET, tmp); + return OK; +} + +/**************************************************************************** + * Name: at32can_setup + ****************************************************************************/ + +static int at32can_setup(struct at32_can_s *priv) +{ + int ret; + +#ifdef CONFIG_NET_CAN_ERRORS + ninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8 + " TX irq: %" PRIu8 " SCE irq: %" PRIu8 "\n", + priv->port, priv->canrx[0], priv->canrx[1], priv->cantx, + priv->cansce); +#else + ninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8 + " TX irq: %" PRIu8 "\n", + priv->port, priv->canrx[0], priv->canrx[1], priv->cantx); +#endif + + /* CAN cell initialization */ + + ret = at32can_cellinit(priv); + if (ret < 0) + { + nerr("ERROR: CAN%" PRId8 " cell initialization failed: %d\n", + priv->port, ret); + return ret; + } + + at32can_dumpctrlregs(priv, "After cell initialization"); + at32can_dumpmbregs(priv, NULL); + + /* CAN filter initialization */ + + ret = at32can_filterinit(priv); + if (ret < 0) + { + nerr("ERROR: CAN%" PRIu8 " filter initialization failed: %d\n", + priv->port, ret); + return ret; + } + + at32can_dumpfiltregs(priv, "After filter initialization"); + + /* Attach the CAN RX FIFO 0/1 interrupts and TX interrupts. + * The others are not used. + */ + + ret = irq_attach(priv->canrx[0], at32can_rx0interrupt, priv); + if (ret < 0) + { + nerr("ERROR: Failed to attach CAN%" PRIu8 " RX0 IRQ (%" PRIu8 ")", + priv->port, priv->canrx[0]); + return ret; + } + + ret = irq_attach(priv->canrx[1], at32can_rx1interrupt, priv); + if (ret < 0) + { + nerr("ERROR: Failed to attach CAN%" PRIu8 " RX1 IRQ (%" PRIu8 ")", + priv->port, priv->canrx[1]); + return ret; + } + + ret = irq_attach(priv->cantx, at32can_txinterrupt, priv); + if (ret < 0) + { + nerr("ERROR: Failed to attach CAN%" PRIu8 " TX IRQ (%" PRIu8 ")", + priv->port, priv->cantx); + return ret; + } + +#ifdef CONFIG_NET_CAN_ERRORS + ret = irq_attach(priv->cansce, at32can_sceinterrupt, priv); + if (ret < 0) + { + nerr("ERROR: Failed to attach CAN%" PRIu8 " SCE IRQ (%" PRIu8 ")", + priv->port, priv->cansce); + return ret; + } +#endif + + return OK; +} + +/**************************************************************************** + * Name: at32can_shutdown + ****************************************************************************/ + +static void at32can_shutdown(struct at32_can_s *priv) +{ + ninfo("CAN%" PRIu8 "\n", priv->port); + + /* Disable the RX FIFO 0/1 and TX interrupts */ + + up_disable_irq(priv->canrx[0]); + up_disable_irq(priv->canrx[1]); + up_disable_irq(priv->cantx); +#ifdef CONFIG_NET_CAN_ERRORS + up_disable_irq(priv->cansce); +#endif + + /* Detach the RX FIFO 0/1 and TX interrupts */ + + irq_detach(priv->canrx[0]); + irq_detach(priv->canrx[1]); + irq_detach(priv->cantx); +#ifdef CONFIG_NET_CAN_ERRORS + irq_detach(priv->cansce); +#endif +} + +/**************************************************************************** + * Name: at32can_reset + * + * Description: + * Put the CAN device in the non-operational, reset state + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void at32can_reset(struct at32_can_s *priv) +{ + uint32_t regval; + uint32_t regbit = 0; + irqstate_t flags; + + ninfo("CAN%" PRIu8 "\n", priv->port); + + /* Get the bits in the AHB1RSTR register needed to reset this CAN device */ + +#ifdef CONFIG_AT32_CAN1 + if (priv->port == 1) + { + regbit = CRM_APB1RST_CAN1RST; + } + else +#endif +#ifdef CONFIG_AT32_CAN2 + if (priv->port == 2) + { + regbit = CRM_APB1RST_CAN2RST; + } + else +#endif + { + nerr("ERROR: Unsupported port %d\n", priv->port); + return; + } + + /* Disable interrupts momentarily to stop any ongoing CAN event processing + * and to prevent any concurrent access to the AHB1RSTR register. + */ + + flags = enter_critical_section(); + + /* Reset the CAN */ + + regval = getreg32(AT32_CRM_APB1RST); + regval |= regbit; + putreg32(regval, AT32_CRM_APB1RST); + + regval &= ~regbit; + putreg32(regval, AT32_CRM_APB1RST); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: at32can_enterinitmode + * + * Description: + * Put the CAN cell in Initialization mode. This only disconnects the CAN + * peripheral, no registers are changed. The initialization mode is + * required to change the baud rate. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32can_enterinitmode(struct at32_can_s *priv) +{ + uint32_t regval; + volatile uint32_t timeout; + + ninfo("CAN%" PRIu8 "\n", priv->port); + + /* Enter initialization mode */ + + regval = at32can_getreg(priv, AT32_CAN_MCTRL_OFFSET); + regval |= CAN_MCTRL_FZEN; + at32can_putreg(priv, AT32_CAN_MCTRL_OFFSET, regval); + + /* Wait until initialization mode is acknowledged */ + + for (timeout = INAK_TIMEOUT; timeout > 0; timeout--) + { + regval = at32can_getreg(priv, AT32_CAN_MSTS_OFFSET); + if ((regval & CAN_MSTS_FZC) != 0) + { + /* We are in initialization mode */ + + break; + } + } + + /* Check for a timeout */ + + if (timeout < 1) + { + nerr("ERROR: Timed out waiting to enter initialization mode\n"); + return -ETIMEDOUT; + } + + return OK; +} + +/**************************************************************************** + * Name: at32can_exitinitmode + * + * Description: + * Put the CAN cell out of the Initialization mode (to Normal mode) + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32can_exitinitmode(struct at32_can_s *priv) +{ + uint32_t regval; + volatile uint32_t timeout; + + /* Exit Initialization mode, enter Normal mode */ + + regval = at32can_getreg(priv, AT32_CAN_MCTRL_OFFSET); + regval &= ~CAN_MCTRL_FZEN; + at32can_putreg(priv, AT32_CAN_MCTRL_OFFSET, regval); + + /* Wait until the initialization mode exit is acknowledged */ + + for (timeout = INAK_TIMEOUT; timeout > 0; timeout--) + { + regval = at32can_getreg(priv, AT32_CAN_MSTS_OFFSET); + if ((regval & CAN_MSTS_FZC) == 0) + { + /* We are out of initialization mode */ + + break; + } + } + + /* Check for a timeout */ + + if (timeout < 1) + { + nerr("ERROR: Timed out waiting to exit initialization mode: %08" + PRIx32 "\n", regval); + return -ETIMEDOUT; + } + + return OK; +} + +/**************************************************************************** + * Name: at32can_cellinit + * + * Description: + * CAN cell initialization + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32can_cellinit(struct at32_can_s *priv) +{ + uint32_t regval; + int ret; + + ninfo("CAN%" PRIu8 "\n", priv->port); + + /* Exit from sleep mode */ + + regval = at32can_getreg(priv, AT32_CAN_MCTRL_OFFSET); + regval &= ~CAN_MCTRL_DZEN; + at32can_putreg(priv, AT32_CAN_MCTRL_OFFSET, regval); + + ret = at32can_enterinitmode(priv); + if (ret != 0) + { + return ret; + } + + /* Disable the following modes: + * + * - Time triggered communication mode + * - Automatic bus-off management + * - Automatic wake-up mode + * - No automatic retransmission + * - Receive FIFO locked mode + * + * Enable: + * + * - Transmit FIFO priority + */ + + regval = at32can_getreg(priv, AT32_CAN_MCTRL_OFFSET); + regval &= ~(CAN_MCTRL_MDRSEL | CAN_MCTRL_PRSFEN | CAN_MCTRL_AEDEN | + CAN_MCTRL_AEBOEN | CAN_MCTRL_TTCEN); + regval |= CAN_MCTRL_MMSSR; + at32can_putreg(priv, AT32_CAN_MCTRL_OFFSET, regval); + + /* Configure bit timing. */ + + ret = at32can_bittiming(priv); + if (ret < 0) + { + nerr("ERROR: Failed to set bit timing: %d\n", ret); + return ret; + } + + return at32can_exitinitmode(priv); +} + +/**************************************************************************** + * Name: at32can_filterinit + * + * Description: + * CAN filter initialization. CAN filters are not currently used by this + * driver. The CAN filters can be configured in a different way: + * + * 1. As a match of specific IDs in a list (IdList mode), or as + * 2. And ID and a mask (IdMask mode). + * + * Filters can also be configured as: + * + * 3. 16- or 32-bit. The advantage of 16-bit filters is that you get + * more filters; The advantage of 32-bit filters is that you get + * finer control of the filtering. + * + * One filter is set up for each CAN. The filter resources are shared + * between the two CAN modules: CAN1 uses only filter 0 (but reserves + * 0 through CAN_NFILTERS/2-1); CAN2 uses only filter CAN_NFILTERS/2 + * (but reserves CAN_NFILTERS/2 through CAN_NFILTERS-1). + * + * 32-bit IdMask mode is configured. However, both the ID and the MASK + * are set to zero thus suppressing all filtering because anything masked + * with zero matches zero. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32can_filterinit(struct at32_can_s *priv) +{ + uint32_t regval; + uint32_t bitmask; + + ninfo("CAN%" PRIu8 " filter: %" PRIu8 "\n", priv->port, priv->filter); + + /* Get the bitmask associated with the filter used by this CAN block */ + + bitmask = (uint32_t)1 << priv->filter; + + /* Enter filter initialization mode */ + + regval = at32can_getfreg(priv, AT32_CAN_FCTRL_OFFSET); + regval |= CAN_FCTRL_FCS; + at32can_putfreg(priv, AT32_CAN_FCTRL_OFFSET, regval); + + /* Disable the filter */ + + regval = at32can_getfreg(priv, AT32_CAN_FACFG_OFFSET); + regval &= ~bitmask; + at32can_putfreg(priv, AT32_CAN_FACFG_OFFSET, regval); + + /* Select the 32-bit scale for the filter */ + + regval = at32can_getfreg(priv, AT32_CAN_FSCFG_OFFSET); + regval |= bitmask; + at32can_putfreg(priv, AT32_CAN_FSCFG_OFFSET, regval); + + /* There are 14 or 28 filter banks (depending) on the device. + * Each filter bank is composed of two 32-bit registers, CAN_FiR: + */ + + at32can_putfreg(priv, AT32_CAN_FBF_OFFSET(priv->filter, 1), 0); + at32can_putfreg(priv, AT32_CAN_FBF_OFFSET(priv->filter, 2), 0); + + /* Set Id/Mask mode for the filter */ + + regval = at32can_getfreg(priv, AT32_CAN_FMCFG_OFFSET); + regval &= ~bitmask; + at32can_putfreg(priv, AT32_CAN_FMCFG_OFFSET, regval); + + /* Assign FIFO 0 for the filter */ + + regval = at32can_getfreg(priv, AT32_CAN_FRF_OFFSET); + regval &= ~bitmask; + at32can_putfreg(priv, AT32_CAN_FRF_OFFSET, regval); + + /* Enable the filter */ + + regval = at32can_getfreg(priv, AT32_CAN_FACFG_OFFSET); + regval |= bitmask; + at32can_putfreg(priv, AT32_CAN_FACFG_OFFSET, regval); + + /* Exit filter initialization mode */ + + regval = at32can_getfreg(priv, AT32_CAN_FCTRL_OFFSET); + regval &= ~CAN_FCTRL_FCS; + at32can_putfreg(priv, AT32_CAN_FCTRL_OFFSET, regval); + return OK; +} + +/**************************************************************************** + * Name: at32can_txmb0empty + * + * Input Parameters: + * tsr_regval - value of CAN transmit status register + * + * Returned Value: + * Returns true if mailbox 0 is empty and can be used for sending. + * + ****************************************************************************/ + +static bool at32can_txmb0empty(uint32_t tsr_regval) +{ + return (tsr_regval & CAN_TSTS_TM0EF) != 0 && + (tsr_regval & CAN_TSTS_TM0TCF) == 0; +} + +/**************************************************************************** + * Name: at32can_txmb1empty + * + * Input Parameters: + * tsr_regval - value of CAN transmit status register + * + * Returned Value: + * Returns true if mailbox 1 is empty and can be used for sending. + * + ****************************************************************************/ + +static bool at32can_txmb1empty(uint32_t tsr_regval) +{ + return (tsr_regval & CAN_TSTS_TM1EF) != 0 && + (tsr_regval & CAN_TSTS_TM1TCF) == 0; +} + +/**************************************************************************** + * Name: at32can_txmb2empty + * + * Input Parameters: + * tsr_regval - value of CAN transmit status register + * + * Returned Value: + * Returns true if mailbox 2 is empty and can be used for sending. + * + ****************************************************************************/ + +static bool at32can_txmb2empty(uint32_t tsr_regval) +{ + return (tsr_regval & CAN_TSTS_TM2EF) != 0 && + (tsr_regval & CAN_TSTS_TM2TCF) == 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_cansockinitialize + * + * Description: + * Initialize the selected CAN port as CAN socket interface + * + * Input Parameters: + * Port number (for hardware that has multiple CAN interfaces) + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int at32_cansockinitialize(int port) +{ + struct at32_can_s *priv = NULL; + int ret = OK; + + ninfo("CAN%" PRIu8 "\n", port); + + /* NOTE: Peripherical clocking for CAN1 and/or CAN2 was already provided + * by at32_clockconfig() early in the reset sequence. + */ + +#ifdef CONFIG_AT32_CAN1 + if (port == 1) + { + /* Select the CAN1 device structure */ + + priv = &g_can1priv; + + /* Configure CAN1 pins. The ambiguous settings in the at32*_pinmap.h + * file must have been disambiguated in the board.h file. + */ + + at32_configgpio(GPIO_CAN1_RX); + at32_configgpio(GPIO_CAN1_TX); + } + else +#endif +#ifdef CONFIG_AT32_CAN2 + if (port == 2) + { + /* Select the CAN2 device structure */ + + priv = &g_can2priv; + + /* Configure CAN2 pins. The ambiguous settings in the at32*_pinmap.h + * file must have been disambiguated in the board.h file. + */ + + at32_configgpio(GPIO_CAN2_RX); + at32_configgpio(GPIO_CAN2_TX); + } + else +#endif + { + nerr("ERROR: Unsupported port %d\n", port); + ret = -EINVAL; + goto errout; + } + + /* Initialize the driver structure */ + + priv->dev.d_ifup = at32can_ifup; + priv->dev.d_ifdown = at32can_ifdown; + priv->dev.d_txavail = at32can_txavail; +#ifdef CONFIG_NETDEV_IOCTL + priv->dev.d_ioctl = at32can_netdev_ioctl; +#endif + priv->dev.d_private = priv; + + /* Put the interface in the down state. This usually amounts to resetting + * the device and/or calling at32can_ifdown(). + */ + + ninfo("callbacks done\n"); + + at32can_ifdown(&priv->dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + ret = netdev_register(&priv->dev, NET_LL_CAN); + +errout: + return ret; +} + +/**************************************************************************** + * Name: arm_netinitialize + * + * Description: + * Initialize the CAN device interfaces. If there is more than one device + * interface in the chip, then board-specific logic will have to provide + * this function to determine which, if any, CAN interfaces should be + * initialized. + * + ****************************************************************************/ + +#if !defined(CONFIG_NETDEV_LATEINIT) && !defined(CONFIG_AT32_ETHMAC) +void arm_netinitialize(void) +{ +#ifdef CONFIG_AT32_CAN1 + at32_cansockinitialize(1); +#endif + +#ifdef CONFIG_AT32_CAN2 + at32_cansockinitialize(2); +#endif +} +#endif + diff --git a/arch/arm/src/at32/at32_dbgmcu.h b/arch/arm/src/at32/at32_dbgmcu.h new file mode 100644 index 0000000000..1ce5832798 --- /dev/null +++ b/arch/arm/src/at32/at32_dbgmcu.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_dbgmcu.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_DBGMCU_H +#define __ARCH_ARM_SRC_AT32_AT32_DBGMCU_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" +#include "hardware/at32_dbgmcu.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_AT32_AT32_DBGMCU_H */ diff --git a/arch/arm/src/at32/at32_dma.c b/arch/arm/src/at32/at32_dma.c new file mode 100644 index 0000000000..7d400d69f8 --- /dev/null +++ b/arch/arm/src/at32/at32_dma.c @@ -0,0 +1,47 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_dma.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/* This file is only a thin shell that includes the correct DMA + * implementation for the selected AT32 IP core: + * - AT32 DMA IP version 1 - F43X + * + */ + +#if defined(CONFIG_AT32_HAVE_IP_DMA_V1) +# if defined(CONFIG_AT32_HAVE_DMAMUX) +# include "at32_dma_v1mux.c" +# else +# include "at32_dma_v1.c" +# endif +#elif defined(CONFIG_AT32_HAVE_IP_DMA_V2) +# include "at32_dma_v2.c" +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ diff --git a/arch/arm/src/at32/at32_dma.h b/arch/arm/src/at32/at32_dma.h new file mode 100644 index 0000000000..0761183b56 --- /dev/null +++ b/arch/arm/src/at32/at32_dma.h @@ -0,0 +1,315 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_dma.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_DMA_H +#define __ARCH_ARM_SRC_AT32_AT32_DMA_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "chip.h" + +#include "hardware/at32_dma.h" + +#ifdef CONFIG_AT32_HAVE_DMAMUX +# include "hardware/at32_dmamux.h" +#endif + +/* These definitions provide the bit encoding of the 'status' parameter + * passed to the DMA callback function (see dma_callback_t). + */ + +#define DMA_STATUS_FEIF 0 /* (Not available in F1) */ +#define DMA_STATUS_DMEIF 0 /* (Not available in F1) */ +#define DMA_STATUS_TEIF DMA_CHAN_TEIF_BIT /* Channel Transfer Error */ +#define DMA_STATUS_HTIF DMA_CHAN_HTIF_BIT /* Channel Half Transfer */ +#define DMA_STATUS_TCIF DMA_CHAN_TCIF_BIT /* Channel Transfer Complete */ + +#define DMA_STATUS_ERROR (DMA_STATUS_FEIF | DMA_STATUS_DMEIF | DMA_STATUS_TEIF) +#define DMA_STATUS_SUCCESS (DMA_STATUS_TCIF | DMA_STATUS_HTIF) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* DMA_HANDLE provides an opaque reference that can be used to represent a + * DMA channel (F1) or a DMA stream (F4). + */ + +typedef void *DMA_HANDLE; + +/* Description: + * This is the type of the callback that is used to inform the user of the + * completion of the DMA. + * + * Input Parameters: + * handle - Refers to the DMA channel or stream + * status - A bit encoded value that provides the completion status. See + * the DMASTATUS_* definitions above. + * arg - A user-provided value that was provided when at32_dmastart() + * was called. + */ + +typedef void (*dma_callback_t)(DMA_HANDLE handle, uint8_t status, void *arg); + +#ifdef CONFIG_DEBUG_DMA_INFO + +struct at32_dmaregs_s +{ + uint32_t isr; + uint32_t ccr; + uint32_t cndtr; + uint32_t cpar; + uint32_t cmar; +}; + +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_dmachannel + * + * Description: + * Allocate a DMA channel. This function gives the caller mutually + * exclusive access to the DMA channel specified by the 'chan' argument. + * DMA channels are shared on the AT32: Devices sharing the same DMA + * channel cannot do DMA concurrently! See the DMACHAN_* definitions in + * at32_dma.h. + * + * If the DMA channel is not available, then at32_dmachannel() will wait + * until the holder of the channel relinquishes the channel by calling + * at32_dmafree(). WARNING: If you have two devices sharing a DMA + * channel and the code never releases the channel, the at32_dmachannel + * call for the other will hang forever in this function! Don't let your + * design do that! + * + * Hmm.. I suppose this interface could be extended to make a non-blocking + * version. Feel free to do that if that is what you need. + * + * Input Parameters: + * chan - Identifies the channel resource + * + * Returned Value: + * Provided that 'chan' is valid, this function ALWAYS returns a non-NULL, + * void* DMA channel handle. (If 'chan' is invalid, the function will + * assert if debug is enabled or do something ignorant otherwise). + * + * Assumptions: + * - The caller does not hold he DMA channel. + * - The caller can wait for the DMA channel to be freed if it is no + * available. + * + ****************************************************************************/ + +DMA_HANDLE at32_dmachannel(unsigned int chan); + +/**************************************************************************** + * Name: at32_dmafree + * + * Description: + * Release a DMA channel. If another thread is waiting for this DMA + * channel in a call to at32_dmachannel, then this function will re- + * assign the DMA channel to that thread and wake it up. + * + * NOTE: The 'handle' used in this argument must NEVER be used again + * until at32_dmachannel() is called again to re-gain access to the + * channel. + * + * Returned Value: + * None + * + * Assumptions: + * - The caller holds the DMA channel. + * - There is no DMA in progress + * + ****************************************************************************/ + +void at32_dmafree(DMA_HANDLE handle); + +/**************************************************************************** + * Name: at32_dmasetup + * + * Description: + * Configure DMA before using + * + ****************************************************************************/ + +void at32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, + size_t ntransfers, uint32_t ccr); + +/**************************************************************************** + * Name: at32_dmastart + * + * Description: + * Start the DMA transfer + * + * Assumptions: + * - DMA handle allocated by at32_dmachannel() + * - No DMA in progress + * + ****************************************************************************/ + +void at32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, + bool half); + +/**************************************************************************** + * Name: at32_dmastop + * + * Description: + * Cancel the DMA. After at32_dmastop() is called, the DMA channel is + * reset and at32_dmasetup() must be called before at32_dmastart() can be + * called again + * + * Assumptions: + * - DMA handle allocated by at32_dmachannel() + * + ****************************************************************************/ + +void at32_dmastop(DMA_HANDLE handle); + +/**************************************************************************** + * Name: at32_dmaresidual + * + * Description: + * Returns the number of bytes remaining to be transferred + * + * Assumptions: + * - DMA handle allocated by at32_dmachannel() + * + ****************************************************************************/ + +size_t at32_dmaresidual(DMA_HANDLE handle); + +/**************************************************************************** + * Name: at32_dmacapable + * + * Description: + * Check if the DMA controller can transfer data to/from given memory + * address with the given configuration. This depends on the internal + * connections in the ARM bus matrix of the processor. Note that this only + * applies to memory addresses, it will return false for any peripheral + * address. + * + * Returned Value: + * True, if transfer is possible. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_DMACAPABLE +bool at32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr); +#else +# define at32_dmacapable(maddr, count, ccr) (true) +#endif + +/**************************************************************************** + * Name: at32_dmasample + * + * Description: + * Sample DMA register contents + * + * Assumptions: + * - DMA handle allocated by at32_dmachannel() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +void at32_dmasample(DMA_HANDLE handle, struct at32_dmaregs_s *regs); +#else +# define at32_dmasample(handle,regs) +#endif + +/**************************************************************************** + * Name: at32_dmadump + * + * Description: + * Dump previously sampled DMA register contents + * + * Assumptions: + * - DMA handle allocated by at32_dmachannel() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +void at32_dmadump(DMA_HANDLE handle, const struct at32_dmaregs_s *regs, + const char *msg); +#else +# define at32_dmadump(handle,regs,msg) +#endif + +/* High performance, zero latency DMA interrupts need some additional + * interfaces. + * + * TODO: For now the interface is different for AT32 DMAv1 and AT32 DMAv2. + * It should be unified somehow. + */ + +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + +/**************************************************************************** + * Name: at32_dma_intack + * + * Description: + * Public visible interface to acknowledge interrupts on DMA channel + * + ****************************************************************************/ + +void at32_dma_intack(unsigned int chndx, uint32_t isr); + +/**************************************************************************** + * Name: at32_dma_intget + * + * Description: + * Public visible interface to get pending interrupts from DMA channel + * + ****************************************************************************/ + +uint32_t at32_dma_intget(unsigned int chndx); + +#endif /* CONFIG_ARCH_HIPRI_INTERRUPT */ + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_DMA_H */ diff --git a/arch/arm/src/at32/at32_dma_v1mux.c b/arch/arm/src/at32/at32_dma_v1mux.c new file mode 100644 index 0000000000..d3085a4f19 --- /dev/null +++ b/arch/arm/src/at32/at32_dma_v1mux.c @@ -0,0 +1,1464 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_dma_v1mux.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "arm_internal.h" +#include "sched/sched.h" +#include "at32_dma.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_AT32_DMAMUX +# error "Configuration error, CONFIG_AT32_DMAMUX not defined!" +#endif + +#define DMAMUX_NUM 2 +#define DMA_CONTROLLERS 2 + +#ifdef CONFIG_AT32_DMA1 +# if defined(CONFIG_AT32_AT32F43XX) +# define DMA1_NCHAN 7 +# else +# error +# endif +#else +# define DMA1_NCHAN 0 +#endif +#ifdef CONFIG_AT32_DMA2 +# if defined(CONFIG_AT32_AT32F43XX) +# define DMA2_NCHAN 7 +# else +# error +# endif +#else +# define DMA2_NCHAN 0 +#endif + +#define DMA1_FIRST (0) +#define DMA1_LAST (DMA1_FIRST+DMA1_NCHAN) +#define DMA2_FIRST (DMA1_LAST) +#define DMA2_LAST (DMA2_FIRST+DMA2_NCHAN) + +/* All available DMA channels */ + +#define DMA_NCHANNELS (DMA1_NCHAN + DMA2_NCHAN) + +/* DMAMUX channels */ + +#if defined(CONFIG_AT32_AT32F43XX) +# define DMAMUX_NCHANNELS 14 +#else +# error +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure described one DMAMUX device */ + +struct at32_dmamux_s +{ + uint8_t id; /* DMAMUX id */ + uint8_t nchan; /* DMAMUX channels */ + uint32_t base; /* DMAMUX base address */ +}; + +typedef const struct at32_dmamux_s *DMA_MUX; + +/* This structure describes one DMA controller */ + +struct at32_dma_s +{ + uint8_t first; /* Offset in at32_dmach_s array */ + uint8_t nchan; /* Number of channels */ + uint8_t dmamux_offset; /* DMAMUX channel offset */ + uint32_t base; /* Base address */ + DMA_MUX dmamux; /* DMAMUX associated with controller */ +}; + +/* This structure describes one DMA channel (DMA1, DMA2) */ + +struct at32_dmach_s +{ + bool used; /* Channel in use */ + uint8_t dmamux_req; /* Configured DMAMUX input request */ + uint8_t ctrl; /* DMA controller */ + uint8_t chan; /* DMA channel channel id */ + uint8_t irq; /* DMA channel IRQ number */ + uint8_t shift; /* IFCR bit shift value */ + uint32_t base; /* DMA register channel base address */ + dma_callback_t callback; /* Callback invoked when the DMA completes */ + void *arg; /* Argument passed to callback function */ +}; + +typedef struct at32_dmach_s *DMA_CHANNEL; + +/* DMA operations */ + +struct at32_dma_ops_s +{ + /* Disable the DMA transfer */ + + void (*dma_disable)(DMA_CHANNEL dmachan); + + /* DMA interrupt */ + + int (*dma_interrupt)(int irq, void *context, void *arg); + + /* Setup the DMA */ + + void (*dma_setup)(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, + size_t ntransfers, uint32_t ccr); + + /* Start the DMA */ + + void (*dma_start)(DMA_HANDLE handle, dma_callback_t callback, + void *arg, bool half); + + /* Read remaining DMA bytes */ + + size_t (*dma_residual)(DMA_HANDLE handle); + + /* Check the DMA configuration */ + + bool (*dma_capable)(uint32_t maddr, uint32_t count, uint32_t ccr); + +#ifdef CONFIG_DEBUG_DMA_INFO + /* Sample the DMA registers */ + + void (*dma_sample)(DMA_HANDLE handle, struct at32_dmaregs_s *regs); + + /* Dump the DMA registers */ + + void (*dma_dump)(DMA_HANDLE handle, + const struct at32_dmaregs_s *regs, + const char *msg); +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#if defined(CONFIG_AT32_DMA1) || defined(CONFIG_AT32_DMA2) +static void at32_dma12_disable(DMA_CHANNEL dmachan); +static int at32_dma12_interrupt(int irq, void *context, void *arg); +static void at32_dma12_setup(DMA_HANDLE handle, uint32_t paddr, + uint32_t maddr, size_t ntransfers, + uint32_t ccr); +static void at32_dma12_start(DMA_HANDLE handle, dma_callback_t callback, + void *arg, bool half); +static size_t at32_dma12_residual(DMA_HANDLE handle); +#ifdef CONFIG_DEBUG_DMA_INFO +static void at32_dma12_sample(DMA_HANDLE handle, + struct at32_dmaregs_s *regs); +static void at32_dma12_dump(DMA_HANDLE handle, + const struct at32_dmaregs_s *regs, + const char *msg); +#endif +#endif + +static uint32_t dmachan_getbase(DMA_CHANNEL dmachan); +static uint32_t dmabase_getreg(DMA_CHANNEL dmachan, uint32_t offset); +static void dmabase_putreg(DMA_CHANNEL dmachan, uint32_t offset, + uint32_t value); +static uint32_t dmachan_getreg(DMA_CHANNEL dmachan, uint32_t offset); +static void dmachan_putreg(DMA_CHANNEL dmachan, uint32_t offset, + uint32_t value); +static void dmamux_putreg(DMA_MUX dmamux, uint32_t offset, uint32_t value); +#ifdef CONFIG_DEBUG_DMA_INFO +static uint32_t dmamux_getreg(DMA_MUX dmamux, uint32_t offset); +static void at32_dmamux_sample(DMA_MUX dmamux, uint8_t chan, + struct at32_dmaregs_s *regs); +static void at32_dmamux_dump(DMA_MUX dmamux, uint8_t channel, + const struct at32_dmaregs_s *regs); +#endif +static DMA_CHANNEL at32_dma_channel_get(uint8_t channel, + uint8_t controller); +static void at32_gdma_limits_get(uint8_t controller, uint8_t *first, + uint8_t *last); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Operations specific to DMA controller */ + +static const struct at32_dma_ops_s g_dma_ops[DMA_CONTROLLERS] = +{ +#ifdef CONFIG_AT32_DMA1 + /* 0 - DMA1 */ + + { + .dma_disable = at32_dma12_disable, + .dma_interrupt = at32_dma12_interrupt, + .dma_setup = at32_dma12_setup, + .dma_start = at32_dma12_start, + .dma_residual = at32_dma12_residual, +#ifdef CONFIG_DEBUG_DMA_INFO + .dma_sample = at32_dma12_sample, + .dma_dump = at32_dma12_dump, +#endif + }, +#else + { + NULL + }, +#endif + +#ifdef CONFIG_AT32_DMA2 + /* 1 - DMA2 */ + + { + .dma_disable = at32_dma12_disable, + .dma_interrupt = at32_dma12_interrupt, + .dma_setup = at32_dma12_setup, + .dma_start = at32_dma12_start, + .dma_residual = at32_dma12_residual, +#ifdef CONFIG_DEBUG_DMA_INFO + .dma_sample = at32_dma12_sample, + .dma_dump = at32_dma12_dump, +#endif + } +#else + { + NULL + } +#endif +}; + +/* This array describes the state of DMAMUX controller */ + +static const struct at32_dmamux_s g_dmamux[DMAMUX_NUM] = +{ + /* 1 - DMA1 */ + + { + .id = 1, + .nchan = DMAMUX_NCHANNELS, + .base = AT32_DMAMUX1_BASE + }, + + /* 2 - DMA2 */ + + { + .id = 2, + .nchan = DMAMUX_NCHANNELS, + .base = AT32_DMAMUX2_BASE + } +}; + +/* This array describes the state of each controller */ + +static const struct at32_dma_s g_dma[DMA_NCHANNELS] = +{ + /* 0 - DMA1 */ + + { + .base = AT32_DMA1_BASE, + .first = DMA1_FIRST, + .nchan = DMA1_NCHAN, + .dmamux = &g_dmamux[DMAMUX1], /* DMAMUX1 channels 0-6 */ + .dmamux_offset = 0 + }, + + /* 1 - DMA2 */ + + { + .base = AT32_DMA2_BASE, + .first = DMA2_FIRST, + .nchan = DMA2_NCHAN, + .dmamux = &g_dmamux[DMAMUX2], /* DMAMUX1 channels 7-13 */ + .dmamux_offset = 7 + } +}; + +/* This array describes the state of each DMA channel. */ + +static struct at32_dmach_s g_dmach[DMA_NCHANNELS] = +{ +#ifdef CONFIG_AT32_DMA1 + /* DMA1 */ + + { + .ctrl = DMA1, + .chan = 0, + .irq = AT32_IRQ_DMA1CH1, + .shift = DMA_CHAN_SHIFT(0), + .base = AT32_DMA1_BASE + AT32_DMACHAN_OFFSET(0), + }, + + { + .ctrl = DMA1, + .chan = 1, + .irq = AT32_IRQ_DMA1CH2, + .shift = DMA_CHAN_SHIFT(1), + .base = AT32_DMA1_BASE + AT32_DMACHAN_OFFSET(1), + }, + + { + .ctrl = DMA1, + .chan = 2, + .irq = AT32_IRQ_DMA1CH3, + .shift = DMA_CHAN_SHIFT(2), + .base = AT32_DMA1_BASE + AT32_DMACHAN_OFFSET(2), + }, + + { + .ctrl = DMA1, + .chan = 3, + .irq = AT32_IRQ_DMA1CH4, + .shift = DMA_CHAN_SHIFT(3), + .base = AT32_DMA1_BASE + AT32_DMACHAN_OFFSET(3), + }, + + { + .ctrl = DMA1, + .chan = 4, + .irq = AT32_IRQ_DMA1CH5, + .shift = DMA_CHAN_SHIFT(4), + .base = AT32_DMA1_BASE + AT32_DMACHAN_OFFSET(4), + }, + + { + .ctrl = DMA1, + .chan = 5, + .irq = AT32_IRQ_DMA1CH6, + .shift = DMA_CHAN_SHIFT(5), + .base = AT32_DMA1_BASE + AT32_DMACHAN_OFFSET(5), + }, + + { + .ctrl = DMA1, + .chan = 6, + .irq = AT32_IRQ_DMA1CH7, + .shift = DMA_CHAN_SHIFT(6), + .base = AT32_DMA1_BASE + AT32_DMACHAN_OFFSET(6), + }, + +# if DMA1_NCHAN > 7 + { + .ctrl = DMA1, + .chan = 7, + .irq = AT32_IRQ_DMA1CH8, + .shift = DMA_CHAN_SHIFT(7), + .base = AT32_DMA1_BASE + AT32_DMACHAN_OFFSET(7), + }, +# endif +#endif + +#ifdef CONFIG_AT32_DMA2 + /* DMA2 */ + + { + .ctrl = DMA2, + .chan = 0, + .irq = AT32_IRQ_DMA2CH1, + .shift = DMA_CHAN_SHIFT(0), + .base = AT32_DMA2_BASE + AT32_DMACHAN_OFFSET(0), + }, + + { + .ctrl = DMA2, + .chan = 1, + .irq = AT32_IRQ_DMA2CH2, + .shift = DMA_CHAN_SHIFT(1), + .base = AT32_DMA2_BASE + AT32_DMACHAN_OFFSET(1), + }, + + { + .ctrl = DMA2, + .chan = 2, + .irq = AT32_IRQ_DMA2CH3, + .shift = DMA_CHAN_SHIFT(2), + .base = AT32_DMA2_BASE + AT32_DMACHAN_OFFSET(2), + }, + + { + .ctrl = DMA2, + .chan = 3, + .irq = AT32_IRQ_DMA2CH4, + .shift = DMA_CHAN_SHIFT(3), + .base = AT32_DMA2_BASE + AT32_DMACHAN_OFFSET(3), + }, + + { + .ctrl = DMA2, + .chan = 4, + .irq = AT32_IRQ_DMA2CH5, + .shift = DMA_CHAN_SHIFT(4), + .base = AT32_DMA2_BASE + AT32_DMACHAN_OFFSET(4), + }, + + { + .ctrl = DMA2, + .chan = 5, + .irq = AT32_IRQ_DMA2CH6, + .shift = DMA_CHAN_SHIFT(5), + .base = AT32_DMA2_BASE + AT32_DMACHAN_OFFSET(5), + }, + +# if DMA2_NCHAN > 6 + { + .ctrl = DMA2, + .chan = 6, + .irq = AT32_IRQ_DMA2CH7, + .shift = DMA_CHAN_SHIFT(6), + .base = AT32_DMA2_BASE + AT32_DMACHAN_OFFSET(6), + }, +# endif + +# if DMA2_NCHAN > 7 + { + .ctrl = DMA2, + .chan = 7, + .irq = AT32_IRQ_DMA2CH8, + .shift = DMA_CHAN_SHIFT(7), + .base = AT32_DMA2_BASE + AT32_DMACHAN_OFFSET(7), + }, +# endif +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * DMA register access functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dmachan_getbase + * + * Description: + * Get base DMA address for dmachan + * + ****************************************************************************/ + +static uint32_t dmachan_getbase(DMA_CHANNEL dmachan) +{ + uint8_t controller = dmachan->ctrl; + + return g_dma[controller].base; +} + +/**************************************************************************** + * Name: dmabase_getreg + * + * Description: + * Get non-channel register from DMA controller + * + ****************************************************************************/ + +static uint32_t dmabase_getreg(DMA_CHANNEL dmachan, uint32_t offset) +{ + uint32_t dmabase = dmachan_getbase(dmachan); + + return getreg32(dmabase + offset); +} + +/**************************************************************************** + * Name: dmabase_putreg + * + * Description: + * Write to non-channel register in DMA controller + * + ****************************************************************************/ + +static void dmabase_putreg(DMA_CHANNEL dmachan, uint32_t offset, + uint32_t value) +{ + uint32_t dmabase = dmachan_getbase(dmachan); + + putreg32(value, dmabase + offset); +} + +/**************************************************************************** + * Name: dmachan_getreg + * + * Description: + * Get channel register. + * + ****************************************************************************/ + +static uint32_t dmachan_getreg(DMA_CHANNEL dmachan, uint32_t offset) +{ + return getreg32(dmachan->base + offset); +} + +/**************************************************************************** + * Name: dmachan_putreg + * + * Description: + * Write to channel register. + * + ****************************************************************************/ + +static void dmachan_putreg(DMA_CHANNEL dmachan, uint32_t offset, + uint32_t value) +{ + putreg32(value, dmachan->base + offset); +} + +/**************************************************************************** + * Name: dmamux_getreg + * + * Description: + * Write to DMAMUX + * + ****************************************************************************/ + +static void dmamux_putreg(DMA_MUX dmamux, uint32_t offset, uint32_t value) +{ + putreg32(value, dmamux->base + offset); +} + +/**************************************************************************** + * Name: dmamux_getreg + * + * Description: + * Get DMAMUX register. + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +static uint32_t dmamux_getreg(DMA_MUX dmamux, uint32_t offset) +{ + return getreg32(dmamux->base + offset); +} +#endif + +/**************************************************************************** + * Name: at32_dma_channel_get + * + * Description: + * Get the g_dmach table entry associated with a given DMA controller + * and channel number. + * + ****************************************************************************/ + +static DMA_CHANNEL at32_dma_channel_get(uint8_t channel, + uint8_t controller) +{ + uint8_t first = 0; + uint8_t nchan = 0; + + /* Get limits for g_dma array */ + + at32_gdma_limits_get(controller, &first, &nchan); + + DEBUGASSERT(channel <= nchan); + + return &g_dmach[first + channel]; +} + +/**************************************************************************** + * Name: at32_gdma_limits_get + * + * Description: + * Get g_dma array limits for a given DMA controller. + * + ****************************************************************************/ + +static void at32_gdma_limits_get(uint8_t controller, uint8_t *first, + uint8_t *nchan) +{ + DEBUGASSERT(first != NULL); + DEBUGASSERT(nchan != NULL); + + DEBUGASSERT(controller >= DMA1 && controller <= DMA2); + + *first = g_dma[controller].first; + *nchan = g_dma[controller].nchan; +} + +/**************************************************************************** + * DMA controller functions + ****************************************************************************/ + +#if defined(CONFIG_AT32_DMA1) || defined(CONFIG_AT32_DMA2) + +/**************************************************************************** + * Name: at32_dma12_disable + * + * Description: + * Disable DMA channel (DMA1/DMA2) + * + ****************************************************************************/ + +static void at32_dma12_disable(DMA_CHANNEL dmachan) +{ + uint32_t regval; + + DEBUGASSERT(dmachan->ctrl == DMA1 || dmachan->ctrl == DMA2); + + /* Disable all interrupts at the DMA controller */ + + regval = dmachan_getreg(dmachan, AT32_DMACHAN_CCR_OFFSET); + regval &= ~DMA_CCR_ALLINTS; + + /* Disable the DMA channel */ + + regval &= ~DMA_CCR_EN; + dmachan_putreg(dmachan, AT32_DMACHAN_CCR_OFFSET, regval); + + /* Clear pending channel interrupts */ + + dmabase_putreg(dmachan, AT32_DMA_IFCR_OFFSET, + DMA_ISR_CHAN_MASK(dmachan->chan)); +} + +/**************************************************************************** + * Name: at32_dma12_interrupt + * + * Description: + * DMA channel interrupt handler + * + ****************************************************************************/ + +static int at32_dma12_interrupt(int irq, void *context, void *arg) +{ + DMA_CHANNEL dmachan; + uint32_t isr; + uint8_t channel; + uint8_t controller; + + /* Get the channel and the controller that generated the interrupt */ + + if (0) + { + } +#ifdef CONFIG_AT32_DMA1 + else if (irq >= AT32_IRQ_DMA1CH1 && irq <= AT32_IRQ_DMA1CH5) + { + channel = irq - AT32_IRQ_DMA1CH1; + controller = DMA1; + } + else if (irq >= AT32_IRQ_DMA1CH6 && irq <= AT32_IRQ_DMA1CH7) + { + channel = irq - AT32_IRQ_DMA1CH6 + (6 - 1); + controller = DMA1; + } +#endif +#ifdef CONFIG_AT32_DMA2 + else if (irq >= AT32_IRQ_DMA2CH1 && irq <= AT32_IRQ_DMA2CH7) + { + channel = irq - AT32_IRQ_DMA2CH1; + controller = DMA2; + } +#endif + else + { + DEBUGPANIC(); + return OK; + } + + /* Get the channel structure from the stream and controller numbers */ + + dmachan = at32_dma_channel_get(channel, controller); + + /* Get the interrupt status (for this channel only) */ + + isr = dmabase_getreg(dmachan, AT32_DMA_ISR_OFFSET) & + DMA_ISR_CHAN_MASK(dmachan->chan); + + /* Invoke the callback */ + + if (dmachan->callback) + { + dmachan->callback(dmachan, isr >> DMA_ISR_CHAN_SHIFT(dmachan->chan), + dmachan->arg); + } + + /* Clear the interrupts we are handling */ + + dmabase_putreg(dmachan, AT32_DMA_IFCR_OFFSET, isr); + + return OK; +} + +/**************************************************************************** + * Name: at32_dma12_setup + * + * Description: + * Configure DMA before using + * + ****************************************************************************/ + +static void at32_dma12_setup(DMA_HANDLE handle, uint32_t paddr, + uint32_t maddr, size_t ntransfers, + uint32_t ccr) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + uint32_t regval; + + DEBUGASSERT(handle != NULL); + DEBUGASSERT(ntransfers < 65536); + + DEBUGASSERT(dmachan->ctrl == DMA1 || dmachan->ctrl == DMA2); + + dmainfo("paddr: %08" PRIx32 " maddr: %08" PRIx32 + " ntransfers: %zd ccr: %08" PRIx32 "\n", + paddr, maddr, ntransfers, ccr); + +#ifdef CONFIG_AT32_DMACAPABLE + DEBUGASSERT(g_dma_ops[dmachan->ctrl].dma_capable(maddr, ntransfers, ccr)); +#endif + + /* Then DMA_CNDTRx register can only be modified if the DMA channel is + * disabled. + */ + + regval = dmachan_getreg(dmachan, AT32_DMACHAN_CCR_OFFSET); + regval &= ~(DMA_CCR_EN); + dmachan_putreg(dmachan, AT32_DMACHAN_CCR_OFFSET, regval); + + /* Set the peripheral register address in the DMA_CPARx register. The data + * will be moved from/to this address to/from the memory after the + * peripheral event. + */ + + dmachan_putreg(dmachan, AT32_DMACHAN_CPAR_OFFSET, paddr); + + /* Set the memory address in the DMA_CMARx register. The data will be + * written to or read from this memory after the peripheral event. + */ + + dmachan_putreg(dmachan, AT32_DMACHAN_CMAR_OFFSET, maddr); + + /* Configure the total number of data to be transferred in the DMA_CNDTRx + * register. After each peripheral event, this value will be decremented. + */ + + dmachan_putreg(dmachan, AT32_DMACHAN_CNDTR_OFFSET, ntransfers); + + /* Configure the channel priority using the PL[1:0] bits in the DMA_CCRx + * register. Configure data transfer direction, circular mode, peripheral + * & memory incremented mode, peripheral & memory data size, and interrupt + * after half and/or full transfer in the DMA_CCRx register. + */ + + regval = dmachan_getreg(dmachan, AT32_DMACHAN_CCR_OFFSET); + regval &= ~(DMA_CCR_MEM2MEM | DMA_CCR_PL_MASK | DMA_CCR_MSIZE_MASK | + DMA_CCR_PSIZE_MASK | DMA_CCR_MINC | DMA_CCR_PINC | + DMA_CCR_CIRC | DMA_CCR_DIR); + ccr &= (DMA_CCR_MEM2MEM | DMA_CCR_PL_MASK | DMA_CCR_MSIZE_MASK | + DMA_CCR_PSIZE_MASK | DMA_CCR_MINC | DMA_CCR_PINC | + DMA_CCR_CIRC | DMA_CCR_DIR); + regval |= ccr; + dmachan_putreg(dmachan, AT32_DMACHAN_CCR_OFFSET, regval); +} + +/**************************************************************************** + * Name: at32_dma12_start + * + * Description: + * Start the standard DMA transfer + ****************************************************************************/ + +static void at32_dma12_start(DMA_HANDLE handle, dma_callback_t callback, + void *arg, bool half) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + uint32_t ccr; + + DEBUGASSERT(dmachan->ctrl == DMA1 || dmachan->ctrl == DMA2); + + /* Save the callback info. This will be invoked when the DMA completes */ + + dmachan->callback = callback; + dmachan->arg = arg; + + /* Activate the channel by setting the ENABLE bit in the DMA_CCRx register. + * As soon as the channel is enabled, it can serve any DMA request from the + * peripheral connected on the channel. + */ + + ccr = dmachan_getreg(dmachan, AT32_DMACHAN_CCR_OFFSET); + ccr |= DMA_CCR_EN; + + /* In normal mode, interrupt at either half or full completion. In circular + * mode, always interrupt on buffer wrap, and optionally interrupt at the + * halfway point. + */ + + if ((ccr & DMA_CCR_CIRC) == 0) + { + /* Once half of the bytes are transferred, the half-transfer flag + * (HTIF) is set and an interrupt is generated if the Half-Transfer + * Interrupt Enable bit (HTIE) is set. At the end of the transfer, + * the Transfer Complete Flag (TCIF) is set and an interrupt is + * generated if the Transfer Complete Interrupt Enable bit (TCIE) + * is set. + */ + + ccr |= (half ? (DMA_CCR_HTIE | DMA_CCR_TEIE) : + (DMA_CCR_TCIE | DMA_CCR_TEIE)); + } + else + { + /* In nonstop mode, when the transfer completes it immediately resets + * and starts again. The transfer-complete interrupt is thus always + * enabled, and the half-complete interrupt can be used in circular + * mode to determine when the buffer is half-full, or in + * double-buffered mode to determine when one of the two buffers + * is full. + */ + + ccr |= (half ? DMA_CCR_HTIE : 0) | DMA_CCR_TCIE | DMA_CCR_TEIE; + } + + dmachan_putreg(dmachan, AT32_DMACHAN_CCR_OFFSET, ccr); +} + +/**************************************************************************** + * Name: at32_dma12_residual + ****************************************************************************/ + +static size_t at32_dma12_residual(DMA_HANDLE handle) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + + DEBUGASSERT(dmachan->ctrl == DMA1 || dmachan->ctrl == DMA2); + + return dmachan_getreg(dmachan, AT32_DMACHAN_CNDTR_OFFSET); +} + +/**************************************************************************** + * Name: at32_dma12_sample + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +void at32_dma12_sample(DMA_HANDLE handle, struct at32_dmaregs_s *regs) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + irqstate_t flags; + + flags = enter_critical_section(); + + regs->isr = dmabase_getreg(dmachan, AT32_DMA_ISR_OFFSET); + regs->ccr = dmachan_getreg(dmachan, AT32_DMACHAN_CCR_OFFSET); + regs->cndtr = dmachan_getreg(dmachan, AT32_DMACHAN_CNDTR_OFFSET); + regs->cpar = dmachan_getreg(dmachan, AT32_DMACHAN_CPAR_OFFSET); + regs->cmar = dmachan_getreg(dmachan, AT32_DMACHAN_CMAR_OFFSET); + +#if 0 + at32_dmamux_sample(g_dma[dmachan->ctrl].dmamux, + dmachan->chan + g_dma[dmachan->ctrl].dmamux_offset, + regs); +#endif + + leave_critical_section(flags); +} +#endif + +/**************************************************************************** + * Name: at32_dma12_dump + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +static void at32_dma12_dump(DMA_HANDLE handle, + const struct at32_dmaregs_s *regs, + const char *msg) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + + DEBUGASSERT(dmachan->ctrl == DMA1 || dmachan->ctrl == DMA2); + + uint32_t dmabase = dmachan_getbase(dmachan); + + dmainfo("DMA%d Registers: %s\n", + dmachan->ctrl + 1, + msg); + dmainfo(" ISR[%08x]: %08x\n", + dmabase + AT32_DMA_ISR_OFFSET, + regs->isr); + dmainfo(" CCR[%08x]: %08x\n", + dmachan->base + AT32_DMACHAN_CCR_OFFSET, + regs->ccr); + dmainfo(" CNDTR[%08x]: %08x\n", + dmachan->base + AT32_DMACHAN_CNDTR_OFFSET, + regs->cndtr); + dmainfo(" CPAR[%08x]: %08x\n", + dmachan->base + AT32_DMACHAN_CPAR_OFFSET, + regs->cpar); + dmainfo(" CMAR[%08x]: %08x\n", + dmachan->base + AT32_DMACHAN_CMAR_OFFSET, + regs->cmar); + + at32_dmamux_dump(g_dma[dmachan->ctrl].dmamux, + dmachan->chan + g_dma[dmachan->ctrl].dmamux_offset, + regs); +} +#endif + +#endif /* CONFIG_AT32_DMA1 || CONFIG_AT32_DMA2 */ + +/**************************************************************************** + * Name: at32_dmamux_sample + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +static void at32_dmamux_sample(DMA_MUX dmamux, uint8_t chan, + struct at32_dmaregs_s *regs) +{ + #if 0 + regs->dmamux.ccr = dmamux_getreg(dmamux, AT32_DMAMUX_CXCR_OFFSET(chan)); + regs->dmamux.csr = dmamux_getreg(dmamux, AT32_DMAMUX_CSR_OFFSET); + regs->dmamux.rg0cr = dmamux_getreg(dmamux, AT32_DMAMUX_RG0CR_OFFSET); + regs->dmamux.rg1cr = dmamux_getreg(dmamux, AT32_DMAMUX_RG1CR_OFFSET); + regs->dmamux.rg2cr = dmamux_getreg(dmamux, AT32_DMAMUX_RG2CR_OFFSET); + regs->dmamux.rg3cr = dmamux_getreg(dmamux, AT32_DMAMUX_RG3CR_OFFSET); + regs->dmamux.rgsr = dmamux_getreg(dmamux, AT32_DMAMUX_RGSR_OFFSET); + #endif +} +#endif + +/**************************************************************************** + * Name: at32_dmamux_dump + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +static void at32_dmamux_dump(DMA_MUX dmamux, uint8_t channel, + const struct at32_dmaregs_s *regs) +{ +#if 0 + dmainfo("DMAMUX%d CH=%d\n", dmamux->id, channel); + dmainfo(" CCR[%08x]: %08x\n", + dmamux->base + AT32_DMAMUX_CXCR_OFFSET(channel), + regs->dmamux.ccr); + dmainfo(" CSR[%08x]: %08x\n", + dmamux->base + AT32_DMAMUX_CSR_OFFSET, regs->dmamux.csr); + dmainfo(" RG0CR[%08x]: %08x\n", + dmamux->base + AT32_DMAMUX_RG0CR_OFFSET, regs->dmamux.rg0cr); + dmainfo(" RG1CR[%08x]: %08x\n", + dmamux->base + AT32_DMAMUX_RG1CR_OFFSET, regs->dmamux.rg1cr); + dmainfo(" RG2CR[%08x]: %08x\n", + dmamux->base + AT32_DMAMUX_RG2CR_OFFSET, regs->dmamux.rg2cr); + dmainfo(" RG3CR[%08x]: %08x\n", + dmamux->base + AT32_DMAMUX_RG3CR_OFFSET, regs->dmamux.rg3cr); + dmainfo(" RGSR[%08x]: %08x\n", + dmamux->base + AT32_DMAMUX_RGSR_OFFSET, regs->dmamux.rgsr); +#endif +}; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_dma_initialize + * + * Description: + * Initialize the DMA subsystem (DMA1, DMA2) + * + * Returned Value: + * None + * + ****************************************************************************/ + +void weak_function arm_dma_initialize(void) +{ + DMA_CHANNEL dmachan; + uint8_t controller; + int channel; + + dmainfo("Initialize DMA\n"); + + /* Initialize DMA channels */ + + for (channel = 0; channel < DMA_NCHANNELS; channel++) + { + dmachan = &g_dmach[channel]; + + /* Initialize flag */ + + dmachan->used = false; + + /* Get DMA controller associated with channel */ + + controller = dmachan->ctrl; + + DEBUGASSERT(controller >= DMA1 && controller <= DMA2); + + /* Attach standard DMA interrupt vectors */ + + irq_attach(dmachan->irq, g_dma_ops[controller].dma_interrupt, + dmachan); + + /* Disable the DMA channel */ + + g_dma_ops[controller].dma_disable(dmachan); + + /* Enable the IRQ at the NVIC (still disabled at the DMA controller) */ + + up_enable_irq(dmachan->irq); + + /* Enable mux sel */ + + dmamux_putreg(g_dma[controller].dmamux, 0, 1); + } +} + +/**************************************************************************** + * Name: at32_dmachannel + * + * Description: + * Allocate a DMA channel. This function gives the caller mutually + * exclusive access to the DMA channel specified by the 'dmamap' argument. + * It is common for both DMA controllers (DMA1 and DMA2). + * + * Input Parameters: + * dmamap - Identifies the stream/channel resource. For the AT32+, this + * is a bit-encoded value as provided by the DMAMAP_* definitions + * in hardware/at32g4xxxx_dmamux.h + * + * Returned Value: + * On success, this function returns a non-NULL, void* DMA channel handle. + * NULL is returned on any failure. This function can fail only if no DMA + * channel is available. + * + * Assumptions: + * - The caller does not hold he DMA channel. + * - The caller can wait for the DMA channel to be freed if it is not + * available. + * + ****************************************************************************/ + +DMA_HANDLE at32_dmachannel(unsigned int dmamap) +{ + DMA_CHANNEL dmachan; + uint8_t dmamux_req; + irqstate_t flags; + uint8_t controller; + uint8_t first = 0; + uint8_t nchan = 0; + int item = -1; + int i; + + /* Get DMA controller from encoded DMAMAP value */ + + controller = DMAMAP_CONTROLLER(dmamap); + DEBUGASSERT(controller >= DMA1 && controller <= DMA2); + + /* Get DMAMUX channel from encoded DMAMAP value */ + + dmamux_req = DMAMAP_REQUEST(dmamap); + + /* Get g_dma array limits for given controller */ + + at32_gdma_limits_get(controller, &first, &nchan); + + /* Find available channel for given controller */ + + flags = enter_critical_section(); + for (i = first; i < first + nchan; i += 1) + { + if (g_dmach[i].used == false) + { + item = i; + g_dmach[i].used = true; + g_dmach[i].dmamux_req = dmamux_req; + break; + } + } + + leave_critical_section(flags); + + dmainfo("ctrl=%d item=%d\n", controller, item); + + if (item == -1) + { + dmainfo("No available DMA chan for CTRL=%d\n", + controller); + + /* No available channel */ + + return NULL; + } + + /* Assign DMA item */ + + dmachan = &g_dmach[item]; + + dmainfo("Get g_dmach[%d] CTRL=%d CH=%d\n", i, controller, dmachan->chan); + + /* Be sure that we have proper DMA controller */ + + DEBUGASSERT(dmachan->ctrl == controller); + + return (DMA_HANDLE)dmachan; +} + +/**************************************************************************** + * Name: at32_dmafree + * + * Description: + * Release a DMA channel and unmap DMAMUX if required. + * + * NOTE: The 'handle' used in this argument must NEVER be used again + * until at32_dmachannel() is called again to re-gain access to the + * channel. + * + * Returned Value: + * None + * + * Assumptions: + * - The caller holds the DMA channel. + * - There is no DMA in progress + * + ****************************************************************************/ + +void at32_dmafree(DMA_HANDLE handle) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + uint8_t controller; + irqstate_t flags; + + DEBUGASSERT(handle != NULL); + + /* Get DMA controller */ + + controller = dmachan->ctrl; + DEBUGASSERT(controller >= DMA1 && controller <= DMA2); + + dmainfo("Free g_dmach[%d] CTRL=%d CH=%d\n", dmachan - g_dmach, controller, + dmachan->chan); + UNUSED(controller); + + /* Release the channel */ + + flags = enter_critical_section(); + dmachan->used = false; + dmachan->dmamux_req = 0; + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: at32_dmasetup + * + * Description: + * Configure DMA before using + * + ****************************************************************************/ + +void at32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, + size_t ntransfers, uint32_t ccr) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + uint8_t controller; + + DEBUGASSERT(handle != NULL); + + /* Get DMA controller */ + + controller = dmachan->ctrl; + DEBUGASSERT(controller >= DMA1 && controller <= DMA2); + + g_dma_ops[controller].dma_setup(handle, paddr, maddr, ntransfers, ccr); +} + +/**************************************************************************** + * Name: at32_dmastart + * + * Description: + * Start the DMA transfer + * + * Assumptions: + * - DMA handle allocated by at32_dmachannel() + * - No DMA in progress + * + ****************************************************************************/ + +void at32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, + bool half) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + DMA_MUX dmamux; + uint32_t regval; + uint8_t dmamux_chan; + uint8_t controller; + + DEBUGASSERT(handle != NULL); + + /* Get DMA controller */ + + controller = dmachan->ctrl; + DEBUGASSERT(controller >= DMA1 && controller <= DMA2); + + /* Recommended channel configure procedure in reference manual: + * 1. Set and configure the DMA channel y, except enabling the channel y. + * 2. Set and configure the related DMAMUX y channel. + * 3. Last, activate the DMA channel y. + */ + + /* Get DMAMUX associated with DMA controller */ + + dmamux = g_dma[controller].dmamux; + dmamux_chan = dmachan->chan + g_dma[controller].dmamux_offset; + + /* DMAMUX Set DMA channel source */ + + regval = dmachan->dmamux_req << DMAMUX_CCR_DMAREQID_SHIFT; + dmamux_putreg(dmamux, AT32_DMAMUX_CXCR_OFFSET(dmamux_chan), regval); + + /* Enable DMA channel */ + + g_dma_ops[controller].dma_start(handle, callback, arg, half); +} + +/**************************************************************************** + * Name: at32_dmastop + * + * Description: + * Cancel the DMA. After at32_dmastop() is called, the DMA channel is + * reset and at32_dmasetup() must be called before at32_dmastart() + * can be called again + * + * Assumptions: + * - DMA handle allocated by at32_dmachannel() + * + ****************************************************************************/ + +void at32_dmastop(DMA_HANDLE handle) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + DMA_MUX dmamux; + uint8_t dmamux_chan; + uint8_t controller; + + DEBUGASSERT(handle != NULL); + + /* Get DMA controller */ + + controller = dmachan->ctrl; + DEBUGASSERT(controller >= DMA1 && controller <= DMA2); + + /* Get DMAMUX associated with DMA controller */ + + dmamux = g_dma[controller].dmamux; + dmamux_chan = dmachan->chan + g_dma[controller].dmamux_offset; + + /* Disable DMA channel */ + + g_dma_ops[controller].dma_disable(dmachan); + + /* DMAMUX Clear DMA channel source */ + + dmamux_putreg(dmamux, AT32_DMAMUX_CXCR_OFFSET(dmamux_chan), 0); +} + +/**************************************************************************** + * Name: at32_dmaresidual + * + * Description: + * Read the DMA bytes-remaining register. + * + * Assumptions: + * - DMA handle allocated by at32_dmachannel() + * + ****************************************************************************/ + +size_t at32_dmaresidual(DMA_HANDLE handle) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + uint8_t controller; + + DEBUGASSERT(handle != NULL); + + /* Get DMA controller */ + + controller = dmachan->ctrl; + DEBUGASSERT(controller >= DMA1 && controller <= DMA2); + + return g_dma_ops[controller].dma_residual(handle); +} + +/**************************************************************************** + * Name: at32_dmacapable + * + * Description: + * Check if the DMA controller can transfer data to/from given memory + * address. This depends on the internal connections in the ARM bus matrix + * of the processor. Note that this only applies to memory addresses, it + * will return false for any peripheral address. + * + * Input Parameters: + * cfg - DMA transfer configuration + * + * Returned Value: + * True, if transfer is possible. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_DMACAPABLE +bool at32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr) +{ + unsigned int msize_shift; + uint32_t transfer_size; + uint32_t mend; + + /* Verify that the address conforms to the memory transfer size. + * Transfers to/from memory performed by the DMA controller are + * required to be aligned to their size. + * + * Datasheet 3.13 claims + * "Access to Flash, SRAM, APB and AHB peripherals as source + * and destination" + */ + + switch (ccr & DMA_CCR_MSIZE_MASK) + { + case DMA_CCR_MSIZE_8BITS: + msize_shift = 0; + break; + + case DMA_CCR_MSIZE_16BITS: + msize_shift = 1; + break; + + case DMA_CCR_MSIZE_32BITS: + msize_shift = 2; + break; + + default: + return false; + } + + transfer_size = 1 << msize_shift; + + if ((maddr & (transfer_size - 1)) != 0) + { + return false; + } + + /* Verify that the transfer is to a memory region that supports DMA. */ + + mend = maddr + (count << msize_shift) - 1; + + if ((maddr & AT32_REGION_MASK) != (mend & AT32_REGION_MASK)) + { + return false; + } + + switch (maddr & AT32_REGION_MASK) + { + case AT32_PERIPH_BASE: + case AT32_FMC_PC_CARD: + case AT32_FSMC_BANK1: + case AT32_FMC_QSPI2: + case AT32_FSMC_BANK3: + case AT32_FMC_QSPI_BASE: + case AT32_SRAM_BASE: + case AT32_CODE_BASE: + case AT32_FMX_SDRAM: + + /* All RAM and flash is supported */ + + return true; + + default: + + /* Everything else is unsupported by DMA */ + + return false; + } +} +#endif + +/**************************************************************************** + * Name: at32_dmasample + * + * Description: + * Sample DMA register contents + * + * Assumptions: + * - DMA handle allocated by at32_dmachannel() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +void at32_dmasample(DMA_HANDLE handle, struct at32_dmaregs_s *regs) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + uint8_t controller; + + DEBUGASSERT(handle != NULL); + + /* Get DMA controller */ + + controller = dmachan->ctrl; + DEBUGASSERT(controller >= DMA1 && controller <= DMA2); + + g_dma_ops[controller].dma_sample(handle, regs); +} +#endif + +/**************************************************************************** + * Name: at32_dmadump + * + * Description: + * Dump previously sampled DMA register contents + * + * Assumptions: + * - DMA handle allocated by at32_dmachannel() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +void at32_dmadump(DMA_HANDLE handle, const struct at32_dmaregs_s *regs, + const char *msg) +{ + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + uint8_t controller; + + DEBUGASSERT(handle != NULL); + + /* Get DMA controller */ + + controller = dmachan->ctrl; + DEBUGASSERT(controller >= DMA1 && controller <= DMA2); + + dmainfo("DMA %d CH%d Registers: %s\n", dmachan->ctrl, dmachan->ctrl, msg); + + g_dma_ops[controller].dma_dump(handle, regs, msg); +} +#endif diff --git a/arch/arm/src/at32/at32_dumpgpio.c b/arch/arm/src/at32/at32_dumpgpio.c new file mode 100644 index 0000000000..3848a5876a --- /dev/null +++ b/arch/arm/src/at32/at32_dumpgpio.c @@ -0,0 +1,138 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_dumpgpio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/* Output debug info even if debug output is not selected. */ + +#undef CONFIG_DEBUG_INFO +#define CONFIG_DEBUG_INFO 1 + +#include +#include +#include + +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32_gpio.h" +#include "at32_rcc.h" + +#ifdef CONFIG_DEBUG_FEATURES + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Port letters for prettier debug output */ + +static const char g_portchar[AT32_NGPIO_PORTS] = +{ +#if AT32_NGPIO_PORTS > 8 +# error "Additional support required for this number of GPIOs" +#elif AT32_NGPIO_PORTS > 7 + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' +#elif AT32_NGPIO_PORTS > 6 + 'A', 'B', 'C', 'D', 'E', 'F', 'G' +#elif AT32_NGPIO_PORTS > 5 + 'A', 'B', 'C', 'D', 'E', 'F' +#elif AT32_NGPIO_PORTS > 4 + 'A', 'B', 'C', 'D', 'E' +#elif AT32_NGPIO_PORTS > 3 + 'A', 'B', 'C', 'D' +#elif AT32_NGPIO_PORTS > 2 + 'A', 'B', 'C' +#elif AT32_NGPIO_PORTS > 1 + 'A', 'B' +#elif AT32_NGPIO_PORTS > 0 + 'A' +#else +# error "Bad number of GPIOs" +#endif +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: at32_dumpgpio + * + * Description: + * Dump all GPIO registers associated with the provided base address + * + ****************************************************************************/ + +int at32_dumpgpio(uint32_t pinset, const char *msg) +{ + irqstate_t flags; + uint32_t base; + unsigned int port; + + /* Get the base address associated with the GPIO port */ + + port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + base = g_gpiobase[port]; + + /* The following requires exclusive access to the GPIO registers */ + + flags = enter_critical_section(); + +#if defined(CONFIG_AT32_AT32F43XX) + DEBUGASSERT(port < AT32_NGPIO_PORTS); + + _info("GPIO%c pinset: %08x base: %08x -- %s\n", + g_portchar[port], pinset, base, msg); + + if ((getreg32(AT32_CRM_AHBEN1) & CRM_AHB1EN1_GPIOEN(port)) != 0) + { + _info(" MODE: %08x OTYPE: %04x OSPEED: %08x PUPDR: %08x\n", + getreg32(base + AT32_GPIO_CFGR_OFFSET), + getreg32(base + AT32_GPIO_OMODER_OFFSET), + getreg32(base + AT32_GPIO_ODRVR_OFFSET), + getreg32(base + AT32_GPIO_PULL_OFFSET)); + _info(" IDR: %04x ODR: %04x BSRR: %08x LCKR: %04x\n", + getreg32(base + AT32_GPIO_IDT_OFFSET), + getreg32(base + AT32_GPIO_ODT_OFFSET), + getreg32(base + AT32_GPIO_SCR_OFFSET), + getreg32(base + AT32_GPIO_WPR_OFFSET)); + _info(" AFRH: %08x AFRL: %08x\n", + getreg32(base + AT32_GPIO_MUXH_OFFSET), + getreg32(base + AT32_GPIO_MUXL_OFFSET)); + } + else + { + _info(" GPIO%c not enabled: AHB1ENR: %08x\n", + g_portchar[port], getreg32(AT32_CRM_AHBEN1)); + } + +#else +# error "Unsupported AT32 chip" +#endif + leave_critical_section(flags); + return OK; +} + +#endif /* CONFIG_DEBUG_FEATURES */ diff --git a/arch/arm/src/at32/at32_eth.c b/arch/arm/src/at32/at32_eth.c new file mode 100644 index 0000000000..a83816bfec --- /dev/null +++ b/arch/arm/src/at32/at32_eth.c @@ -0,0 +1,4030 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_eth.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_AT32_ETHMAC) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_NET_PKT) +# include +#endif + +#include "arm_internal.h" +#include "chip.h" +#include "at32_gpio.h" +#include "at32_rcc.h" +#include "at32_syscfg.h" +#include "at32_eth.h" +#include "at32_uid.h" + +#include + +/* AT32_NETHERNET determines the number of physical interfaces + * that will be supported. + */ + +#if AT32_NETHERNET > 0 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* See boards/arm/at32/at3240g-eval/README.txt for an explanation of the + * configuration settings. + */ + +#if AT32_NETHERNET > 1 +# error "Logic to support multiple Ethernet interfaces is incomplete" +#endif + +/* Work queue support is required. */ + +#if !defined(CONFIG_SCHED_WORKQUEUE) +# error Work queue support is required +#endif + +/* The low priority work queue is preferred. If it is not enabled, LPWORK + * will be the same as HPWORK. + * + * NOTE: However, the network should NEVER run on the high priority work + * queue! That queue is intended only to service short back end interrupt + * processing that never suspends. Suspending the high priority work queue + * may bring the system to its knees! + */ + +#define ETHWORK LPWORK + +#if !defined(CONFIG_AT32_SYSCFG) && !defined(CONFIG_AT32_CONNECTIVITYLINE) +# error "CONFIG_AT32_SYSCFG must be defined in the NuttX configuration" +#endif + +#ifndef CONFIG_AT32_PHYADDR +# error "CONFIG_AT32_PHYADDR must be defined in the NuttX configuration" +#endif + +#if !defined(CONFIG_AT32_MII) && !defined(CONFIG_AT32_RMII) +# warning "Neither CONFIG_AT32_MII nor CONFIG_AT32_RMII defined" +#endif + +#if defined(CONFIG_AT32_MII) && defined(CONFIG_AT32_RMII) +# error "Both CONFIG_AT32_MII and CONFIG_AT32_RMII defined" +#endif + +#ifdef CONFIG_AT32_MII +# if defined(CONFIG_AT32_AT32F43XX) +# if !defined(CONFIG_AT32_MII_MCO1) && !defined(CONFIG_AT32_MII_MCO2) && !defined(CONFIG_AT32_MII_EXTCLK) +# warning "Neither CONFIG_AT32_MII_MCO1, CONFIG_AT32_MII_MCO2, nor CONFIG_AT32_MII_EXTCLK defined" +# endif +# if defined(CONFIG_AT32_MII_MCO1) && defined(CONFIG_AT32_MII_MCO2) +# error "Both CONFIG_AT32_MII_MCO1 and CONFIG_AT32_MII_MCO2 defined" +# endif +# elif defined(CONFIG_AT32_CONNECTIVITYLINE) +# if !defined(CONFIG_AT32_MII_MCO) && !defined(CONFIG_AT32_MII_EXTCLK) +# warning "Neither CONFIG_AT32_MII_MCO nor CONFIG_AT32_MII_EXTCLK defined" +# endif +# endif +#endif + +#ifdef CONFIG_AT32_RMII +# if defined(CONFIG_AT32_AT32F43XX) +# if !defined(CONFIG_AT32_RMII_MCO1) && !defined(CONFIG_AT32_RMII_MCO2) && !defined(CONFIG_AT32_RMII_EXTCLK) +# warning "Neither CONFIG_AT32_RMII_MCO1, CONFIG_AT32_RMII_MCO2, nor CONFIG_AT32_RMII_EXTCLK defined" +# endif +# if defined(CONFIG_AT32_RMII_MCO1) && defined(CONFIG_AT32_RMII_MCO2) +# error "Both CONFIG_AT32_RMII_MCO1 and CONFIG_AT32_RMII_MCO2 defined" +# endif +# elif defined(CONFIG_AT32_CONNECTIVITYLINE) +# if !defined(CONFIG_AT32_RMII_MCO) && !defined(CONFIG_AT32_RMII_EXTCLK) +# warning "Neither CONFIG_AT32_RMII_MCO nor CONFIG_AT32_RMII_EXTCLK defined" +# endif +# endif +#endif + +#ifdef CONFIG_AT32_AUTONEG +# ifndef CONFIG_AT32_PHYSR +# error "CONFIG_AT32_PHYSR must be defined in the NuttX configuration" +# endif +# ifdef CONFIG_AT32_PHYSR_ALTCONFIG +# ifndef CONFIG_AT32_PHYSR_ALTMODE +# error "CONFIG_AT32_PHYSR_ALTMODE must be defined in the NuttX configuration" +# endif +# ifndef CONFIG_AT32_PHYSR_10HD +# error "CONFIG_AT32_PHYSR_10HD must be defined in the NuttX configuration" +# endif +# ifndef CONFIG_AT32_PHYSR_100HD +# error "CONFIG_AT32_PHYSR_100HD must be defined in the NuttX configuration" +# endif +# ifndef CONFIG_AT32_PHYSR_10FD +# error "CONFIG_AT32_PHYSR_10FD must be defined in the NuttX configuration" +# endif +# ifndef CONFIG_AT32_PHYSR_100FD +# error "CONFIG_AT32_PHYSR_100FD must be defined in the NuttX configuration" +# endif +# else +# ifndef CONFIG_AT32_PHYSR_SPEED +# error "CONFIG_AT32_PHYSR_SPEED must be defined in the NuttX configuration" +# endif +# ifndef CONFIG_AT32_PHYSR_100MBPS +# error "CONFIG_AT32_PHYSR_100MBPS must be defined in the NuttX configuration" +# endif +# ifndef CONFIG_AT32_PHYSR_MODE +# error "CONFIG_AT32_PHYSR_MODE must be defined in the NuttX configuration" +# endif +# ifndef CONFIG_AT32_PHYSR_FULLDUPLEX +# error "CONFIG_AT32_PHYSR_FULLDUPLEX must be defined in the NuttX configuration" +# endif +# endif +#endif + +/* These definitions are used to enable the PHY interrupts */ + +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) +# if defined( CONFIG_ETH0_PHY_AM79C874) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_KS8721) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_KSZ8041) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_KSZ8051) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_KSZ8061) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_KSZ8081) +# define MII_INT_REG MII_KSZ8081_INT +# define MII_INT_SETEN MII_KSZ80X1_INT_LDEN | MII_KSZ80X1_INT_LUEN +# define MII_INT_CLREN 0 +# elif defined( CONFIG_ETH0_PHY_KSZ90x1) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_DP83848C) +# define MII_INT_REG MII_DP83848C_MISR +# define MII_INT_SETEN MII_DP83848C_LINK_INT_EN +# define MII_INT_CLREN 0 +# elif defined( CONFIG_ETH0_PHY_LAN8720) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_LAN8740) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_LAN8740A) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_LAN8742A) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_DM9161) +# error missing logic +# else +# error unknown PHY +# endif +#endif + +#ifdef CONFIG_AT32_ETH_PTP +# warning "CONFIG_AT32_ETH_PTP is not yet supported" +#endif + +/* This driver does not use enhanced descriptors. Enhanced descriptors must + * be used, however, if time stamping or and/or IPv4 checksum offload is + * supported. + */ + +#undef CONFIG_AT32_ETH_ENHANCEDDESC + +#define CONFIG_AT32_ETH_HWCHECKSUM + +/* Add 4 to the configured buffer size to account for the 2 byte checksum + * memory needed at the end of the maximum size packet. Buffer sizes must + * be an even multiple of 4, 8, or 16 bytes (depending on buswidth). We + * will use the 16-byte alignment in all cases. + */ + +#define OPTIMAL_ETH_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 4 + 15) & ~15) + +#ifndef CONFIG_AT32_ETH_BUFSIZE +# define CONFIG_AT32_ETH_BUFSIZE OPTIMAL_ETH_BUFSIZE +#endif + +#if CONFIG_AT32_ETH_BUFSIZE > ETH_TDES1_TBS1_MASK +# error "CONFIG_AT32_ETH_BUFSIZE is too large" +#endif + +#if (CONFIG_AT32_ETH_BUFSIZE & 15) != 0 +# error "CONFIG_AT32_ETH_BUFSIZE must be aligned" +#endif + +#if CONFIG_AT32_ETH_BUFSIZE != OPTIMAL_ETH_BUFSIZE +# warning "You using an incomplete/untested configuration" +#endif + +#ifndef CONFIG_AT32_ETH_NRXDESC +# define CONFIG_AT32_ETH_NRXDESC 8 +#endif +#ifndef CONFIG_AT32_ETH_NTXDESC +# define CONFIG_AT32_ETH_NTXDESC 4 +#endif + +/* We need at least one more free buffer than transmit buffers */ + +#define AT32_ETH_NFREEBUFFERS (CONFIG_AT32_ETH_NTXDESC+1) + +/* Extremely detailed register debug that you would normally never want + * enabled. + */ + +#ifndef CONFIG_DEBUG_NET_INFO +# undef CONFIG_AT32_ETHMAC_REGDEBUG +#endif + +/* Clocking *****************************************************************/ + +/* Set MACMIIAR CR bits depending on HCLK setting */ + +#if AT32_HCLK_FREQUENCY >= 20000000 && AT32_HCLK_FREQUENCY < 35000000 +# define ETH_MACMIIAR_CR ETH_MACMIIAR_CR_20_35 +#elif AT32_HCLK_FREQUENCY >= 35000000 && AT32_HCLK_FREQUENCY < 60000000 +# define ETH_MACMIIAR_CR ETH_MACMIIAR_CR_35_60 +#elif AT32_HCLK_FREQUENCY >= 60000000 && AT32_HCLK_FREQUENCY < 100000000 +# define ETH_MACMIIAR_CR ETH_MACMIIAR_CR_60_100 +#elif AT32_HCLK_FREQUENCY >= 100000000 && AT32_HCLK_FREQUENCY < 150000000 +# define ETH_MACMIIAR_CR ETH_MACMIIAR_CR_100_150 +#elif AT32_HCLK_FREQUENCY >= 150000000 && AT32_HCLK_FREQUENCY < 250000000 +# define ETH_MACMIIAR_CR ETH_MACMIIAR_CR_150_250 +#elif AT32_HCLK_FREQUENCY >= 250000000 && AT32_HCLK_FREQUENCY <= 300000000 +# define ETH_MACMIIAR_CR ETH_MACMIIAR_CR_250_300 +#else +# error "AT32_HCLK_FREQUENCY not supportable" +#endif + +/* Timing *******************************************************************/ + +/* TX timeout = 1 minute */ + +#define AT32_TXTIMEOUT (60*CLK_TCK) + +/* PHY reset/configuration delays in milliseconds */ + +#define PHY_RESET_DELAY (65) +#define PHY_CONFIG_DELAY (1000) + +/* PHY read/write delays in loop counts */ + +#define PHY_READ_TIMEOUT (0x0004ffff) +#define PHY_WRITE_TIMEOUT (0x0004ffff) +#define PHY_RETRY_TIMEOUT (0x0004ffff) + +/* Register values **********************************************************/ + +/* Clear the MACCR bits that will be setup during MAC initialization (or that + * are cleared unconditionally). Per the reference manual, all reserved bits + * must be retained at their reset value. + * + * ETH_MACCR_RE Bit 2: Receiver enable + * ETH_MACCR_TE Bit 3: Transmitter enable + * ETH_MACCR_DC Bit 4: Deferral check + * ETH_MACCR_BL Bits 5-6: Back-off limit + * ETH_MACCR_APCS Bit 7: Automatic pad/CRC stripping + * ETH_MACCR_RD Bit 9: Retry disable + * ETH_MACCR_IPCO Bit 10: IPv4 checksum offload + * ETH_MACCR_DM Bit 11: Duplex mode + * ETH_MACCR_LM Bit 12: Loopback mode + * ETH_MACCR_ROD Bit 13: Receive own disable + * ETH_MACCR_FES Bit 14: Fast Ethernet speed + * ETH_MACCR_CSD Bit 16: Carrier sense disable + * ETH_MACCR_IFG Bits 17-19: Interframe gap + * ETH_MACCR_JD Bit 22: Jabber disable + * ETH_MACCR_WD Bit 23: Watchdog disable + */ + +#define MACCR_CLEAR_BITS \ + (ETH_MACCR_RE | ETH_MACCR_TE | ETH_MACCR_DC | ETH_MACCR_BL_MASK | \ + ETH_MACCR_APCS | ETH_MACCR_RD | ETH_MACCR_IPCO | ETH_MACCR_DM | \ + ETH_MACCR_LM | ETH_MACCR_ROD | ETH_MACCR_FES | ETH_MACCR_CSD | \ + ETH_MACCR_IFG_MASK | ETH_MACCR_JD | ETH_MACCR_WD) + +/* The following bits are set or left zero unconditionally in all modes. + * + * ETH_MACCR_RE Receiver enable 0 (disabled) + * ETH_MACCR_TE Transmitter enable 0 (disabled) + * ETH_MACCR_DC Deferral check 0 (disabled) + * ETH_MACCR_BL Back-off limit 0 (10) + * ETH_MACCR_APCS Automatic pad/CRC stripping 0 (disabled) + * ETH_MACCR_RD Retry disable 1 (disabled) + * ETH_MACCR_IPCO IPv4 checksum offload Depends on + * CONFIG_AT32_ETH_HWCHECKSUM + * ETH_MACCR_LM Loopback mode 0 (disabled) + * ETH_MACCR_ROD Receive own disable 0 (enabled) + * ETH_MACCR_CSD Carrier sense disable 0 (enabled) + * ETH_MACCR_IFG Interframe gap 0 (96 bits) + * ETH_MACCR_JD Jabber disable 0 (enabled) + * ETH_MACCR_WD Watchdog disable 0 (enabled) + * ETH_MACCR_CSTF CRC stripping for Type frames 0 (disabled, F4 only) + * + * The following are set conditioinally based on mode and speed. + * + * ETH_MACCR_DM Duplex mode Depends on priv->fduplex + * ETH_MACCR_FES Fast Ethernet speed Depends on priv->mbps100 + */ + +#ifdef CONFIG_AT32_ETH_HWCHECKSUM +# define MACCR_SET_BITS \ + (ETH_MACCR_BL_10 | ETH_MACCR_RD | ETH_MACCR_IPCO | ETH_MACCR_IFG(96)) +#else +# define MACCR_SET_BITS \ + (ETH_MACCR_BL_10 | ETH_MACCR_RD | ETH_MACCR_IFG(96)) +#endif + +/* Clear the MACCR bits that will be setup during MAC initialization (or that + * are cleared unconditionally). Per the reference manual, all reserved bits + * must be retained at their reset value. + * + * ETH_MACFFR_PM Bit 0: Promiscuous mode + * ETH_MACFFR_HU Bit 1: Hash unicast + * ETH_MACFFR_HM Bit 2: Hash multicast + * ETH_MACFFR_DAIF Bit 3: Destination address inverse filtering + * ETH_MACFFR_PAM Bit 4: Pass all multicast + * ETH_MACFFR_BFD Bit 5: Broadcast frames disable + * ETH_MACFFR_PCF Bits 6-7: Pass control frames + * ETH_MACFFR_SAIF Bit 8: Source address inverse filtering + * ETH_MACFFR_SAF Bit 9: Source address filter + * ETH_MACFFR_HPF Bit 10: Hash or perfect filter + * ETH_MACFFR_RA Bit 31: Receive all + */ + +#define MACFFR_CLEAR_BITS \ + (ETH_MACFFR_PM | ETH_MACFFR_HU | ETH_MACFFR_HM | ETH_MACFFR_DAIF | \ + ETH_MACFFR_PAM | ETH_MACFFR_BFD | ETH_MACFFR_PCF_MASK | ETH_MACFFR_SAIF | \ + ETH_MACFFR_SAF | ETH_MACFFR_HPF | ETH_MACFFR_RA) + +/* The following bits are set or left zero unconditionally in all modes. + * + * ETH_MACFFR_HU Hash unicast 0 (perfect dest filtering) + * ETH_MACFFR_HM Hash multicast 0 (perfect dest filtering) + * ETH_MACFFR_DAIF Destination address 0 (normal) + * inverse filtering + * ETH_MACFFR_PAM Pass all multicast 0 (Depends on HM bit) + * ETH_MACFFR_BFD Broadcast frames disable 0 (enabled) + * ETH_MACFFR_PCF Pass control frames 1 (block all but PAUSE) + * ETH_MACFFR_SAIF Source address inverse 0 (not used) + * filtering + * ETH_MACFFR_SAF Source address filter 0 (disabled) + * ETH_MACFFR_HPF Hash or perfect filter 0 (Only matching frames passed) + * ETH_MACFFR_RA Receive all 0 (disabled) + */ + +#ifdef CONFIG_NET_PROMISCUOUS +# define MACFFR_SET_BITS (ETH_MACFFR_PCF_PAUSE | ETH_MACFFR_PM) +#else +# define MACFFR_SET_BITS (ETH_MACFFR_PCF_PAUSE) +#endif + +/* Clear the MACFCR bits that will be setup during MAC initialization (or + * that are cleared unconditionally). Per the reference manual, all reserved + * bits must be retained at their reset value. + * + * ETH_MACFCR_FCB_BPA Bit 0: Flow control busy/back pressure activate + * ETH_MACFCR_TFCE Bit 1: Transmit flow control enable + * ETH_MACFCR_RFCE Bit 2: Receive flow control enable + * ETH_MACFCR_UPFD Bit 3: Unicast pause frame detect + * ETH_MACFCR_PLT Bits 4-5: Pause low threshold + * ETH_MACFCR_ZQPD Bit 7: Zero-quanta pause disable + * ETH_MACFCR_PT Bits 16-31: Pause time + */ + +#define MACFCR_CLEAR_MASK \ + (ETH_MACFCR_FCB_BPA | ETH_MACFCR_TFCE | ETH_MACFCR_RFCE | ETH_MACFCR_UPFD | \ + ETH_MACFCR_PLT_MASK | ETH_MACFCR_ZQPD | ETH_MACFCR_PT_MASK) + +/* The following bits are set or left zero unconditionally in all modes. + * + * ETH_MACFCR_FCB_BPA Flow control busy/back 0 (no pause control frame) + * activate pressure + * ETH_MACFCR_TFCE Transmit flow control enable 0 (disabled) + * ETH_MACFCR_RFCE Receive flow control enable 0 (disabled) + * ETH_MACFCR_UPFD Unicast pause frame detect 0 (disabled) + * ETH_MACFCR_PLT Pause low threshold 0 (pause time - 4) + * ETH_MACFCR_ZQPD Zero-quanta pause disable 1 (disabled) + * ETH_MACFCR_PT Pause time 0 + */ + +#define MACFCR_SET_MASK (ETH_MACFCR_PLT_M4 | ETH_MACFCR_ZQPD) + +/* Clear the DMAOMR bits that will be setup during MAC initialization (or + * that are cleared unconditionally). Per the reference manual, all reserved + * bits must be retained at their reset value. + * + * ETH_DMAOMR_SR Bit 1: Start/stop receive + * TH_DMAOMR_OSF Bit 2: Operate on second frame + * ETH_DMAOMR_RTC Bits 3-4: Receive threshold control + * ETH_DMAOMR_FUGF Bit 6: Forward undersized good frames + * ETH_DMAOMR_FEF Bit 7: Forward error frames + * ETH_DMAOMR_ST Bit 13: Start/stop transmission + * ETH_DMAOMR_TTC Bits 14-16: Transmit threshold control + * ETH_DMAOMR_FTF Bit 20: Flush transmit FIFO + * ETH_DMAOMR_TSF Bit 21: Transmit store and forward + * ETH_DMAOMR_DFRF Bit 24: Disable flushing of received frames + * ETH_DMAOMR_RSF Bit 25: Receive store and forward + * TH_DMAOMR_DTCEFD Bit 26: Dropping of TCP/IP checksum error frames disable + */ + +#define DMAOMR_CLEAR_MASK \ + (ETH_DMAOMR_SR | ETH_DMAOMR_OSF | ETH_DMAOMR_RTC_MASK | ETH_DMAOMR_FUGF | \ + ETH_DMAOMR_FEF | ETH_DMAOMR_ST | ETH_DMAOMR_TTC_MASK | ETH_DMAOMR_FTF | \ + ETH_DMAOMR_TSF | ETH_DMAOMR_DFRF | ETH_DMAOMR_RSF | ETH_DMAOMR_DTCEFD) + +/* The following bits are set or left zero unconditionally in all modes. + * + * ETH_DMAOMR_SR Start/stop receive 0 (not running) + * TH_DMAOMR_OSF Operate on second frame 1 (enabled) + * ETH_DMAOMR_RTC Receive threshold control 0 (64 bytes) + * ETH_DMAOMR_FUGF Forward undersized good 0 (disabled) + * frames + * ETH_DMAOMR_FEF Forward error frames 0 (disabled) + * ETH_DMAOMR_ST Start/stop transmission 0 (not running) + * ETH_DMAOMR_TTC Transmit threshold control 0 (64 bytes) + * ETH_DMAOMR_FTF Flush transmit FIFO 0 (no flush) + * ETH_DMAOMR_TSF Transmit store and forward 1 (enabled) + * ETH_DMAOMR_DFRF Disable flushing of received 0 (enabled) + * frames + * ETH_DMAOMR_RSF Receive store and forward 1 (enabled) + * TH_DMAOMR_DTCEFD Dropping of TCP/IP checksum Depends on + * error frames disable CONFIG_AT32_ETH_HWCHECKSUM + * + * When the checksum offload feature is enabled, we need to enable the Store + * and Forward mode: the store and forward guarantee that a whole frame is + * stored in the FIFO, so the MAC can insert/verify the checksum, if the + * checksum is OK the DMA can handle the frame otherwise the frame is dropped + */ + +#ifdef CONFIG_AT32_ETH_HWCHECKSUM +# define DMAOMR_SET_MASK \ + (ETH_DMAOMR_OSF | ETH_DMAOMR_RTC_64 | ETH_DMAOMR_TTC_64 | \ + ETH_DMAOMR_TSF | ETH_DMAOMR_RSF) +#else +# define DMAOMR_SET_MASK \ + (ETH_DMAOMR_OSF | ETH_DMAOMR_RTC_64 | ETH_DMAOMR_TTC_64 | \ + ETH_DMAOMR_TSF | ETH_DMAOMR_RSF | ETH_DMAOMR_DTCEFD) +#endif + +/* Clear the DMABMR bits that will be setup during MAC initialization (or + * that are cleared unconditionally). Per the reference manual, all reserved + * bits must be retained at their reset value. + * + * ETH_DMABMR_SR Bit 0: Software reset + * ETH_DMABMR_DA Bit 1: DMA Arbitration + * ETH_DMABMR_DSL Bits 2-6: Descriptor skip length + * ETH_DMABMR_PBL Bits 8-13: Programmable burst length + * ETH_DMABMR_RTPR Bits 14-15: RX TX priority ratio + * ETH_DMABMR_FB Bit 16: Fixed burst + * ETH_DMABMR_RDP Bits 17-22: RX DMA PBL + * ETH_DMABMR_USP Bit 23: Use separate PBL + * ETH_DMABMR_FPM Bit 24: 8xPBL mode + * ETH_DMABMR_AAB Bit 25: Address-aligned beats + */ + +#define DMABMR_CLEAR_MASK \ + (ETH_DMABMR_SR | ETH_DMABMR_DA | ETH_DMABMR_DSL_MASK | \ + ETH_DMABMR_PBL_MASK | ETH_DMABMR_RTPR_MASK | ETH_DMABMR_FB | ETH_DMABMR_RDP_MASK | \ + ETH_DMABMR_USP | ETH_DMABMR_FPM | ETH_DMABMR_AAB) + +/* The following bits are set or left zero unconditionally in all modes. + * + * + * ETH_DMABMR_SR Software reset 0 (no reset) + * ETH_DMABMR_DA DMA Arbitration 0 (round robin) + * ETH_DMABMR_DSL Descriptor skip length 0 + * ETH_DMABMR_PBL Programmable burst length 32 beats + * ETH_DMABMR_RTPR RX TX priority ratio 2:1 + * ETH_DMABMR_FB Fixed burst 1 (enabled) + * ETH_DMABMR_RDP RX DMA PBL 32 beats + * ETH_DMABMR_USP Use separate PBL 1 (enabled) + * ETH_DMABMR_FPM 8xPBL mode 0 (disabled) + * ETH_DMABMR_AAB Address-aligned beats 1 (enabled) + * ETH_DMABMR_MB Mixed burst 0 (disabled, F4 only) + */ + +#define DMABMR_SET_MASK \ + (ETH_DMABMR_DSL(0) | ETH_DMABMR_PBL(32) | ETH_DMABMR_RTPR_2TO1 | ETH_DMABMR_FB | \ + ETH_DMABMR_RDP(32) | ETH_DMABMR_USP | ETH_DMABMR_AAB) + +/* Interrupt bit sets *******************************************************/ + +/* All interrupts in the normal and abnormal interrupt summary. Early + * transmit interrupt (ETI) is excluded from the abnormal set because it + * causes too many interrupts and is not interesting. + */ + +#define ETH_DMAINT_NORMAL \ + (ETH_DMAINT_TI | ETH_DMAINT_TBUI | ETH_DMAINT_RI | ETH_DMAINT_ERI) + +#define ETH_DMAINT_ABNORMAL \ + (ETH_DMAINT_TPSI | ETH_DMAINT_TJTI | ETH_DMAINT_ROI | ETH_DMAINT_TUI | \ + ETH_DMAINT_RBUI | ETH_DMAINT_RPSI | ETH_DMAINT_RWTI | /* ETH_DMAINT_ETI | */ \ + ETH_DMAINT_FBEI) + +/* Normal receive, transmit, error interrupt enable bit sets */ + +#define ETH_DMAINT_RECV_ENABLE (ETH_DMAINT_NIS | ETH_DMAINT_RI) +#define ETH_DMAINT_XMIT_ENABLE (ETH_DMAINT_NIS | ETH_DMAINT_TI) +#define ETH_DMAINT_XMIT_DISABLE (ETH_DMAINT_TI) + +#ifdef CONFIG_DEBUG_NET +# define ETH_DMAINT_ERROR_ENABLE (ETH_DMAINT_AIS | ETH_DMAINT_ABNORMAL) +#else +# define ETH_DMAINT_ERROR_ENABLE (0) +#endif + +/* Helpers ******************************************************************/ + +/* This is a helper pointer for accessing the contents of the Ethernet + * header + */ + +#define BUF ((struct eth_hdr_s *)priv->dev.d_buf) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The at32_ethmac_s encapsulates all state information for a single + * hardware interface + */ + +struct at32_ethmac_s +{ + uint8_t ifup : 1; /* true:ifup false:ifdown */ + uint8_t mbps100 : 1; /* 100MBps operation (vs 10 MBps) */ + uint8_t fduplex : 1; /* Full (vs. half) duplex */ + struct wdog_s txtimeout; /* TX timeout timer */ + struct work_s irqwork; /* For deferring interrupt work to the work queue */ + struct work_s pollwork; /* For deferring poll work to the work queue */ + + /* This holds the information visible to the NuttX network */ + + struct net_driver_s dev; /* Interface understood by the network */ + + /* Used to track transmit and receive descriptors */ + + struct eth_txdesc_s *txhead; /* Next available TX descriptor */ + struct eth_rxdesc_s *rxhead; /* Next available RX descriptor */ + + struct eth_txdesc_s *txtail; /* First "in_flight" TX descriptor */ + struct eth_rxdesc_s *rxcurr; /* First RX descriptor of the segment */ + uint16_t segments; /* RX segment count */ + uint16_t inflight; /* Number of TX transfers "in_flight" */ + sq_queue_t freeb; /* The free buffer list */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Descriptor allocations */ + +static struct eth_rxdesc_s g_rxtable[CONFIG_AT32_ETH_NRXDESC] + aligned_data(4); +static struct eth_txdesc_s g_txtable[CONFIG_AT32_ETH_NTXDESC] + aligned_data(4); + +/* Buffer allocations */ + +static uint8_t g_rxbuffer[CONFIG_AT32_ETH_NRXDESC * + CONFIG_AT32_ETH_BUFSIZE] aligned_data(4); +static uint8_t g_alloc[AT32_ETH_NFREEBUFFERS * + CONFIG_AT32_ETH_BUFSIZE] aligned_data(4); + +static struct at32_ethmac_s g_at32ethmac[AT32_NETHERNET]; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register operations ******************************************************/ + +#if defined(CONFIG_AT32_ETHMAC_REGDEBUG) && defined(CONFIG_DEBUG_FEATURES) +static uint32_t at32_getreg(uint32_t addr); +static void at32_putreg(uint32_t val, uint32_t addr); +static void at32_checksetup(void); +#else +# define at32_getreg(addr) getreg32(addr) +# define at32_putreg(val,addr) putreg32(val,addr) +# define at32_checksetup() +#endif + +/* Free buffer management */ + +static void at32_initbuffer(struct at32_ethmac_s *priv, uint8_t *alloc); +static inline uint8_t *at32_allocbuffer(struct at32_ethmac_s *priv); +static inline void at32_freebuffer(struct at32_ethmac_s *priv, + uint8_t *buffer); +static inline bool at32_isfreebuffer(struct at32_ethmac_s *priv); + +/* Common TX logic */ + +static int at32_transmit(struct at32_ethmac_s *priv); +static int at32_txpoll(struct net_driver_s *dev); +static void at32_dopoll(struct at32_ethmac_s *priv); + +/* Interrupt handling */ + +static void at32_enableint(struct at32_ethmac_s *priv, + uint32_t ierbit); +static void at32_disableint(struct at32_ethmac_s *priv, + uint32_t ierbit); + +static void at32_freesegment(struct at32_ethmac_s *priv, + struct eth_rxdesc_s *rxfirst, int segments); +static int at32_recvframe(struct at32_ethmac_s *priv); +static void at32_receive(struct at32_ethmac_s *priv); +static void at32_freeframe(struct at32_ethmac_s *priv); +static void at32_txdone(struct at32_ethmac_s *priv); + +static void at32_interrupt_work(void *arg); +static int at32_interrupt(int irq, void *context, void *arg); + +/* Watchdog timer expirations */ + +static void at32_txtimeout_work(void *arg); +static void at32_txtimeout_expiry(wdparm_t arg); + +/* NuttX callback functions */ + +static int at32_ifup(struct net_driver_s *dev); +static int at32_ifdown(struct net_driver_s *dev); + +static void at32_txavail_work(void *arg); +static int at32_txavail(struct net_driver_s *dev); + +#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6) +static int at32_addmac(struct net_driver_s *dev, const uint8_t *mac); +#endif +#ifdef CONFIG_NET_MCASTGROUP +static int at32_rmmac(struct net_driver_s *dev, const uint8_t *mac); +#endif +#ifdef CONFIG_NETDEV_IOCTL +static int at32_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg); +#endif + +/* Descriptor Initialization */ + +static void at32_txdescinit(struct at32_ethmac_s *priv, + struct eth_txdesc_s *txtable); +static void at32_rxdescinit(struct at32_ethmac_s *priv, + struct eth_rxdesc_s *rxtable, + uint8_t *rxbuffer); + +/* PHY Initialization */ + +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) +static int at32_phyintenable(struct at32_ethmac_s *priv); +#endif +#if defined(CONFIG_AT32_AUTONEG) || defined(CONFIG_NETDEV_PHY_IOCTL) || \ + defined(CONFIG_ETH0_PHY_DM9161) +static int at32_phyread(uint16_t phydevaddr, uint16_t phyregaddr, + uint16_t *value); +#endif +static int at32_phywrite(uint16_t phydevaddr, uint16_t phyregaddr, + uint16_t value); +#ifdef CONFIG_ETH0_PHY_DM9161 +static inline int at32_dm9161(struct at32_ethmac_s *priv); +#endif +static int at32_phyinit(struct at32_ethmac_s *priv); + +/* MAC/DMA Initialization */ + +#ifdef CONFIG_AT32_MII +static inline void at32_selectmii(void); +#endif +#ifdef CONFIG_AT32_RMII +static inline void at32_selectrmii(void); +#endif +static inline void at32_ethgpioconfig(struct at32_ethmac_s *priv); +static int at32_ethreset(struct at32_ethmac_s *priv); +static int at32_macconfig(struct at32_ethmac_s *priv); +static void at32_macaddress(struct at32_ethmac_s *priv); +#ifdef CONFIG_NET_ICMPv6 +static void at32_ipv6multicast(struct at32_ethmac_s *priv); +#endif +static int at32_macenable(struct at32_ethmac_s *priv); +static int at32_ethconfig(struct at32_ethmac_s *priv); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_getreg + * + * Description: + * This function may to used to intercept an monitor all register accesses. + * Clearly this is nothing you would want to do unless you are debugging + * this driver. + * + * Input Parameters: + * addr - The register address to read + * + * Returned Value: + * The value read from the register + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_ETHMAC_REGDEBUG +static uint32_t at32_getreg(uint32_t addr) +{ + static uint32_t prevaddr = 0; + static uint32_t preval = 0; + static uint32_t count = 0; + + /* Read the value from the register */ + + uint32_t val = getreg32(addr); + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (addr == prevaddr && val == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + ninfo("...\n"); + } + + return val; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + ninfo("[repeats %d more times]\n", count - 3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + preval = val; + count = 1; + } + + /* Show the register value read */ + + ninfo("%08x->%08x\n", addr, val); + return val; +} +#endif + +/**************************************************************************** + * Name: at32_putreg + * + * Description: + * This function may to used to intercept an monitor all register accesses. + * Clearly this is nothing you would want to do unless you are debugging + * this driver. + * + * Input Parameters: + * val - The value to write to the register + * addr - The register address to read + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_AT32_ETHMAC_REGDEBUG) && defined(CONFIG_DEBUG_FEATURES) +static void at32_putreg(uint32_t val, uint32_t addr) +{ + /* Show the register value being written */ + + ninfo("%08x<-%08x\n", addr, val); + + /* Write the value */ + + putreg32(val, addr); +} +#endif + +/**************************************************************************** + * Name: at32_checksetup + * + * Description: + * Show the state of critical configuration registers. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_ETHMAC_REGDEBUG +static void at32_checksetup(void) +{ +} +#endif + +/**************************************************************************** + * Function: at32_initbuffer + * + * Description: + * Initialize the free buffer list. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called during early driver initialization before Ethernet interrupts + * are enabled. + * + ****************************************************************************/ + +static void at32_initbuffer(struct at32_ethmac_s *priv, uint8_t *alloc) +{ + uint8_t *buffer; + int i; + + /* Initialize the head of the free buffer list */ + + sq_init(&priv->freeb); + + /* Add all of the pre-allocated buffers to the free buffer list */ + + for (i = 0, buffer = alloc; + i < AT32_ETH_NFREEBUFFERS; + i++, buffer += CONFIG_AT32_ETH_BUFSIZE) + { + sq_addlast((sq_entry_t *)buffer, &priv->freeb); + } +} + +/**************************************************************************** + * Function: at32_allocbuffer + * + * Description: + * Allocate one buffer from the free buffer list. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * Pointer to the allocated buffer on success; NULL on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static inline uint8_t *at32_allocbuffer(struct at32_ethmac_s *priv) +{ + /* Allocate a buffer by returning the head of the free buffer list */ + + return (uint8_t *)sq_remfirst(&priv->freeb); +} + +/**************************************************************************** + * Function: at32_freebuffer + * + * Description: + * Return a buffer to the free buffer list. + * + * Input Parameters: + * priv - Reference to the driver state structure + * buffer - A pointer to the buffer to be freed + * + * Returned Value: + * None + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static inline void at32_freebuffer(struct at32_ethmac_s *priv, + uint8_t *buffer) +{ + /* Free the buffer by adding it to the end of the free buffer list */ + + sq_addlast((sq_entry_t *)buffer, &priv->freeb); +} + +/**************************************************************************** + * Function: at32_isfreebuffer + * + * Description: + * Return TRUE if the free buffer list is not empty. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * True if there are one or more buffers in the free buffer list; + * false if the free buffer list is empty + * + * Assumptions: + * None. + * + ****************************************************************************/ + +static inline bool at32_isfreebuffer(struct at32_ethmac_s *priv) +{ + /* Return TRUE if the free buffer list is not empty */ + + return !sq_empty(&priv->freeb); +} + +/**************************************************************************** + * Function: at32_transmit + * + * Description: + * Start hardware transmission. Called either from the txdone interrupt + * handling or from watchdog based polling. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int at32_transmit(struct at32_ethmac_s *priv) +{ + struct eth_txdesc_s *txdesc; + struct eth_txdesc_s *txfirst; + + /* The internal (optimal) network buffer size may be configured to be + * larger than the Ethernet buffer size. + */ + +#if OPTIMAL_ETH_BUFSIZE > CONFIG_AT32_ETH_BUFSIZE + uint8_t *buffer; + int bufcount; + int lastsize; + int i; +#endif + + /* Verify that the hardware is ready to send another packet. If we get + * here, then we are committed to sending a packet; Higher level logic + * must have assured that there is no transmission in progress. + */ + + txdesc = priv->txhead; + txfirst = txdesc; + + ninfo("d_len: %d d_buf: %p txhead: %p tdes0: %08" PRIx32 "\n", + priv->dev.d_len, priv->dev.d_buf, txdesc, txdesc->tdes0); + + DEBUGASSERT(txdesc && (txdesc->tdes0 & ETH_TDES0_OWN) == 0); + + /* Is the size to be sent greater than the size of the Ethernet buffer? */ + + DEBUGASSERT(priv->dev.d_len > 0 && priv->dev.d_buf != NULL); + +#if OPTIMAL_ETH_BUFSIZE > CONFIG_AT32_ETH_BUFSIZE + if (priv->dev.d_len > CONFIG_AT32_ETH_BUFSIZE) + { + /* Yes... how many buffers will be need to send the packet? */ + + bufcount = (priv->dev.d_len + (CONFIG_AT32_ETH_BUFSIZE - 1)) / + CONFIG_AT32_ETH_BUFSIZE; + lastsize = priv->dev.d_len - (bufcount - 1) * CONFIG_AT32_ETH_BUFSIZE; + + ninfo("bufcount: %d lastsize: %d\n", bufcount, lastsize); + + /* Set the first segment bit in the first TX descriptor */ + + txdesc->tdes0 |= ETH_TDES0_FS; + + /* Set up all but the last TX descriptor */ + + buffer = priv->dev.d_buf; + + for (i = 0; i < bufcount; i++) + { + /* This could be a normal event but the design does not handle it */ + + DEBUGASSERT((txdesc->tdes0 & ETH_TDES0_OWN) == 0); + + /* Set the Buffer1 address pointer */ + + txdesc->tdes2 = (uint32_t)buffer; + + /* Set the buffer size in all TX descriptors */ + + if (i == (bufcount - 1)) + { + /* This is the last segment. Set the last segment bit in the + * last TX descriptor and ask for an interrupt when this + * segment transfer completes. + */ + + txdesc->tdes0 |= (ETH_TDES0_LS | ETH_TDES0_IC); + + /* This segment is, most likely, of fractional buffersize */ + + txdesc->tdes1 = lastsize; + buffer += lastsize; + } + else + { + /* This is not the last segment. We don't want an interrupt + * when this segment transfer completes. + */ + + txdesc->tdes0 &= ~ETH_TDES0_IC; + + /* The size of the transfer is the whole buffer */ + + txdesc->tdes1 = CONFIG_AT32_ETH_BUFSIZE; + buffer += CONFIG_AT32_ETH_BUFSIZE; + } + + /* Give the descriptor to DMA */ + + txdesc->tdes0 |= ETH_TDES0_OWN; + txdesc = (struct eth_txdesc_s *)txdesc->tdes3; + } + } + else +#endif + { + /* The single descriptor is both the first and last segment. And we do + * want an interrupt when the transfer completes. + */ + + txdesc->tdes0 |= (ETH_TDES0_FS | ETH_TDES0_LS | ETH_TDES0_IC); + + /* Set frame size */ + + DEBUGASSERT(priv->dev.d_len <= CONFIG_AT32_ETH_BUFSIZE); + txdesc->tdes1 = priv->dev.d_len; + + /* Set the Buffer1 address pointer */ + + txdesc->tdes2 = (uint32_t)priv->dev.d_buf; + + /* Set OWN bit of the TX descriptor tdes0. This gives the buffer to + * Ethernet DMA + */ + + txdesc->tdes0 |= ETH_TDES0_OWN; + + /* Point to the next available TX descriptor */ + + txdesc = (struct eth_txdesc_s *)txdesc->tdes3; + } + + /* Remember where we left off in the TX descriptor chain */ + + priv->txhead = txdesc; + + /* Detach the buffer from priv->dev structure. That buffer is now + * "in-flight". + */ + + priv->dev.d_buf = NULL; + priv->dev.d_len = 0; + + /* If there is no other TX buffer, in flight, then remember the location + * of the TX descriptor. This is the location to check for TX done events. + */ + + if (!priv->txtail) + { + DEBUGASSERT(priv->inflight == 0); + priv->txtail = txfirst; + } + + /* Increment the number of TX transfer in-flight */ + + priv->inflight++; + + ninfo("txhead: %p txtail: %p inflight: %d\n", + priv->txhead, priv->txtail, priv->inflight); + + /* If all TX descriptors are in-flight, then we have to disable receive + * interrupts too. This is because receive events can trigger more + * un-stoppable transmit events. + */ + + if (priv->inflight >= CONFIG_AT32_ETH_NTXDESC) + { + at32_disableint(priv, ETH_DMAINT_RI); + } + + /* Check if the TX Buffer unavailable flag is set */ + + if ((at32_getreg(AT32_ETH_DMASR) & ETH_DMAINT_TBUI) != 0) + { + /* Clear TX Buffer unavailable flag */ + + at32_putreg(ETH_DMAINT_TBUI, AT32_ETH_DMASR); + + /* Resume DMA transmission */ + + at32_putreg(0, AT32_ETH_DMATPDR); + } + + /* Enable TX interrupts */ + + at32_enableint(priv, ETH_DMAINT_TI); + + /* Setup the TX timeout watchdog (perhaps restarting the timer) */ + + wd_start(&priv->txtimeout, AT32_TXTIMEOUT, + at32_txtimeout_expiry, (wdparm_t)priv); + return OK; +} + +/**************************************************************************** + * Function: at32_txpoll + * + * Description: + * The transmitter is available, check if the network has any outgoing + * packets ready to send. This is a callback from devif_poll(). + * devif_poll() may be called: + * + * 1. When the preceding TX packet send is complete, + * 2. When the preceding TX packet send timesout and the interface is reset + * 3. During normal TX polling + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int at32_txpoll(struct net_driver_s *dev) +{ + struct at32_ethmac_s *priv = + (struct at32_ethmac_s *)dev->d_private; + + DEBUGASSERT(priv->dev.d_buf != NULL); + + /* Send the packet */ + + at32_transmit(priv); + DEBUGASSERT(dev->d_len == 0 && dev->d_buf == NULL); + + /* Check if the next TX descriptor is owned by the Ethernet DMA or + * CPU. We cannot perform the TX poll if we are unable to accept + * another packet for transmission. + * + * In a race condition, ETH_TDES0_OWN may be cleared BUT still + * not available because at32_freeframe() has not yet run. If + * at32_freeframe() has run, the buffer1 pointer (tdes2) will be + * nullified (and inflight should be < CONFIG_AT32_ETH_NTXDESC). + */ + + if ((priv->txhead->tdes0 & ETH_TDES0_OWN) != 0 || + priv->txhead->tdes2 != 0) + { + /* We have to terminate the poll if we have no more descriptors + * available for another transfer. + */ + + return -EBUSY; + } + + /* We have the descriptor, we can continue the poll. Allocate a new + * buffer for the poll. + */ + + dev->d_buf = at32_allocbuffer(priv); + + /* We can't continue the poll if we have no buffers */ + + if (dev->d_buf == NULL) + { + /* Terminate the poll. */ + + return -ENOMEM; + } + + /* If zero is returned, the polling will continue until all connections + * have been examined. + */ + + return 0; +} + +/**************************************************************************** + * Function: at32_dopoll + * + * Description: + * The function is called in order to perform an out-of-sequence TX poll. + * This is done: + * + * 1. After completion of a transmission (at32_txdone), + * 2. When new TX data is available (at32_txavail_process), and + * 3. After a TX timeout to restart the sending process + * (at32_txtimeout_process). + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static void at32_dopoll(struct at32_ethmac_s *priv) +{ + struct net_driver_s *dev = &priv->dev; + + /* Check if the next TX descriptor is owned by the Ethernet DMA or + * CPU. We cannot perform the TX poll if we are unable to accept + * another packet for transmission. + * + * In a race condition, ETH_TDES0_OWN may be cleared BUT still + * not available because at32_freeframe() has not yet run. If + * at32_freeframe() has run, the buffer1 pointer (tdes2) will be + * nullified (and inflight should be < CONFIG_AT32_ETH_NTXDESC). + */ + + if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0 && + priv->txhead->tdes2 == 0) + { + /* If we have the descriptor, then poll the network for new XMIT data. + * Allocate a buffer for the poll. + */ + + DEBUGASSERT(dev->d_len == 0 && dev->d_buf == NULL); + dev->d_buf = at32_allocbuffer(priv); + + /* We can't poll if we have no buffers */ + + if (dev->d_buf) + { + devif_poll(dev, at32_txpoll); + + /* We will, most likely end up with a buffer to be freed. But it + * might not be the same one that we allocated above. + */ + + if (dev->d_buf) + { + DEBUGASSERT(dev->d_len == 0); + at32_freebuffer(priv, dev->d_buf); + dev->d_buf = NULL; + } + } + } +} + +/**************************************************************************** + * Function: at32_enableint + * + * Description: + * Enable a "normal" interrupt + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static void at32_enableint(struct at32_ethmac_s *priv, + uint32_t ierbit) +{ + uint32_t regval; + + /* Enable the specified "normal" interrupt */ + + regval = at32_getreg(AT32_ETH_DMAIER); + regval |= (ETH_DMAINT_NIS | ierbit); + at32_putreg(regval, AT32_ETH_DMAIER); +} + +/**************************************************************************** + * Function: at32_disableint + * + * Description: + * Disable a normal interrupt. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static void at32_disableint(struct at32_ethmac_s *priv, + uint32_t ierbit) +{ + uint32_t regval; + + /* Disable the "normal" interrupt */ + + regval = at32_getreg(AT32_ETH_DMAIER); + regval &= ~ierbit; + + /* Are all "normal" interrupts now disabled? */ + + if ((regval & ETH_DMAINT_NORMAL) == 0) + { + /* Yes.. disable normal interrupts */ + + regval &= ~ETH_DMAINT_NIS; + } + + at32_putreg(regval, AT32_ETH_DMAIER); +} + +/**************************************************************************** + * Function: at32_freesegment + * + * Description: + * The function is called when a frame is received using the DMA receive + * interrupt. It scans the RX descriptors to the received frame. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static void at32_freesegment(struct at32_ethmac_s *priv, + struct eth_rxdesc_s *rxfirst, int segments) +{ + struct eth_rxdesc_s *rxdesc; + int i; + + ninfo("rxfirst: %p segments: %d\n", rxfirst, segments); + + /* Set OWN bit in RX descriptors. This gives the buffers back to DMA */ + + rxdesc = rxfirst; + for (i = 0; i < segments; i++) + { + rxdesc->rdes0 = ETH_RDES0_OWN; + rxdesc = (struct eth_rxdesc_s *)rxdesc->rdes3; + } + + /* Reset the segment management logic */ + + priv->rxcurr = NULL; + priv->segments = 0; + + /* Check if the RX Buffer unavailable flag is set */ + + if ((at32_getreg(AT32_ETH_DMASR) & ETH_DMAINT_RBUI) != 0) + { + /* Clear RBUS Ethernet DMA flag */ + + at32_putreg(ETH_DMAINT_RBUI, AT32_ETH_DMASR); + + /* Resume DMA reception */ + + at32_putreg(0, AT32_ETH_DMARPDR); + } +} + +/**************************************************************************** + * Function: at32_recvframe + * + * Description: + * The function is called when a frame is received using the DMA receive + * interrupt. It scans the RX descriptors of the received frame. + * + * NOTE: This function will silently discard any packets containing errors. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * OK if a packet was successfully returned; -EAGAIN if there are no + * further packets available + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static int at32_recvframe(struct at32_ethmac_s *priv) +{ + struct eth_rxdesc_s *rxdesc; + struct eth_rxdesc_s *rxcurr; + uint8_t *buffer; + int i; + + ninfo("rxhead: %p rxcurr: %p segments: %d\n", + priv->rxhead, priv->rxcurr, priv->segments); + + /* Check if there are free buffers. We cannot receive new frames in this + * design unless there is at least one free buffer. + */ + + if (!at32_isfreebuffer(priv)) + { + nerr("ERROR: No free buffers\n"); + return -ENOMEM; + } + + /* Scan descriptors owned by the CPU. Scan until: + * + * 1) We find a descriptor still owned by the DMA, + * 2) We have examined all of the RX descriptors, or + * 3) All of the TX descriptors are in flight. + * + * This last case is obscure. It is due to that fact that each packet + * that we receive can generate an unstoppable transmisson. So we have + * to stop receiving when we can not longer transmit. In this case, the + * transmit logic should also have disabled further RX interrupts. + */ + + rxdesc = priv->rxhead; + for (i = 0; + (rxdesc->rdes0 & ETH_RDES0_OWN) == 0 && + i < CONFIG_AT32_ETH_NRXDESC && + priv->inflight < CONFIG_AT32_ETH_NTXDESC; + i++) + { + /* Check if this is the first segment in the frame */ + + if ((rxdesc->rdes0 & ETH_RDES0_FS) != 0 && + (rxdesc->rdes0 & ETH_RDES0_LS) == 0) + { + priv->rxcurr = rxdesc; + priv->segments = 1; + } + + /* Check if this is an intermediate segment in the frame */ + + else if (((rxdesc->rdes0 & ETH_RDES0_LS) == 0) && + ((rxdesc->rdes0 & ETH_RDES0_FS) == 0)) + { + priv->segments++; + } + + /* Otherwise, it is the last segment in the frame */ + + else + { + priv->segments++; + + /* Check if there is only one segment in the frame */ + + if (priv->segments == 1) + { + rxcurr = rxdesc; + } + else + { + rxcurr = priv->rxcurr; + } + + ninfo("rxhead: %p rxcurr: %p segments: %d\n", + priv->rxhead, priv->rxcurr, priv->segments); + + /* Check if any errors are reported in the frame */ + + if ((rxdesc->rdes0 & ETH_RDES0_ES) == 0) + { + struct net_driver_s *dev = &priv->dev; + + /* Get the Frame Length of the received packet: substruct 4 + * bytes of the CRC + */ + + dev->d_len = ((rxdesc->rdes0 & ETH_RDES0_FL_MASK) >> + ETH_RDES0_FL_SHIFT) - 4; + + if (priv->segments > 1 || + dev->d_len > CONFIG_AT32_ETH_BUFSIZE) + { + /* The Frame is to big, it spans segments */ + + nerr("ERROR: Dropped, RX descriptor Too big: %d in %d " + "segments\n", dev->d_len, priv->segments); + + at32_freesegment(priv, rxcurr, priv->segments); + } + + else + { + /* Get a buffer from the free list. We don't even check if + * this is successful because we already assure the free + * list is not empty above. + */ + + buffer = at32_allocbuffer(priv); + + /* Take the buffer from the RX descriptor of the first free + * segment, put it into the network device structure, then + * replace the buffer in the RX descriptor with the newly + * allocated buffer. + */ + + DEBUGASSERT(dev->d_buf == NULL); + dev->d_buf = (uint8_t *)rxcurr->rdes2; + rxcurr->rdes2 = (uint32_t)buffer; + + /* Return success, remembering where we should re-start + * scanning and resetting the segment scanning logic + */ + + priv->rxhead = (struct eth_rxdesc_s *)rxdesc->rdes3; + at32_freesegment(priv, rxcurr, priv->segments); + + ninfo("rxhead: %p d_buf: %p d_len: %d\n", + priv->rxhead, dev->d_buf, dev->d_len); + + return OK; + } + } + else + { + /* Drop the frame that contains the errors, reset the segment + * scanning logic, and continue scanning with the next frame. + */ + + nerr("ERROR: Dropped, RX descriptor errors: %08" PRIx32 "\n", + rxdesc->rdes0); + at32_freesegment(priv, rxcurr, priv->segments); + } + } + + /* Try the next descriptor */ + + rxdesc = (struct eth_rxdesc_s *)rxdesc->rdes3; + } + + /* We get here after all of the descriptors have been scanned or when + * rxdesc points to the first descriptor owned by the DMA. Remember + * where we left off. + */ + + priv->rxhead = rxdesc; + + ninfo("rxhead: %p rxcurr: %p segments: %d\n", + priv->rxhead, priv->rxcurr, priv->segments); + + return -EAGAIN; +} + +/**************************************************************************** + * Function: at32_receive + * + * Description: + * An interrupt was received indicating the availability of a new RX packet + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static void at32_receive(struct at32_ethmac_s *priv) +{ + struct net_driver_s *dev = &priv->dev; + + /* Loop while while at32_recvframe() successfully retrieves valid + * Ethernet frames. + */ + + while (at32_recvframe(priv) == OK) + { +#ifdef CONFIG_NET_PKT + /* When packet sockets are enabled, feed the frame into the tap */ + + pkt_input(&priv->dev); +#endif + + /* Check if the packet is a valid size for the network buffer + * configuration (this should not happen) + */ + + if (dev->d_len > CONFIG_NET_ETH_PKTSIZE) + { + nwarn("WARNING: DROPPED Too big: %d\n", dev->d_len); + + /* Free dropped packet buffer */ + + if (dev->d_buf) + { + at32_freebuffer(priv, dev->d_buf); + dev->d_buf = NULL; + dev->d_len = 0; + } + + continue; + } + + /* We only accept IP packets of the configured type and ARP packets */ + +#ifdef CONFIG_NET_IPv4 + if (BUF->type == HTONS(ETHTYPE_IP)) + { + ninfo("IPv4 frame\n"); + + /* Receive an IPv4 packet from the network device */ + + ipv4_input(&priv->dev); + + /* If the above function invocation resulted in data that should be + * sent out on the network, d_len field will set to a value > 0. + */ + + if (priv->dev.d_len > 0) + { + /* And send the packet */ + + at32_transmit(priv); + } + } + else +#endif +#ifdef CONFIG_NET_IPv6 + if (BUF->type == HTONS(ETHTYPE_IP6)) + { + ninfo("IPv6 frame\n"); + + /* Give the IPv6 packet to the network layer */ + + ipv6_input(&priv->dev); + + /* If the above function invocation resulted in data that should be + * sent out on the network, d_len field will set to a value > 0. + */ + + if (priv->dev.d_len > 0) + { + /* And send the packet */ + + at32_transmit(priv); + } + } + else +#endif +#ifdef CONFIG_NET_ARP + if (BUF->type == HTONS(ETHTYPE_ARP)) + { + ninfo("ARP frame\n"); + + /* Handle ARP packet */ + + arp_input(&priv->dev); + + /* If the above function invocation resulted in data that should be + * sent out on the network, d_len field will set to a value > 0. + */ + + if (priv->dev.d_len > 0) + { + at32_transmit(priv); + } + } + else +#endif + { + nerr("ERROR: Dropped, Unknown type: %04x\n", BUF->type); + } + + /* We are finished with the RX buffer. NOTE: If the buffer is + * re-used for transmission, the dev->d_buf field will have been + * nullified. + */ + + if (dev->d_buf) + { + /* Free the receive packet buffer */ + + at32_freebuffer(priv, dev->d_buf); + dev->d_buf = NULL; + dev->d_len = 0; + } + } +} + +/**************************************************************************** + * Function: at32_freeframe + * + * Description: + * Scans the TX descriptors and frees the buffers of completed transfers. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None. + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static void at32_freeframe(struct at32_ethmac_s *priv) +{ + struct eth_txdesc_s *txdesc; + + ninfo("txhead: %p txtail: %p inflight: %d\n", + priv->txhead, priv->txtail, priv->inflight); + + /* Scan for "in-flight" descriptors owned by the CPU */ + + txdesc = priv->txtail; + if (txdesc) + { + DEBUGASSERT(priv->inflight > 0); + + while ((txdesc->tdes0 & ETH_TDES0_OWN) == 0) + { + /* There should be a buffer assigned to all in-flight + * TX descriptors. + */ + + ninfo("txtail: %p tdes0: %08" PRIx32 + " tdes2: %08" PRIx32 " tdes3: %08" PRIx32 "\n", + txdesc, txdesc->tdes0, txdesc->tdes2, txdesc->tdes3); + + DEBUGASSERT(txdesc->tdes2 != 0); + + /* Check if this is the first segment of a TX frame. */ + + if ((txdesc->tdes0 & ETH_TDES0_FS) != 0) + { + /* Yes.. Free the buffer */ + + at32_freebuffer(priv, (uint8_t *)txdesc->tdes2); + } + + /* In any event, make sure that TDES2 is nullified. */ + + txdesc->tdes2 = 0; + + /* Check if this is the last segment of a TX frame */ + + if ((txdesc->tdes0 & ETH_TDES0_LS) != 0) + { + /* Yes.. Decrement the number of frames "in-flight". */ + + priv->inflight--; + + /* If all of the TX descriptors were in-flight, + * then RX interrupts may have been disabled... + * we can re-enable them now. + */ + + at32_enableint(priv, ETH_DMAINT_RI); + + /* If there are no more frames in-flight, then bail. */ + + if (priv->inflight <= 0) + { + priv->txtail = NULL; + priv->inflight = 0; + return; + } + } + + /* Try the next descriptor in the TX chain */ + + txdesc = (struct eth_txdesc_s *)txdesc->tdes3; + } + + /* We get here if (1) there are still frames "in-flight". Remember + * where we left off. + */ + + priv->txtail = txdesc; + + ninfo("txhead: %p txtail: %p inflight: %d\n", + priv->txhead, priv->txtail, priv->inflight); + } +} + +/**************************************************************************** + * Function: at32_txdone + * + * Description: + * An interrupt was received indicating that the last TX packet + * transfer(s) are complete. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by the watchdog logic. + * + ****************************************************************************/ + +static void at32_txdone(struct at32_ethmac_s *priv) +{ + DEBUGASSERT(priv->txtail != NULL); + + /* Scan the TX descriptor change, returning buffers to free list */ + + at32_freeframe(priv); + + /* If no further xmits are pending, then cancel the TX timeout */ + + if (priv->inflight <= 0) + { + /* Cancel the TX timeout */ + + wd_cancel(&priv->txtimeout); + + /* And disable further TX interrupts. */ + + at32_disableint(priv, ETH_DMAINT_TI); + } + + /* Then poll the network for new XMIT data */ + + at32_dopoll(priv); +} + +/**************************************************************************** + * Function: at32_interrupt_work + * + * Description: + * Perform interrupt related work from the worker thread + * + * Input Parameters: + * arg - The argument passed when work_queue() was called. + * + * Returned Value: + * OK on success + * + * Assumptions: + * Ethernet interrupts are disabled + * + ****************************************************************************/ + +static void at32_interrupt_work(void *arg) +{ + struct at32_ethmac_s *priv = (struct at32_ethmac_s *)arg; + uint32_t dmasr; + + DEBUGASSERT(priv); + + /* Process pending Ethernet interrupts */ + + net_lock(); + + /* Get the DMA interrupt status bits (no MAC interrupts are expected) */ + + dmasr = at32_getreg(AT32_ETH_DMASR); + + /* Mask only enabled interrupts. This depends on the fact that the + * interrupt related bits (0-16) correspond in these two registers. + */ + + dmasr &= at32_getreg(AT32_ETH_DMAIER); + + /* Check if there are pending "normal" interrupts */ + + if ((dmasr & ETH_DMAINT_NIS) != 0) + { + /* Yes.. Check if we received an incoming packet, if so, call + * at32_receive() + */ + + if ((dmasr & ETH_DMAINT_RI) != 0) + { + /* Clear the pending receive interrupt */ + + at32_putreg(ETH_DMAINT_RI, AT32_ETH_DMASR); + + /* Handle the received package */ + + at32_receive(priv); + } + + /* Check if a packet transmission just completed. If so, call + * at32_txdone(). This may disable further TX interrupts if there + * are no pending transmissions. + */ + + if ((dmasr & ETH_DMAINT_TI) != 0) + { + /* Clear the pending receive interrupt */ + + at32_putreg(ETH_DMAINT_TI, AT32_ETH_DMASR); + + /* Check if there are pending transmissions */ + + at32_txdone(priv); + } + + /* Clear the pending normal summary interrupt */ + + at32_putreg(ETH_DMAINT_NIS, AT32_ETH_DMASR); + } + + /* Handle error interrupt only if CONFIG_DEBUG_NET is eanbled */ + +#ifdef CONFIG_DEBUG_NET + + /* Check if there are pending "anormal" interrupts */ + + if ((dmasr & ETH_DMAINT_AIS) != 0) + { + /* Just let the user know what happened */ + + nerr("ERROR: Abormal event(s): %08x\n", dmasr); + + /* Clear all pending abnormal events */ + + at32_putreg(ETH_DMAINT_ABNORMAL, AT32_ETH_DMASR); + + /* Clear the pending abnormal summary interrupt */ + + at32_putreg(ETH_DMAINT_AIS, AT32_ETH_DMASR); + } +#endif + + net_unlock(); + + /* Re-enable Ethernet interrupts at the NVIC */ + + up_enable_irq(AT32_IRQ_ETH); +} + +/**************************************************************************** + * Function: at32_interrupt + * + * Description: + * Hardware interrupt handler + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info (architecture-specific) + * + * Returned Value: + * OK on success + * + * Assumptions: + * + ****************************************************************************/ + +static int at32_interrupt(int irq, void *context, void *arg) +{ + struct at32_ethmac_s *priv = &g_at32ethmac[0]; + uint32_t dmasr; + + /* Get the DMA interrupt status bits (no MAC interrupts are expected) */ + + dmasr = at32_getreg(AT32_ETH_DMASR); + if (dmasr != 0) + { + /* Disable further Ethernet interrupts. Because Ethernet interrupts + * are also disabled if the TX timeout event occurs, there can be no + * race condition here. + */ + + up_disable_irq(AT32_IRQ_ETH); + + /* Check if a packet transmission just completed. */ + + if ((dmasr & ETH_DMAINT_TI) != 0) + { + /* If a TX transfer just completed, then cancel the TX timeout so + * there will be no race condition between any subsequent timeout + * expiration and the deferred interrupt processing. + */ + + wd_cancel(&priv->txtimeout); + } + + /* Schedule to perform the interrupt processing on the worker thread. */ + + work_queue(ETHWORK, &priv->irqwork, at32_interrupt_work, priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Function: at32_txtimeout_work + * + * Description: + * Perform TX timeout related work from the worker thread + * + * Input Parameters: + * arg - The argument passed when work_queue() as called. + * + * Returned Value: + * OK on success + * + * Assumptions: + * Ethernet interrupts are disabled + * + ****************************************************************************/ + +static void at32_txtimeout_work(void *arg) +{ + struct at32_ethmac_s *priv = (struct at32_ethmac_s *)arg; + + /* Reset the hardware. Just take the interface down, then back up again. */ + + net_lock(); + at32_ifdown(&priv->dev); + at32_ifup(&priv->dev); + + /* Then poll for new XMIT data */ + + at32_dopoll(priv); + net_unlock(); +} + +/**************************************************************************** + * Function: at32_txtimeout_expiry + * + * Description: + * Our TX watchdog timed out. Called from the timer interrupt handler. + * The last TX never completed. Reset the hardware and start again. + * + * Input Parameters: + * arg - The argument + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by the watchdog logic. + * + ****************************************************************************/ + +static void at32_txtimeout_expiry(wdparm_t arg) +{ + struct at32_ethmac_s *priv = (struct at32_ethmac_s *)arg; + + nerr("ERROR: Timeout!\n"); + + /* Disable further Ethernet interrupts. This will prevent some race + * conditions with interrupt work. There is still a potential race + * condition with interrupt work that is already queued and in progress. + * + * Interrupts will be re-enabled when at32_ifup() is called. + */ + + up_disable_irq(AT32_IRQ_ETH); + + /* Schedule to perform the TX timeout processing on the worker thread, + * perhaps canceling any pending IRQ processing. + */ + + work_queue(ETHWORK, &priv->irqwork, at32_txtimeout_work, priv, 0); +} + +/**************************************************************************** + * Function: at32_ifup + * + * Description: + * NuttX Callback: Bring up the Ethernet interface when an IP address is + * provided + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + * Assumptions: + * + ****************************************************************************/ + +static int at32_ifup(struct net_driver_s *dev) +{ + struct at32_ethmac_s *priv = + (struct at32_ethmac_s *)dev->d_private; + int ret; + +#ifdef CONFIG_NET_IPv4 + ninfo("Bringing up: %d.%d.%d.%d\n", + (int)(dev->d_ipaddr & 0xff), + (int)((dev->d_ipaddr >> 8) & 0xff), + (int)((dev->d_ipaddr >> 16) & 0xff), + (int)(dev->d_ipaddr >> 24)); +#endif +#ifdef CONFIG_NET_IPv6 + ninfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + dev->d_ipv6addr[0], dev->d_ipv6addr[1], dev->d_ipv6addr[2], + dev->d_ipv6addr[3], dev->d_ipv6addr[4], dev->d_ipv6addr[5], + dev->d_ipv6addr[6], dev->d_ipv6addr[7]); +#endif + + /* Configure the Ethernet interface for DMA operation. */ + + ret = at32_ethconfig(priv); + if (ret < 0) + { + return ret; + } + + /* Enable the Ethernet interrupt */ + + priv->ifup = true; + up_enable_irq(AT32_IRQ_ETH); + + at32_checksetup(); + return OK; +} + +/**************************************************************************** + * Function: at32_ifdown + * + * Description: + * NuttX Callback: Stop the interface. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * Returns zero on success; a negated errno value is returned on any + * failure. + * + * Assumptions: + * + ****************************************************************************/ + +static int at32_ifdown(struct net_driver_s *dev) +{ + struct at32_ethmac_s *priv = + (struct at32_ethmac_s *)dev->d_private; + irqstate_t flags; + int ret = OK; + + ninfo("Taking the network down\n"); + + /* Disable the Ethernet interrupt */ + + flags = enter_critical_section(); + up_disable_irq(AT32_IRQ_ETH); + + /* Cancel the TX timeout timers */ + + wd_cancel(&priv->txtimeout); + + /* Put the EMAC in its reset, non-operational state. This should be + * a known configuration that will guarantee the at32_ifup() always + * successfully brings the interface back up. + */ + + ret = at32_ethreset(priv); + if (ret < 0) + { + nerr("ERROR: at32_ethreset failed (timeout), " + "still assuming it's going down.\n"); + } + + /* Mark the device "down" */ + + priv->ifup = false; + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Function: at32_txavail_work + * + * Description: + * Perform an out-of-cycle poll on the worker thread. + * + * Input Parameters: + * arg - Reference to the NuttX driver state structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * Called on the higher priority worker thread. + * + ****************************************************************************/ + +static void at32_txavail_work(void *arg) +{ + struct at32_ethmac_s *priv = (struct at32_ethmac_s *)arg; + + ninfo("ifup: %d\n", priv->ifup); + + /* Ignore the notification if the interface is not yet up */ + + net_lock(); + if (priv->ifup) + { + /* Poll the network for new XMIT data */ + + at32_dopoll(priv); + } + + net_unlock(); +} + +/**************************************************************************** + * Function: at32_txavail + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called in normal user mode + * + ****************************************************************************/ + +static int at32_txavail(struct net_driver_s *dev) +{ + struct at32_ethmac_s *priv = + (struct at32_ethmac_s *)dev->d_private; + + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&priv->pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(ETHWORK, &priv->pollwork, at32_txavail_work, priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Function: at32_calcethcrc + * + * Description: + * Function to calculate the CRC used by AT32 to check an ethernet frame + * + * Input Parameters: + * data - the data to be checked + * length - length of the data + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6) +static uint32_t at32_calcethcrc(const uint8_t *data, size_t length) +{ + uint32_t crc = 0xffffffff; + size_t i; + int j; + + for (i = 0; i < length; i++) + { + for (j = 0; j < 8; j++) + { + if (((crc >> 31) ^ (data[i] >> j)) & 0x01) + { + /* x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 */ + + crc = (crc << 1) ^ 0x04c11db7; + } + else + { + crc = crc << 1; + } + } + } + + return ~crc; +} +#endif + +/**************************************************************************** + * Function: at32_addmac + * + * Description: + * NuttX Callback: Add the specified MAC address to the hardware multicast + * address filtering + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be added + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6) +static int at32_addmac(struct net_driver_s *dev, const uint8_t *mac) +{ + uint32_t crc; + uint32_t hashindex; + uint32_t temp; + uint32_t registeraddress; + + ninfo("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + /* Add the MAC address to the hardware multicast hash table */ + + crc = at32_calcethcrc(mac, 6); + + hashindex = (crc >> 26) & 0x3f; + + if (hashindex > 31) + { + registeraddress = AT32_ETH_MACHTHR; + hashindex -= 32; + } + else + { + registeraddress = AT32_ETH_MACHTLR; + } + + temp = at32_getreg(registeraddress); + temp |= 1 << hashindex; + at32_putreg(temp, registeraddress); + + temp = at32_getreg(AT32_ETH_MACFFR); + temp |= (ETH_MACFFR_HM | ETH_MACFFR_HPF); + at32_putreg(temp, AT32_ETH_MACFFR); + + return OK; +} +#endif /* CONFIG_NET_MCASTGROUP || CONFIG_NET_ICMPv6 */ + +/**************************************************************************** + * Function: at32_rmmac + * + * Description: + * NuttX Callback: Remove the specified MAC address from the hardware + * multicast address filtering + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be removed + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_MCASTGROUP +static int at32_rmmac(struct net_driver_s *dev, const uint8_t *mac) +{ + uint32_t crc; + uint32_t hashindex; + uint32_t temp; + uint32_t registeraddress; + + ninfo("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + /* Remove the MAC address to the hardware multicast hash table */ + + crc = at32_calcethcrc(mac, 6); + + hashindex = (crc >> 26) & 0x3f; + + if (hashindex > 31) + { + registeraddress = AT32_ETH_MACHTHR; + hashindex -= 32; + } + else + { + registeraddress = AT32_ETH_MACHTLR; + } + + temp = at32_getreg(registeraddress); + temp &= ~(1 << hashindex); + at32_putreg(temp, registeraddress); + + /* If there is no address registered any more, delete multicast filtering */ + + if (at32_getreg(AT32_ETH_MACHTHR) == 0 && + at32_getreg(AT32_ETH_MACHTLR) == 0) + { + temp = at32_getreg(AT32_ETH_MACFFR); + temp &= ~(ETH_MACFFR_HM | ETH_MACFFR_HPF); + at32_putreg(temp, AT32_ETH_MACFFR); + } + + return OK; +} +#endif + +/**************************************************************************** + * Function: at32_txdescinit + * + * Description: + * Initializes the DMA TX descriptors in chain mode. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void at32_txdescinit(struct at32_ethmac_s *priv, + struct eth_txdesc_s *txtable) +{ + struct eth_txdesc_s *txdesc; + int i; + + /* priv->txhead point to the first, available TX descriptor in the chain. + * Set the priv->txhead pointer to the first descriptor in the table. + */ + + priv->txhead = txtable; + + /* priv->txtail will point to the first segment of the oldest pending + * "in-flight" TX transfer. NULL means that there are no active TX + * transfers. + */ + + priv->txtail = NULL; + priv->inflight = 0; + + /* Initialize each TX descriptor */ + + for (i = 0; i < CONFIG_AT32_ETH_NTXDESC; i++) + { + txdesc = &txtable[i]; + + /* Set Second Address Chained bit */ + + txdesc->tdes0 = ETH_TDES0_TCH; + +#ifdef CHECKSUM_BY_HARDWARE + /* Enable the checksum insertion for the TX frames */ + + txdesc->tdes0 |= ETH_TDES0_CIC_ALL; +#endif + + /* Clear Buffer1 address pointer (buffers will be assigned as they + * are used) + */ + + txdesc->tdes2 = 0; + + /* Initialize the next descriptor with + * the Next Descriptor Polling Enable + */ + + if (i < (CONFIG_AT32_ETH_NTXDESC - 1)) + { + /* Set next descriptor address register with next descriptor base + * address + */ + + txdesc->tdes3 = (uint32_t)&txtable[i + 1]; + } + else + { + /* For last descriptor, set next descriptor address register equal + * to the first descriptor base address + */ + + txdesc->tdes3 = (uint32_t)txtable; + } + } + + /* Set Transmit Descriptor List Address Register */ + + at32_putreg((uint32_t)txtable, AT32_ETH_DMATDLAR); +} + +/**************************************************************************** + * Function: at32_rxdescinit + * + * Description: + * Initializes the DMA RX descriptors in chain mode. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void at32_rxdescinit(struct at32_ethmac_s *priv, + struct eth_rxdesc_s *rxtable, + uint8_t *rxbuffer) +{ + struct eth_rxdesc_s *rxdesc; + int i; + + /* priv->rxhead will point to the first, RX descriptor in the chain. + * This will be where we receive the first incomplete frame. + */ + + priv->rxhead = rxtable; + + /* If we accumulate the frame in segments, priv->rxcurr points to the + * RX descriptor of the first segment in the current TX frame. + */ + + priv->rxcurr = NULL; + priv->segments = 0; + + /* Initialize each TX descriptor */ + + for (i = 0; i < CONFIG_AT32_ETH_NRXDESC; i++) + { + rxdesc = &rxtable[i]; + + /* Set Own bit of the RX descriptor rdes0 */ + + rxdesc->rdes0 = ETH_RDES0_OWN; + + /* Set Buffer1 size and Second Address Chained bit and enabled DMA + * RX desc receive interrupt + */ + + rxdesc->rdes1 = ETH_RDES1_RCH | (uint32_t)CONFIG_AT32_ETH_BUFSIZE; + + /* Set Buffer1 address pointer */ + + rxdesc->rdes2 = (uint32_t)&rxbuffer[i * CONFIG_AT32_ETH_BUFSIZE]; + + /* Initialize the next descriptor with + * the Next Descriptor Polling Enable + */ + + if (i < (CONFIG_AT32_ETH_NRXDESC - 1)) + { + /* Set next descriptor address register with next descriptor base + * address + */ + + rxdesc->rdes3 = (uint32_t)&rxtable[i + 1]; + } + else + { + /* For last descriptor, set next descriptor address register equal + * to the first descriptor base address + */ + + rxdesc->rdes3 = (uint32_t)rxtable; + } + } + + /* Set Receive Descriptor List Address Register */ + + at32_putreg((uint32_t)rxtable, AT32_ETH_DMARDLAR); +} + +/**************************************************************************** + * Function: at32_ioctl + * + * Description: + * Executes the SIOCxMIIxxx command and responds using the request struct + * that must be provided as its 2nd parameter. + * + * When called with SIOCGMIIPHY it will get the PHY address for the device + * and write it to the req->phy_id field of the request struct. + * + * When called with SIOCGMIIREG it will read a register of the PHY that is + * specified using the req->reg_no struct field and then write its output + * to the req->val_out field. + * + * When called with SIOCSMIIREG it will write to a register of the PHY that + * is specified using the req->reg_no struct field and use req->val_in as + * its input. + * + * Input Parameters: + * dev - Ethernet device structure + * cmd - SIOCxMIIxxx command code + * arg - Request structure also used to return values + * + * Returned Value: Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int at32_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) +{ +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) + struct at32_ethmac_s *priv = + (struct at32_ethmac_s *)dev->d_private; +#endif + int ret; + + switch (cmd) + { +#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_ARCH_PHY_INTERRUPT + case SIOCMIINOTIFY: /* Set up for PHY event notifications */ + { + struct mii_ioctl_notify_s *req = + (struct mii_ioctl_notify_s *)((uintptr_t)arg); + + ret = phy_notify_subscribe(dev->d_ifname, req->pid, &req->event); + if (ret == OK) + { + /* Enable PHY link up/down interrupts */ + + ret = at32_phyintenable(priv); + } + } + break; +#endif + + case SIOCGMIIPHY: /* Get MII PHY address */ + { + struct mii_ioctl_data_s *req = + (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->phy_id = CONFIG_AT32_PHYADDR; + ret = OK; + } + break; + + case SIOCGMIIREG: /* Get register from MII PHY */ + { + struct mii_ioctl_data_s *req = + (struct mii_ioctl_data_s *)((uintptr_t)arg); + ret = at32_phyread(req->phy_id, req->reg_num, &req->val_out); + } + break; + + case SIOCSMIIREG: /* Set register in MII PHY */ + { + struct mii_ioctl_data_s *req = + (struct mii_ioctl_data_s *)((uintptr_t)arg); + ret = at32_phywrite(req->phy_id, req->reg_num, req->val_in); + } + break; +#endif /* CONFIG_NETDEV_PHY_IOCTL */ + + default: + ret = -ENOTTY; + break; + } + + return ret; +} +#endif /* CONFIG_NETDEV_IOCTL */ + +/**************************************************************************** + * Function: at32_phyintenable + * + * Description: + * Enable link up/down PHY interrupts. The interrupt protocol is like this: + * + * - Interrupt status is cleared when the interrupt is enabled. + * - Interrupt occurs. Interrupt is disabled (at the processor level) when + * is received. + * - Interrupt status is cleared when the interrupt is re-enabled. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * OK on success; Negated errno (-ETIMEDOUT) on failure. + * + ****************************************************************************/ + +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) +static int at32_phyintenable(struct at32_ethmac_s *priv) +{ + uint16_t phyval; + int ret; + + ret = at32_phyread(CONFIG_AT32_PHYADDR, MII_INT_REG, &phyval); + if (ret == OK) + { + /* Enable link up/down interrupts */ + +#ifdef CONFIG_ETH0_PHY_DP83848C + ret = at32_phywrite(CONFIG_AT32_PHYADDR, MII_DP83848C_MICR, + MII_DP83848C_INT_EN | MII_DP83848C_INT_OEN); +#endif + ret = at32_phywrite(CONFIG_AT32_PHYADDR, MII_INT_REG, + (phyval & ~MII_INT_CLREN) | MII_INT_SETEN); + } + + return ret; +} +#endif + +/**************************************************************************** + * Function: at32_phyread + * + * Description: + * Read a PHY register. + * + * Input Parameters: + * phydevaddr - The PHY device address + * phyregaddr - The PHY register address + * value - The location to return the 16-bit PHY register value. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#if defined(CONFIG_AT32_AUTONEG) || defined(CONFIG_NETDEV_PHY_IOCTL) || \ + defined(CONFIG_ETH0_PHY_DM9161) +static int at32_phyread(uint16_t phydevaddr, + uint16_t phyregaddr, uint16_t *value) +{ + volatile uint32_t timeout; + uint32_t regval; + + regval = at32_getreg(AT32_ETH_MACMIIAR); + + /* Clear the busy bit before accessing the MACMIIAR register. */ + + regval &= ~ETH_MACMIIAR_MB; + at32_putreg(regval, AT32_ETH_MACMIIAR); + + /* Configure the MACMIIAR register, + * preserving CSR Clock Range CR[2:0] bits + */ + + regval &= ETH_MACMIIAR_CR_MASK; + + /* Set the PHY device address, PHY register address, and set the busy bit. + * the ETH_MACMIIAR_MW is clear, indicating a read operation. + */ + + regval |= (phydevaddr << ETH_MACMIIAR_PA_SHIFT) & ETH_MACMIIAR_PA_MASK; + regval |= (phyregaddr << ETH_MACMIIAR_MR_SHIFT) & ETH_MACMIIAR_MR_MASK; + regval |= ETH_MACMIIAR_MB; + + at32_putreg(regval, AT32_ETH_MACMIIAR); + + /* Wait for the transfer to complete */ + + for (timeout = 0; timeout < PHY_READ_TIMEOUT; timeout++) + { + if ((at32_getreg(AT32_ETH_MACMIIAR) & ETH_MACMIIAR_MB) == 0) + { + *value = (uint16_t)at32_getreg(AT32_ETH_MACMIIDR); + return OK; + } + } + + nerr("ERROR: MII transfer timed out: phydevaddr: %04x phyregaddr: %04x\n", + phydevaddr, phyregaddr); + + return -ETIMEDOUT; +} +#endif + +/**************************************************************************** + * Function: at32_phywrite + * + * Description: + * Write to a PHY register. + * + * Input Parameters: + * phydevaddr - The PHY device address + * phyregaddr - The PHY register address + * value - The 16-bit value to write to the PHY register value. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +static int at32_phywrite(uint16_t phydevaddr, + uint16_t phyregaddr, uint16_t value) +{ + volatile uint32_t timeout; + uint32_t regval; + + regval = at32_getreg(AT32_ETH_MACMIIAR); + + /* Clear the busy bit before accessing the MACMIIAR register. */ + + regval &= ~ETH_MACMIIAR_MB; + at32_putreg(regval, AT32_ETH_MACMIIAR); + + /* Configure the MACMIIAR register, + * preserving CSR Clock Range CR[2:0] bits + */ + + regval &= ETH_MACMIIAR_CR_MASK; + + /* Set the PHY device address, PHY register address, and set the busy bit. + * the ETH_MACMIIAR_MW is set, indicating a write operation. + */ + + regval |= (phydevaddr << ETH_MACMIIAR_PA_SHIFT) & ETH_MACMIIAR_PA_MASK; + regval |= (phyregaddr << ETH_MACMIIAR_MR_SHIFT) & ETH_MACMIIAR_MR_MASK; + regval |= (ETH_MACMIIAR_MB | ETH_MACMIIAR_MW); + + /* Write the value into the MACIIDR register before setting the new + * MACMIIAR register value. + */ + + at32_putreg(value, AT32_ETH_MACMIIDR); + at32_putreg(regval, AT32_ETH_MACMIIAR); + + /* Wait for the transfer to complete */ + + for (timeout = 0; timeout < PHY_WRITE_TIMEOUT; timeout++) + { + if ((at32_getreg(AT32_ETH_MACMIIAR) & ETH_MACMIIAR_MB) == 0) + { + return OK; + } + } + + nerr("ERROR: MII transfer timed out: " + "phydevaddr: %04x phyregaddr: %04x value: %04x\n", + phydevaddr, phyregaddr, value); + + return -ETIMEDOUT; +} + +/**************************************************************************** + * Function: at32_dm9161 + * + * Description: + * Special workaround for the Davicom DM9161 PHY is required. On power, + * up, the PHY is not usually configured correctly but will work after + * a powered-up reset. This is really a workaround for some more + * fundamental issue with the PHY clocking initialization, but the + * root cause has not been studied (nor will it be with this workaround). + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_ETH0_PHY_DM9161 +static inline int at32_dm9161(struct at32_ethmac_s *priv) +{ + uint16_t phyval; + int ret; + + /* Read the PHYID1 register; A failure to read the PHY ID is one + * indication that check if the DM9161 PHY CHIP is not ready. + */ + + ret = at32_phyread(CONFIG_AT32_PHYADDR, MII_PHYID1, &phyval); + if (ret < 0) + { + nerr("ERROR: Failed to read the PHY ID1: %d\n", ret); + return ret; + } + + /* If we failed to read the PHY ID1 register, + * then reset the MCU to recover + */ + + else if (phyval == 0xffff) + { + up_systemreset(); + } + + ninfo("PHY ID1: 0x%04X\n", phyval); + + /* Now check the "DAVICOM Specified Configuration Register (DSCR)"(16) */ + + ret = at32_phyread(CONFIG_AT32_PHYADDR, 16, &phyval); + if (ret < 0) + { + nerr("ERROR: Failed to read the PHY Register 0x10: %d\n", ret); + return ret; + } + + /* Bit 8 of the DSCR register is zero, then the DM9161 has not selected + * RMII. If RMII is not selected, then reset the MCU to recover. + */ + + else if ((phyval & (1 << 8)) == 0) + { + up_systemreset(); + } + + return OK; +} +#endif + +/**************************************************************************** + * Function: at32_phyinit + * + * Description: + * Configure the PHY and determine the link speed/duplex. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +static int at32_phyinit(struct at32_ethmac_s *priv) +{ +#ifdef CONFIG_AT32_AUTONEG + volatile uint32_t timeout; +#endif + + uint32_t regval; + uint16_t phyval; + int ret; + + /* Assume 10MBps and half duplex */ + + priv->mbps100 = 0; + priv->fduplex = 0; + + /* Setup up PHY clocking by setting the SR field in the MACMIIAR register */ + + regval = at32_getreg(AT32_ETH_MACMIIAR); + regval &= ~ETH_MACMIIAR_CR_MASK; + regval |= ETH_MACMIIAR_CR; + at32_putreg(regval, AT32_ETH_MACMIIAR); + + /* Put the PHY in reset mode */ + + ret = at32_phywrite(CONFIG_AT32_PHYADDR, MII_MCR, MII_MCR_RESET); + if (ret < 0) + { + nerr("ERROR: Failed to reset the PHY: %d\n", ret); + return ret; + } + + up_mdelay(PHY_RESET_DELAY); + + /* Perform any necessary, board-specific PHY initialization */ + +#ifdef CONFIG_AT32_PHYINIT + ret = at32_phy_boardinitialize(0); + if (ret < 0) + { + nerr("ERROR: Failed to initialize the PHY: %d\n", ret); + return ret; + } +#endif + + /* Special workaround for the Davicom DM9161 PHY is required. */ + +#ifdef CONFIG_ETH0_PHY_DM9161 + ret = at32_dm9161(priv); + if (ret < 0) + { + return ret; + } +#endif + + /* Perform auto-negotiation if so configured */ + +#ifdef CONFIG_AT32_AUTONEG + /* Wait for link status */ + + for (timeout = 0; timeout < PHY_RETRY_TIMEOUT; timeout++) + { + ret = at32_phyread(CONFIG_AT32_PHYADDR, MII_MSR, &phyval); + if (ret < 0) + { + nerr("ERROR: Failed to read the PHY MSR: %d\n", ret); + return ret; + } + else if ((phyval & MII_MSR_LINKSTATUS) != 0) + { + break; + } + } + + if (timeout >= PHY_RETRY_TIMEOUT) + { + nerr("ERROR: Timed out waiting for link status: %04x\n", phyval); + return -ETIMEDOUT; + } + + /* Enable auto-gegotiation */ + + ret = at32_phywrite(CONFIG_AT32_PHYADDR, MII_MCR, MII_MCR_ANENABLE); + if (ret < 0) + { + nerr("ERROR: Failed to enable auto-negotiation: %d\n", ret); + return ret; + } + + /* Wait until auto-negotiation completes */ + + for (timeout = 0; timeout < PHY_RETRY_TIMEOUT; timeout++) + { + ret = at32_phyread(CONFIG_AT32_PHYADDR, MII_MSR, &phyval); + if (ret < 0) + { + nerr("ERROR: Failed to read the PHY MSR: %d\n", ret); + return ret; + } + else if ((phyval & MII_MSR_ANEGCOMPLETE) != 0) + { + break; + } + } + + if (timeout >= PHY_RETRY_TIMEOUT) + { + nerr("ERROR: Timed out waiting for auto-negotiation\n"); + return -ETIMEDOUT; + } + + /* Read the result of the auto-negotiation from the PHY-specific register */ + + ret = at32_phyread(CONFIG_AT32_PHYADDR, CONFIG_AT32_PHYSR, &phyval); + if (ret < 0) + { + nerr("ERROR: Failed to read PHY status register\n"); + return ret; + } + + /* Remember the selected speed and duplex modes */ + + ninfo("PHYSR[%d]: %04x\n", CONFIG_AT32_PHYSR, phyval); + + /* Different PHYs present speed and mode information in different ways. + * IF This CONFIG_AT32_PHYSR_ALTCONFIG is selected, this indicates that + * the PHY represents speed and mode information are combined, for example, + * with separate bits for 10HD, 100HD, 10FD and 100FD. + */ + +#ifdef CONFIG_AT32_PHYSR_ALTCONFIG + switch (phyval & CONFIG_AT32_PHYSR_ALTMODE) + { + default: + case CONFIG_AT32_PHYSR_10HD: + priv->fduplex = 0; + priv->mbps100 = 0; + break; + + case CONFIG_AT32_PHYSR_100HD: + priv->fduplex = 0; + priv->mbps100 = 1; + break; + + case CONFIG_AT32_PHYSR_10FD: + priv->fduplex = 1; + priv->mbps100 = 0; + break; + + case CONFIG_AT32_PHYSR_100FD: + priv->fduplex = 1; + priv->mbps100 = 1; + break; + } + + /* Different PHYs present speed and mode information in different ways. + * Some will present separate information for speed and mode (this is the + * default). Those PHYs, for example, may provide a 10/100 Mbps indication + * and a separate full/half duplex indication. + */ + +#else + if ((phyval & CONFIG_AT32_PHYSR_MODE) == CONFIG_AT32_PHYSR_FULLDUPLEX) + { + priv->fduplex = 1; + } + + if ((phyval & CONFIG_AT32_PHYSR_SPEED) == CONFIG_AT32_PHYSR_100MBPS) + { + priv->mbps100 = 1; + } +#endif + +#else /* Auto-negotiation not selected */ + + phyval = 0; +#ifdef CONFIG_AT32_ETHFD + phyval |= MII_MCR_FULLDPLX; +#endif +#ifdef CONFIG_AT32_ETH100MBPS + phyval |= MII_MCR_SPEED100; +#endif + + ret = at32_phywrite(CONFIG_AT32_PHYADDR, MII_MCR, phyval); + if (ret < 0) + { + nerr("ERROR: Failed to write the PHY MCR: %d\n", ret); + return ret; + } + + up_mdelay(PHY_CONFIG_DELAY); + + /* Remember the selected speed and duplex modes */ + +#ifdef CONFIG_AT32_ETHFD + priv->fduplex = 1; +#endif +#ifdef CONFIG_AT32_ETH100MBPS + priv->mbps100 = 1; +#endif +#endif + + ninfo("Duplex: %s Speed: %d MBps\n", + priv->fduplex ? "FULL" : "HALF", + priv->mbps100 ? 100 : 10); + + return OK; +} + +/**************************************************************************** + * Name: at32_selectmii + * + * Description: + * Selects the MII interface. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_MII +static inline void at32_selectmii(void) +{ + uint32_t regval; + +#ifdef CONFIG_AT32_CONNECTIVITYLINE + regval = getreg32(AT32_AFIO_MAPR); + regval &= ~AFIO_MAPR_MII_RMII_SEL; + putreg32(regval, AT32_AFIO_MAPR); +#else + regval = getreg32(AT32_SCFG_CFG2); + regval &= ~SCFG_CFG2_MII_RMII_SEL; + putreg32(regval, AT32_SCFG_CFG2); +#endif +} +#endif + +/**************************************************************************** + * Name: at32_selectrmii + * + * Description: + * Selects the RMII interface. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_RMII +static inline void at32_selectrmii(void) +{ + uint32_t regval; + +#ifdef CONFIG_AT32_CONNECTIVITYLINE + regval = getreg32(AT32_AFIO_MAPR); + regval |= AFIO_MAPR_MII_RMII_SEL; + putreg32(regval, AT32_AFIO_MAPR); +#else + regval = getreg32(AT32_SCFG_CFG2); + regval |= SCFG_CFG2_MII_RMII_SEL; + putreg32(regval, AT32_SCFG_CFG2); +#endif +} +#endif + +/**************************************************************************** + * Function: at32_ethgpioconfig + * + * Description: + * Configure GPIOs for the Ethernet interface. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * None. + * + * Assumptions: + * + ****************************************************************************/ + +static inline void at32_ethgpioconfig(struct at32_ethmac_s *priv) +{ + /* Configure GPIO pins to support Ethernet */ + +#if defined(CONFIG_AT32_MII) || defined(CONFIG_AT32_RMII) + + /* MDC and MDIO are common to both modes */ + + at32_configgpio(GPIO_ETH_MDC); + at32_configgpio(GPIO_ETH_MDIO); + + /* Set up the MII interface */ + +#if defined(CONFIG_AT32_MII) + + /* Select the MII interface */ + + at32_selectmii(); + + /* Provide clocking via MCO, MCO1 or MCO2: + * + * "MCO1 (microcontroller clock output), used to output HSI, LSE, HSE or + * PLL clock (through a configurable prescaler) on PA8 pin." + * + * "MCO2 (microcontroller clock output), used to output HSE, PLL, SYSCLK or + * PLLI2S clock (through a configurable prescaler) on PC9 pin." + */ + +# if defined(CONFIG_AT32_MII_MCO1) + /* Configure MC01 to drive the PHY. Board logic must provide MC01 clocking + * info. + */ + + at32_configgpio(GPIO_MCO1); + at32_mco1config(BOARD_CFGR_MC01_SOURCE, BOARD_CFGR_MC01_DIVIDER); + +# elif defined(CONFIG_AT32_MII_MCO2) + /* Configure MC02 to drive the PHY. Board logic must provide MC02 clocking + * info. + */ + + at32_configgpio(GPIO_MCO2); + at32_mco2config(BOARD_CFGR_MC02_SOURCE, BOARD_CFGR_MC02_DIVIDER); + +# elif defined(CONFIG_AT32_MII_MCO) + /* Setup MCO pin for alternative usage */ + + at32_configgpio(GPIO_MCO); + at32_mcoconfig(BOARD_CFGR_MCO_SOURCE); +# endif + + /* MII interface pins (17): + * + * MII_TX_CLK, MII_TXD[3:0], MII_TX_EN, MII_RX_CLK, MII_RXD[3:0], + * MII_RX_ER, MII_RX_DV, MII_CRS, MII_COL, MDC, MDIO + */ + + at32_configgpio(GPIO_ETH_MII_COL); + at32_configgpio(GPIO_ETH_MII_CRS); + at32_configgpio(GPIO_ETH_MII_RXD0); + at32_configgpio(GPIO_ETH_MII_RXD1); + at32_configgpio(GPIO_ETH_MII_RXD2); + at32_configgpio(GPIO_ETH_MII_RXD3); + at32_configgpio(GPIO_ETH_MII_RX_CLK); + at32_configgpio(GPIO_ETH_MII_RX_DV); + at32_configgpio(GPIO_ETH_MII_RX_ER); + at32_configgpio(GPIO_ETH_MII_TXD0); + at32_configgpio(GPIO_ETH_MII_TXD1); + at32_configgpio(GPIO_ETH_MII_TXD2); + at32_configgpio(GPIO_ETH_MII_TXD3); + at32_configgpio(GPIO_ETH_MII_TX_CLK); + at32_configgpio(GPIO_ETH_MII_TX_EN); + + /* Set up the RMII interface. */ + +#elif defined(CONFIG_AT32_RMII) + + /* Select the RMII interface */ + + at32_selectrmii(); + + /* Provide clocking via MCO, MCO1 or MCO2: + * + * "MCO1 (microcontroller clock output), used to output HSI, LSE, HSE or + * PLL clock (through a configurable prescaler) on PA8 pin." + * + * "MCO2 (microcontroller clock output), used to output HSE, PLL, SYSCLK or + * PLLI2S clock (through a configurable prescaler) on PC9 pin." + */ + +# if defined(CONFIG_AT32_RMII_MCO1) + /* Configure MC01 to drive the PHY. Board logic must provide MC01 clocking + * info. + */ + + at32_configgpio(GPIO_MCO1); + at32_mco1config(BOARD_CFGR_MC01_SOURCE, BOARD_CFGR_MC01_DIVIDER); + +# elif defined(CONFIG_AT32_RMII_MCO2) + /* Configure MC02 to drive the PHY. Board logic must provide MC02 clocking + * info. + */ + + at32_configgpio(GPIO_MCO2); + at32_mco2config(BOARD_CFGR_MC02_SOURCE, BOARD_CFGR_MC02_DIVIDER); + +# elif defined(CONFIG_AT32_RMII_MCO) + /* Setup MCO pin for alternative usage */ + + at32_configgpio(GPIO_MCO); + at32_mcoconfig(BOARD_CFGR_MCO_SOURCE); +# endif + + /* RMII interface pins (7): + * + * RMII_TXD[1:0], RMII_TX_EN, RMII_RXD[1:0], RMII_CRS_DV, MDC, MDIO, + * RMII_REF_CLK + */ + + at32_configgpio(GPIO_ETH_RMII_CRS_DV); + at32_configgpio(GPIO_ETH_RMII_REF_CLK); + at32_configgpio(GPIO_ETH_RMII_RXD0); + at32_configgpio(GPIO_ETH_RMII_RXD1); + at32_configgpio(GPIO_ETH_RMII_TXD0); + at32_configgpio(GPIO_ETH_RMII_TXD1); + at32_configgpio(GPIO_ETH_RMII_TX_EN); + +#endif +#endif + +#ifdef CONFIG_AT32_ETH_PTP + /* Enable pulse-per-second (PPS) output signal */ + + at32_configgpio(GPIO_ETH_PPS_OUT); +#endif +} + +/**************************************************************************** + * Function: at32_ethreset + * + * Description: + * Reset the Ethernet block. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * Zero on success, or a negated errno value on any failure. + * + * Assumptions: + * + ****************************************************************************/ + +static int at32_ethreset(struct at32_ethmac_s *priv) +{ + uint32_t regval; + uint32_t retries; + +#if defined(CONFIG_AT32_CONNECTIVITYLINE) + regval = at32_getreg(AT32_RCC_AHBRSTR); + regval |= RCC_AHBRSTR_ETHMACRST; + at32_putreg(regval, AT32_RCC_AHBRSTR); + + regval &= ~RCC_AHBRSTR_ETHMACRST; + at32_putreg(regval, AT32_RCC_AHBRSTR); +#else + regval = at32_getreg(AT32_CRM_AHBRST1); + regval |= CRM_AHBRST1_EMACRST; + at32_putreg(regval, AT32_CRM_AHBRST1); + + regval &= ~CRM_AHBRST1_EMACRST; + at32_putreg(regval, AT32_CRM_AHBRST1); +#endif + + /* Perform a software reset by setting the SR bit in the DMABMR register. + * This Resets all MAC subsystem internal registers and logic. After this + * reset all the registers holds their reset values. + */ + + regval = at32_getreg(AT32_ETH_DMABMR); + regval |= ETH_DMABMR_SR; + at32_putreg(regval, AT32_ETH_DMABMR); + + /* Wait for software reset to complete. The SR bit is cleared automatically + * after the reset operation has completed in all core clock domains. + */ + + retries = 100; + while (((at32_getreg(AT32_ETH_DMABMR) & ETH_DMABMR_SR) != 0) && + retries > 0) + { + retries--; + up_mdelay(10); + } + + if (retries == 0) + { + return -ETIMEDOUT; + } + + return 0; +} + +/**************************************************************************** + * Function: at32_macconfig + * + * Description: + * Configure the Ethernet MAC for DMA operation. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +static int at32_macconfig(struct at32_ethmac_s *priv) +{ + uint32_t regval; + + /* Set up the MACCR register */ + + regval = at32_getreg(AT32_ETH_MACCR); + regval &= ~MACCR_CLEAR_BITS; + regval |= MACCR_SET_BITS; + + if (priv->fduplex) + { + /* Set the DM bit for full duplex support */ + + regval |= ETH_MACCR_DM; + } + + if (priv->mbps100) + { + /* Set the FES bit for 100Mbps fast ethernet support */ + + regval |= ETH_MACCR_FES; + } + + at32_putreg(regval, AT32_ETH_MACCR); + + /* Set up the MACFFR register */ + + regval = at32_getreg(AT32_ETH_MACFFR); + regval &= ~MACFFR_CLEAR_BITS; + regval |= MACFFR_SET_BITS; + at32_putreg(regval, AT32_ETH_MACFFR); + + /* Set up the MACHTHR and MACHTLR registers */ + + at32_putreg(0, AT32_ETH_MACHTHR); + at32_putreg(0, AT32_ETH_MACHTLR); + + /* Setup up the MACFCR register */ + + regval = at32_getreg(AT32_ETH_MACFCR); + regval &= ~MACFCR_CLEAR_MASK; + regval |= MACFCR_SET_MASK; + at32_putreg(regval, AT32_ETH_MACFCR); + + /* Setup up the MACVLANTR register */ + + at32_putreg(0, AT32_ETH_MACVLANTR); + + /* DMA Configuration */ + + /* Set up the DMAOMR register */ + + regval = at32_getreg(AT32_ETH_DMAOMR); + regval &= ~DMAOMR_CLEAR_MASK; + regval |= DMAOMR_SET_MASK; + at32_putreg(regval, AT32_ETH_DMAOMR); + + /* Set up the DMABMR register */ + + regval = at32_getreg(AT32_ETH_DMABMR); + regval &= ~DMABMR_CLEAR_MASK; + regval |= DMABMR_SET_MASK; + at32_putreg(regval, AT32_ETH_DMABMR); + + return OK; +} + +/**************************************************************************** + * Function: at32_macaddress + * + * Description: + * Configure the selected MAC address. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +static void at32_macaddress(struct at32_ethmac_s *priv) +{ + struct net_driver_s *dev = &priv->dev; + uint32_t regval; + + ninfo("%s MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->d_ifname, + dev->d_mac.ether.ether_addr_octet[0], + dev->d_mac.ether.ether_addr_octet[1], + dev->d_mac.ether.ether_addr_octet[2], + dev->d_mac.ether.ether_addr_octet[3], + dev->d_mac.ether.ether_addr_octet[4], + dev->d_mac.ether.ether_addr_octet[5]); + + /* Set the MAC address high register */ + + regval = ((uint32_t)dev->d_mac.ether.ether_addr_octet[5] << 8) | + (uint32_t)dev->d_mac.ether.ether_addr_octet[4]; + at32_putreg(regval, AT32_ETH_MACA0HR); + + /* Set the MAC address low register */ + + regval = ((uint32_t)dev->d_mac.ether.ether_addr_octet[3] << 24) | + ((uint32_t)dev->d_mac.ether.ether_addr_octet[2] << 16) | + ((uint32_t)dev->d_mac.ether.ether_addr_octet[1] << 8) | + (uint32_t)dev->d_mac.ether.ether_addr_octet[0]; + at32_putreg(regval, AT32_ETH_MACA0LR); +} + +/**************************************************************************** + * Function: at32_ipv6multicast + * + * Description: + * Configure the IPv6 multicast MAC address. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ICMPv6 +static void at32_ipv6multicast(struct at32_ethmac_s *priv) +{ + struct net_driver_s *dev; + uint16_t tmp16; + uint8_t mac[6]; + + /* For ICMPv6, we need to add the IPv6 multicast address + * + * For IPv6 multicast addresses, the Ethernet MAC is derived by + * the four low-order octets OR'ed with the MAC 33:33:00:00:00:00, + * so for example the IPv6 address FF02:DEAD:BEEF::1:3 would map + * to the Ethernet MAC address 33:33:00:01:00:03. + * + * NOTES: This appears correct for the ICMPv6 Router Solicitation + * Message, but the ICMPv6 Neighbor Solicitation message seems to + * use 33:33:ff:01:00:03. + */ + + mac[0] = 0x33; + mac[1] = 0x33; + + dev = &priv->dev; + tmp16 = dev->d_ipv6addr[6]; + mac[2] = 0xff; + mac[3] = tmp16 >> 8; + + tmp16 = dev->d_ipv6addr[7]; + mac[4] = tmp16 & 0xff; + mac[5] = tmp16 >> 8; + + ninfo("IPv6 Multicast: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + at32_addmac(dev, mac); + +#ifdef CONFIG_NET_ICMPv6_AUTOCONF + /* Add the IPv6 all link-local nodes Ethernet address. This is the + * address that we expect to receive ICMPv6 Router Advertisement + * packets. + */ + + at32_addmac(dev, g_ipv6_ethallnodes.ether_addr_octet); + +#endif /* CONFIG_NET_ICMPv6_AUTOCONF */ +#ifdef CONFIG_NET_ICMPv6_ROUTER + /* Add the IPv6 all link-local routers Ethernet address. This is the + * address that we expect to receive ICMPv6 Router Solicitation + * packets. + */ + + at32_addmac(dev, g_ipv6_ethallrouters.ether_addr_octet); + +#endif /* CONFIG_NET_ICMPv6_ROUTER */ +} +#endif /* CONFIG_NET_ICMPv6 */ + +/**************************************************************************** + * Function: at32_macenable + * + * Description: + * Enable normal MAC operation. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +static int at32_macenable(struct at32_ethmac_s *priv) +{ + uint32_t regval; + + /* Set the MAC address */ + + at32_macaddress(priv); + +#ifdef CONFIG_NET_ICMPv6 + /* Set up the IPv6 multicast address */ + + at32_ipv6multicast(priv); +#endif + + /* Enable transmit state machine of the MAC for transmission on the MII */ + + regval = at32_getreg(AT32_ETH_MACCR); + regval |= ETH_MACCR_TE; + at32_putreg(regval, AT32_ETH_MACCR); + + /* Flush Transmit FIFO */ + + regval = at32_getreg(AT32_ETH_DMAOMR); + regval |= ETH_DMAOMR_FTF; + at32_putreg(regval, AT32_ETH_DMAOMR); + + /* Enable receive state machine of the MAC for reception from the MII */ + + /* Enables or disables the MAC reception. */ + + regval = at32_getreg(AT32_ETH_MACCR); + regval |= ETH_MACCR_RE; + at32_putreg(regval, AT32_ETH_MACCR); + + /* Start DMA transmission */ + + regval = at32_getreg(AT32_ETH_DMAOMR); + regval |= ETH_DMAOMR_ST; + at32_putreg(regval, AT32_ETH_DMAOMR); + + /* Start DMA reception */ + + regval = at32_getreg(AT32_ETH_DMAOMR); + regval |= ETH_DMAOMR_SR; + at32_putreg(regval, AT32_ETH_DMAOMR); + + /* Enable Ethernet DMA interrupts. + * + * The AT32 hardware supports two interrupts: (1) one dedicated to normal + * Ethernet operations and the other, used only for the Ethernet wakeup + * event. The wake-up interrupt is not used by this driver. + * + * The first Ethernet vector is reserved for interrupts generated by the + * MAC and the DMA. The MAC provides PMT and time stamp trigger interrupts, + * neither of which are used by this driver. + */ + + at32_putreg(ETH_MACIMR_ALLINTS, AT32_ETH_MACIMR); + + /* Ethernet DMA supports two classes of interrupts: Normal interrupt + * summary (NIS) and Abnormal interrupt summary (AIS) with a variety + * individual normal and abnormal interrupting events. Here only + * the normal receive event is enabled (unless DEBUG is enabled). Transmit + * events will only be enabled when a transmit interrupt is expected. + */ + + at32_putreg(ETH_DMAINT_RECV_ENABLE | ETH_DMAINT_ERROR_ENABLE, + AT32_ETH_DMAIER); + return OK; +} + +/**************************************************************************** + * Function: at32_ethconfig + * + * Description: + * Configure the Ethernet interface for DMA operation. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +static int at32_ethconfig(struct at32_ethmac_s *priv) +{ + int ret; + + /* NOTE: The Ethernet clocks were initialized early in the boot-up + * sequence in at32_rcc.c. + */ + + /* Reset the Ethernet block */ + + ninfo("Reset the Ethernet block\n"); + ret = at32_ethreset(priv); + if (ret < 0) + { + nerr("ERROR: Reset of Ethernet block failed\n"); + return ret; + } + + /* Initialize the PHY */ + + ninfo("Initialize the PHY\n"); + ret = at32_phyinit(priv); + if (ret < 0) + { + return ret; + } + + /* Initialize the MAC and DMA */ + + ninfo("Initialize the MAC and DMA\n"); + ret = at32_macconfig(priv); + if (ret < 0) + { + return ret; + } + + /* Initialize the free buffer list */ + + at32_initbuffer(priv, g_alloc); + + /* Initialize TX Descriptors list: Chain Mode */ + + at32_txdescinit(priv, g_txtable); + + /* Initialize RX Descriptors list: Chain Mode */ + + at32_rxdescinit(priv, g_rxtable, g_rxbuffer); + + /* Enable normal MAC operation */ + + ninfo("Enable normal operation\n"); + return at32_macenable(priv); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: at32_ethinitialize + * + * Description: + * Initialize the Ethernet driver for one interface. If the AT32 chip + * supports multiple Ethernet controllers, then board specific logic + * must implement arm_netinitialize() and call this function to initialize + * the desired interfaces. + * + * Input Parameters: + * intf - In the case where there are multiple EMACs, this value + * identifies which EMAC is to be initialized. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#if AT32_NETHERNET == 1 || defined(CONFIG_NETDEV_LATEINIT) +static inline +#endif +int at32_ethinitialize(int intf) +{ + struct at32_ethmac_s *priv; + int ret; +#ifdef CONFIG_NET_ETHERNET + uint8_t uniqueid[12]; + uint32_t uid; + uint8_t *mac; +#endif + + ninfo("intf: %d\n", intf); + + /* Get the interface structure associated with this interface number. */ + + DEBUGASSERT(intf < AT32_NETHERNET); + priv = &g_at32ethmac[intf]; + + /* Initialize the driver structure */ + + memset(priv, 0, sizeof(struct at32_ethmac_s)); + priv->dev.d_ifup = at32_ifup; /* I/F up (new IP address) callback */ + priv->dev.d_ifdown = at32_ifdown; /* I/F down callback */ + priv->dev.d_txavail = at32_txavail; /* New TX data callback */ +#ifdef CONFIG_NET_MCASTGROUP + priv->dev.d_addmac = at32_addmac; /* Add multicast MAC address */ + priv->dev.d_rmmac = at32_rmmac; /* Remove multicast MAC address */ +#endif +#ifdef CONFIG_NETDEV_IOCTL + priv->dev.d_ioctl = at32_ioctl; /* Support PHY ioctl() calls */ +#endif + priv->dev.d_private = g_at32ethmac; /* Used to recover private state from dev */ + + /* Configure GPIO pins to support Ethernet */ + + at32_ethgpioconfig(priv); + +#ifdef CONFIG_NET_ETHERNET + /* Determine a unique MAC address from MCU UID */ + + mac = priv->dev.d_mac.ether.ether_addr_octet; + + at32_get_uniqueid(uniqueid); + uid = crc32part(uniqueid, sizeof(uniqueid), 0); + + mac[0] = uniqueid[10] & 0xfe; + mac[1] = uniqueid[11]; + mac[2] = (uid & 0xff000000) >> 24; + mac[3] = (uid & 0x00ff0000) >> 16; + mac[4] = (uid & 0x0000ff00) >> 8; + mac[5] = (uid & 0x000000ff); + +#endif + + /* Attach the IRQ to the driver */ + + if (irq_attach(AT32_IRQ_ETH, at32_interrupt, NULL)) + { + /* We could not attach the ISR to the interrupt */ + + return -EAGAIN; + } + + /* Put the interface in the down state. */ + + ret = at32_ifdown(&priv->dev); + if (ret < 0) + { + nerr("ERROR: Initialization of Ethernet block failed: %d\n", ret); + return ret; + } + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + netdev_register(&priv->dev, NET_LL_ETHERNET); + return OK; +} + +/**************************************************************************** + * Function: arm_netinitialize + * + * Description: + * This is the "standard" network initialization logic called from the + * low-level initialization logic in arm_initialize.c. If AT32_NETHERNET + * greater than one, then board specific logic will have to supply a + * version of arm_netinitialize() that calls at32_ethinitialize() with + * the appropriate interface number. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + * Assumptions: + * + ****************************************************************************/ + +#if AT32_NETHERNET == 1 && !defined(CONFIG_NETDEV_LATEINIT) +void arm_netinitialize(void) +{ + at32_ethinitialize(0); + +#ifdef CONFIG_AT32_CAN_SOCKET + + extern int at32_cansockinitialize(int port); + +#ifdef CONFIG_AT32_CAN1 + at32_cansockinitialize(1); +#endif + +#ifdef CONFIG_AT32_CAN2 + at32_cansockinitialize(2); +#endif + +#endif +} +#endif + +#endif /* AT32_NETHERNET > 0 */ +#endif /* CONFIG_NET && CONFIG_AT32_ETHMAC */ diff --git a/arch/arm/src/at32/at32_eth.h b/arch/arm/src/at32/at32_eth.h new file mode 100644 index 0000000000..fb40de594e --- /dev/null +++ b/arch/arm/src/at32/at32_eth.h @@ -0,0 +1,107 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_eth.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_ETH_H +#define __ARCH_ARM_SRC_AT32_AT32_ETH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +#if AT32_NETHERNET > 0 + +#include "hardware/at32_eth.h" + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Function: at32_ethinitialize + * + * Description: + * Initialize the Ethernet driver for one interface. If the AT32 chip + * supports multiple Ethernet controllers, then board specific logic must + * implement arm_netinitialize() and call this function to initialize the + * desired interfaces. + * + * Input Parameters: + * intf - In the case where there are multiple EMACs, this value + * identifies which EMAC is to be initialized. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#if AT32_NETHERNET > 1 || defined(CONFIG_NETDEV_LATEINIT) +int at32_ethinitialize(int intf); +#endif + +/**************************************************************************** + * Function: at32_phy_boardinitialize + * + * Description: + * Some boards require specialized initialization of the PHY before it can + * be used. This may include such things as configuring GPIOs, resetting + * the PHY, etc. If CONFIG_AT32_PHYINIT is defined in the configuration + * then the board specific logic must provide at32_phyinitialize(); The + * AT32 Ethernet driver will call this function one time before it first + * uses the PHY. + * + * Input Parameters: + * intf - Always zero for now. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_PHYINIT +int at32_phy_boardinitialize(int intf); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* AT32_NETHERNET > 0 */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_ETH_H */ diff --git a/arch/arm/src/at32/at32_exti.h b/arch/arm/src/at32/at32_exti.h new file mode 100644 index 0000000000..53b280a316 --- /dev/null +++ b/arch/arm/src/at32/at32_exti.h @@ -0,0 +1,142 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_exti.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_EXTI_H +#define __ARCH_ARM_SRC_AT32_AT32_EXTI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "chip.h" +#include "hardware/at32_exti.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_gpiosetevent + * + * Description: + * Sets/clears GPIO based event and interrupt triggers. + * + * Input Parameters: + * - pinset: gpio pin configuration + * - rising/falling edge: enables + * - event: generate event when set + * - func: when non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +int at32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, + bool event, xcpt_t func, void *arg); + +/**************************************************************************** + * Name: at32_gpioswirq + * + * Description: + * Trigger an extended interrupt (EXTI) via software on the EXTI line + * corresponding to a GPIO pin. + * + * Input Parameters: + * pinset - GPIO pin to trigger an EXTI on. + * + ****************************************************************************/ + +void at32_gpioswirq(uint32_t pinset); + +/**************************************************************************** + * Name: at32_exti_alarm + * + * Description: + * Sets/clears EXTI alarm interrupt. + * + * Input Parameters: + * - rising/falling edge: enables interrupt on rising/falling edges + * - event: generate event when set + * - func: when non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int at32_exti_alarm(bool risingedge, bool fallingedge, bool event, + xcpt_t func, void *arg); +#endif + +/**************************************************************************** + * Name: at32_exti_wakeup + * + * Description: + * Sets/clears EXTI wakeup interrupt. + * + * Input Parameters: + * - rising/falling edge: enables interrupt on rising/falling edges + * - event: generate event when set + * - func: when non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +int at32_exti_wakeup(bool risingedge, bool fallingedge, bool event, + xcpt_t func, void *arg); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_EXTI_H */ diff --git a/arch/arm/src/at32/at32_exti_alarm.c b/arch/arm/src/at32/at32_exti_alarm.c new file mode 100644 index 0000000000..e47de09b22 --- /dev/null +++ b/arch/arm/src/at32/at32_exti_alarm.c @@ -0,0 +1,138 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_exti_alarm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32_gpio.h" +#include "at32_exti.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Interrupt handlers attached to the ALARM EXTI */ + +static xcpt_t g_alarm_callback; +static void *g_callback_arg; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_exti_alarm_isr + * + * Description: + * EXTI ALARM interrupt service routine/dispatcher + * + ****************************************************************************/ + +static int at32_exti_alarm_isr(int irq, void *context, void *arg) +{ + int ret = OK; + + /* Clear the pending EXTI interrupt */ + + putreg32(EXTI_RTC_ALARM, AT32_EXTI_PR); + + /* And dispatch the interrupt to the handler */ + + if (g_alarm_callback) + { + ret = g_alarm_callback(irq, context, g_callback_arg); + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_exti_alarm + * + * Description: + * Sets/clears EXTI alarm interrupt. + * + * Input Parameters: + * - rising/falling edge: enables interrupt on rising/falling edge + * - event: generate event when set + * - func: when non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +int at32_exti_alarm(bool risingedge, bool fallingedge, bool event, + xcpt_t func, void *arg) +{ + g_alarm_callback = func; + g_callback_arg = arg; + + /* Install external interrupt handlers (if not already attached) */ + + if (func) + { + irq_attach(AT32_IRQ_RTCALRM, at32_exti_alarm_isr, NULL); + up_enable_irq(AT32_IRQ_RTCALRM); + } + else + { + up_disable_irq(AT32_IRQ_RTCALRM); + } + + /* Configure rising/falling edges */ + + modifyreg32(AT32_EXTI_RTSR, + risingedge ? 0 : EXTI_RTC_ALARM, + risingedge ? EXTI_RTC_ALARM : 0); + modifyreg32(AT32_EXTI_FTSR, + fallingedge ? 0 : EXTI_RTC_ALARM, + fallingedge ? EXTI_RTC_ALARM : 0); + + /* Enable Events and Interrupts */ + + modifyreg32(AT32_EXTI_EMR, + event ? 0 : EXTI_RTC_ALARM, + event ? EXTI_RTC_ALARM : 0); + modifyreg32(AT32_EXTI_IMR, + func ? 0 : EXTI_RTC_ALARM, + func ? EXTI_RTC_ALARM : 0); + + return OK; +} diff --git a/arch/arm/src/at32/at32_exti_gpio.c b/arch/arm/src/at32/at32_exti_gpio.c new file mode 100644 index 0000000000..e8398f0e81 --- /dev/null +++ b/arch/arm/src/at32/at32_exti_gpio.c @@ -0,0 +1,385 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_exti_gpio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32_gpio.h" +#include "at32_exti.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct gpio_callback_s +{ + xcpt_t callback; + void *arg; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Interrupt handlers attached to each EXTI */ + +static struct gpio_callback_s g_gpio_callbacks[16]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Interrupt Service Routines - Dispatchers + ****************************************************************************/ + +static int at32_exti0_isr(int irq, void *context, void *arg) +{ + int ret = OK; + + /* Clear the pending interrupt */ + + putreg32(0x0001, AT32_EXTI_PR); + + /* And dispatch the interrupt to the handler */ + + if (g_gpio_callbacks[0].callback != NULL) + { + xcpt_t callback = g_gpio_callbacks[0].callback; + void *cbarg = g_gpio_callbacks[0].arg; + + ret = callback(irq, context, cbarg); + } + + return ret; +} + +static int at32_exti1_isr(int irq, void *context, void *arg) +{ + int ret = OK; + + /* Clear the pending interrupt */ + + putreg32(0x0002, AT32_EXTI_PR); + + /* And dispatch the interrupt to the handler */ + + if (g_gpio_callbacks[1].callback != NULL) + { + xcpt_t callback = g_gpio_callbacks[1].callback; + void *cbarg = g_gpio_callbacks[1].arg; + + ret = callback(irq, context, cbarg); + } + + return ret; +} + +static int at32_exti2_isr(int irq, void *context, void *arg) +{ + int ret = OK; + + /* Clear the pending interrupt */ + + putreg32(0x0004, AT32_EXTI_PR); + + /* And dispatch the interrupt to the handler */ + + if (g_gpio_callbacks[2].callback != NULL) + { + xcpt_t callback = g_gpio_callbacks[2].callback; + void *cbarg = g_gpio_callbacks[2].arg; + + ret = callback(irq, context, cbarg); + } + + return ret; +} + +static int at32_exti3_isr(int irq, void *context, void * arg) +{ + int ret = OK; + + /* Clear the pending interrupt */ + + putreg32(0x0008, AT32_EXTI_PR); + + /* And dispatch the interrupt to the handler */ + + if (g_gpio_callbacks[3].callback != NULL) + { + xcpt_t callback = g_gpio_callbacks[3].callback; + void *cbarg = g_gpio_callbacks[3].arg; + + ret = callback(irq, context, cbarg); + } + + return ret; +} + +static int at32_exti4_isr(int irq, void *context, void *arg) +{ + int ret = OK; + + /* Clear the pending interrupt */ + + putreg32(0x0010, AT32_EXTI_PR); + + /* And dispatch the interrupt to the handler */ + + if (g_gpio_callbacks[4].callback != NULL) + { + xcpt_t callback = g_gpio_callbacks[4].callback; + void *cbarg = g_gpio_callbacks[4].arg; + + ret = callback(irq, context, cbarg); + } + + return ret; +} + +static int at32_exti_multiisr(int irq, void *context, void *arg, + int first, int last) +{ + uint32_t pr; + int pin; + int ret = OK; + + /* Examine the state of each pin in the group */ + + pr = getreg32(AT32_EXTI_PR); + + /* And dispatch the interrupt to the handler */ + + for (pin = first; pin <= last; pin++) + { + /* Is an interrupt pending on this pin? */ + + uint32_t mask = (1 << pin); + if ((pr & mask) != 0) + { + /* Clear the pending interrupt */ + + putreg32(mask, AT32_EXTI_PR); + + /* And dispatch the interrupt to the handler */ + + if (g_gpio_callbacks[pin].callback != NULL) + { + xcpt_t callback = g_gpio_callbacks[pin].callback; + void *cbarg = g_gpio_callbacks[pin].arg; + int tmp; + + tmp = callback(irq, context, cbarg); + if (tmp < 0) + { + ret = tmp; + } + } + } + } + + return ret; +} + +static int at32_exti95_isr(int irq, void *context, void *arg) +{ + return at32_exti_multiisr(irq, context, arg, 5, 9); +} + +static int at32_exti1510_isr(int irq, void *context, void *arg) +{ + return at32_exti_multiisr(irq, context, arg, 10, 15); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_gpiosetevent + * + * Description: + * Sets/clears GPIO based event and interrupt triggers. + * + * Input Parameters: + * - pinset: GPIO pin configuration + * - risingedge: Enables interrupt on rising edges + * - fallingedge: Enables interrupt on falling edges + * - event: Generate event when set + * - func: When non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +int at32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, + bool event, xcpt_t func, void *arg) +{ + struct gpio_callback_s *shared_cbs; + uint32_t pin = pinset & GPIO_PIN_MASK; + uint32_t exti = AT32_EXTI_BIT(pin); + int irq; + xcpt_t handler; + int nshared; + int i; + + /* Select the interrupt handler for this EXTI pin */ + + if (pin < 5) + { + irq = pin + AT32_IRQ_EXTI0; + nshared = 1; + shared_cbs = &g_gpio_callbacks[pin]; + switch (pin) + { + case 0: + handler = at32_exti0_isr; + break; + + case 1: + handler = at32_exti1_isr; + break; + + case 2: + handler = at32_exti2_isr; + break; + + case 3: + handler = at32_exti3_isr; + break; + + default: + handler = at32_exti4_isr; + break; + } + } + else if (pin < 10) + { + irq = AT32_IRQ_EXTI95; + handler = at32_exti95_isr; + shared_cbs = &g_gpio_callbacks[5]; + nshared = 5; + } + else + { + irq = AT32_IRQ_EXTI1510; + handler = at32_exti1510_isr; + shared_cbs = &g_gpio_callbacks[10]; + nshared = 6; + } + + /* Get the previous GPIO IRQ handler; Save the new IRQ handler. */ + + g_gpio_callbacks[pin].callback = func; + g_gpio_callbacks[pin].arg = arg; + + /* Install external interrupt handlers */ + + if (func) + { + irq_attach(irq, handler, NULL); + up_enable_irq(irq); + } + else + { + /* Only disable IRQ if shared handler does not have any active + * callbacks. + */ + + for (i = 0; i < nshared; i++) + { + if (shared_cbs[i].callback != NULL) + { + break; + } + } + + if (i == nshared) + { + up_disable_irq(irq); + } + } + + /* Configure GPIO, enable EXTI line enabled if event or interrupt is + * enabled. + */ + + if (event || func) + { + pinset |= GPIO_EXTI; + } + + at32_configgpio(pinset); + + /* Configure rising/falling edges */ + + modifyreg32(AT32_EXTI_RTSR, + risingedge ? 0 : exti, + risingedge ? exti : 0); + modifyreg32(AT32_EXTI_FTSR, + fallingedge ? 0 : exti, + fallingedge ? exti : 0); + + /* Enable Events and Interrupts */ + + modifyreg32(AT32_EXTI_EMR, + event ? 0 : exti, + event ? exti : 0); + modifyreg32(AT32_EXTI_IMR, + func ? 0 : exti, + func ? exti : 0); + + return OK; +} + +/**************************************************************************** + * Name: at32_gpioswirq + * + * Description: + * Trigger an extended interrupt (EXTI) via software on the EXTI line + * corresponding to a GPIO pin. + * + * Input Parameters: + * pinset - GPIO pin to trigger an EXTI on. + * + ****************************************************************************/ + +void at32_gpioswirq(uint32_t pinset) +{ + putreg32(1u << (pinset & GPIO_PIN_MASK), AT32_EXTI_SWIER); +} diff --git a/arch/arm/src/at32/at32_exti_pwr.c b/arch/arm/src/at32/at32_exti_pwr.c new file mode 100644 index 0000000000..a2a5575171 --- /dev/null +++ b/arch/arm/src/at32/at32_exti_pwr.c @@ -0,0 +1,145 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_exti_pwr.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32_gpio.h" +#include "at32_exti.h" +#include "at32_exti_pwr.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Interrupt handlers attached to the PVD EXTI */ + +static xcpt_t g_pvd_callback; +static void *g_callback_arg; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_exti_pvd_isr + * + * Description: + * EXTI PVD interrupt service routine/dispatcher + * + ****************************************************************************/ + +static int at32_exti_pvd_isr(int irq, void *context, void *arg) +{ + int ret = OK; + + /* Clear the pending EXTI interrupt */ + + putreg32(EXTI_PVD_LINE, AT32_EXTI_PR); + + /* And dispatch the interrupt to the handler */ + + if (g_pvd_callback != NULL) + { + ret = g_pvd_callback(irq, context, g_callback_arg); + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_exti_pvd + * + * Description: + * Sets/clears EXTI PVD interrupt. + * + * Input Parameters: + * - rising/falling edge: enables interrupt on rising/falling edge + * - event: generate event when set + * - func: when non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int at32_exti_pvd(bool risingedge, bool fallingedge, bool event, + xcpt_t func, void *arg) +{ + /* Get the previous GPIO IRQ handler; Save the new IRQ handler. */ + + g_pvd_callback = func; + g_callback_arg = arg; + + /* Install external interrupt handlers (if not already attached) */ + + if (func) + { + irq_attach(AT32_IRQ_PVD, at32_exti_pvd_isr, NULL); + up_enable_irq(AT32_IRQ_PVD); + } + else + { + up_disable_irq(AT32_IRQ_PVD); + } + + /* Configure rising/falling edges */ + + modifyreg32(AT32_EXTI_RTSR, + risingedge ? 0 : EXTI_PVD_LINE, + risingedge ? EXTI_PVD_LINE : 0); + modifyreg32(AT32_EXTI_FTSR, + fallingedge ? 0 : EXTI_PVD_LINE, + fallingedge ? EXTI_PVD_LINE : 0); + + /* Enable Events and Interrupts */ + + modifyreg32(AT32_EXTI_EMR, + event ? 0 : EXTI_PVD_LINE, + event ? EXTI_PVD_LINE : 0); + modifyreg32(AT32_EXTI_IMR, + func ? 0 : EXTI_PVD_LINE, + func ? EXTI_PVD_LINE : 0); + + return OK; +} diff --git a/arch/arm/src/at32/at32_exti_pwr.h b/arch/arm/src/at32/at32_exti_pwr.h new file mode 100644 index 0000000000..cbbce41ae8 --- /dev/null +++ b/arch/arm/src/at32/at32_exti_pwr.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_exti_pwr.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef AT32_EXTI_PWR_H_ +#define AT32_EXTI_PWR_H_ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_exti_pvd + * + * Description: + * Sets/clears EXTI PVD interrupt. + * + * Input Parameters: + * - rising/falling edge: enables interrupt on rising/falling edge + * - event: generate event when set + * - func: when non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int at32_exti_pvd(bool risingedge, bool fallingedge, bool event, + xcpt_t func, void *arg); + +#endif /* AT32_EXTI_PWR_H_ */ diff --git a/arch/arm/src/at32/at32_exti_wakeup.c b/arch/arm/src/at32/at32_exti_wakeup.c new file mode 100644 index 0000000000..0879ee96ce --- /dev/null +++ b/arch/arm/src/at32/at32_exti_wakeup.c @@ -0,0 +1,137 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_exti_wakeup.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32_gpio.h" +#include "at32_exti.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Interrupt handlers attached to the RTC WAKEUP EXTI */ + +static xcpt_t g_wakeup_callback; +static void *g_callback_arg; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_exti_wakeup_isr + * + * Description: + * EXTI periodic WAKEUP interrupt service routine/dispatcher + * + ****************************************************************************/ + +static int at32_exti_wakeup_isr(int irq, void *context, void *arg) +{ + int ret = OK; + + /* Dispatch the interrupt to the handler */ + + if (g_wakeup_callback != NULL) + { + ret = g_wakeup_callback(irq, context, g_callback_arg); + } + + /* Clear the pending EXTI interrupt */ + + putreg32(EXTI_RTC_WAKEUP, AT32_EXTI_PR); + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_exti_wakeup + * + * Description: + * Sets/clears EXTI wakeup interrupt. + * + * Input Parameters: + * - rising/falling edge: enables interrupt on rising/falling edges + * - event: generate event when set + * - func: when non-NULL, generate interrupt + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +int at32_exti_wakeup(bool risingedge, bool fallingedge, bool event, + xcpt_t func, void *arg) +{ + g_wakeup_callback = func; + g_callback_arg = arg; + + /* Install external interrupt handlers (if not already attached) */ + + if (func) + { + irq_attach(AT32_IRQ_RTC_WKUP, at32_exti_wakeup_isr, NULL); + up_enable_irq(AT32_IRQ_RTC_WKUP); + } + else + { + up_disable_irq(AT32_IRQ_RTC_WKUP); + } + + /* Configure rising/falling edges */ + + modifyreg32(AT32_EXTI_RTSR, + risingedge ? 0 : EXTI_RTC_WAKEUP, + risingedge ? EXTI_RTC_WAKEUP : 0); + modifyreg32(AT32_EXTI_FTSR, + fallingedge ? 0 : EXTI_RTC_WAKEUP, + fallingedge ? EXTI_RTC_WAKEUP : 0); + + /* Enable Events and Interrupts */ + + modifyreg32(AT32_EXTI_EMR, + event ? 0 : EXTI_RTC_WAKEUP, + event ? EXTI_RTC_WAKEUP : 0); + modifyreg32(AT32_EXTI_IMR, + func ? 0 : EXTI_RTC_WAKEUP, + func ? EXTI_RTC_WAKEUP : 0); + + return OK; +} diff --git a/arch/arm/src/at32/at32_flash.c b/arch/arm/src/at32/at32_flash.c new file mode 100644 index 0000000000..8a9179562f --- /dev/null +++ b/arch/arm/src/at32/at32_flash.c @@ -0,0 +1,41 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_flash.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Provides standard flash access functions, to be used by the flash mtd + * driver. The interface is defined in the include/nuttx/progmem.h + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/* Include the correct FLASH implementation for the selection AT32 part */ + +#if defined (CONFIG_AT32_AT32F43XX) +# include "at32f43xx_flash.c" +#else +# warning "No FLASH support for the selected part" +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ diff --git a/arch/arm/src/at32/at32_flash.h b/arch/arm/src/at32/at32_flash.h new file mode 100644 index 0000000000..bee270ac5e --- /dev/null +++ b/arch/arm/src/at32/at32_flash.h @@ -0,0 +1,90 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_flash.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_FLASH_H +#define __ARCH_ARM_SRC_AT32_AT32_FLASH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "chip.h" +#include "hardware/at32_flash.h" + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_eeprom_size + * + * Description: + * Get EEPROM data memory size + * + * Returned Value: + * Length of EEPROM memory region + * + ****************************************************************************/ + +size_t at32_eeprom_size(void); + +/**************************************************************************** + * Name: at32_eeprom_getaddress + * + * Description: + * Get EEPROM data memory address + * + * Returned Value: + * Address of EEPROM memory region + * + ****************************************************************************/ + +size_t at32_eeprom_getaddress(void); + +/**************************************************************************** + * Name: at32_eeprom_write + * + * Description: + * Write buffer to EEPROM data memory address + * + * Returned Value: + * Number of written bytes or error code. + * + ****************************************************************************/ + +ssize_t at32_eeprom_write(size_t addr, const void *buf, size_t buflen); + +/**************************************************************************** + * Name: at32_eeprom_erase + * + * Description: + * Erase memory on EEPROM data memory address + * + * Returned Value: + * Number of erased bytes or error code. + * + ****************************************************************************/ + +ssize_t at32_eeprom_erase(size_t addr, size_t eraselen); + +#endif /* __ARCH_ARM_SRC_AT32_AT32_FLASH_H */ diff --git a/arch/arm/src/at32/at32_gpio.c b/arch/arm/src/at32/at32_gpio.c new file mode 100644 index 0000000000..d5300b183e --- /dev/null +++ b/arch/arm/src/at32/at32_gpio.c @@ -0,0 +1,506 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_gpio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32_syscfg.h" +#include "at32_gpio.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Base addresses for each GPIO block */ + +const uint32_t g_gpiobase[AT32_NGPIO_PORTS] = +{ +#if AT32_NGPIO_PORTS > 0 + AT32_GPIOA_BASE, +#endif +#if AT32_NGPIO_PORTS > 1 + AT32_GPIOB_BASE, +#endif +#if AT32_NGPIO_PORTS > 2 + AT32_GPIOC_BASE, +#endif +#if AT32_NGPIO_PORTS > 3 + AT32_GPIOD_BASE, +#endif +#if AT32_NGPIO_PORTS > 4 + AT32_GPIOE_BASE, +#endif +#if AT32_NGPIO_PORTS > 5 + AT32_GPIOF_BASE, +#endif +#if AT32_NGPIO_PORTS > 6 + AT32_GPIOG_BASE, +#endif +#if AT32_NGPIO_PORTS > 7 + AT32_GPIOH_BASE, +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: at32_gpioremap + * + * Description: + * + * Based on configuration within the .config file, this function will + * remaps positions of alternative functions. + * + ****************************************************************************/ + +static inline void at32_gpioremap(void) +{ +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: at32_gpioinit + * + * Description: + * Based on configuration within the .config file, it does: + * - Remaps positions of alternative functions. + * + * Typically called from at32_start(). + * + * Assumptions: + * This function is called early in the initialization sequence so that + * no mutual exclusion is necessary. + * + ****************************************************************************/ + +void at32_gpioinit(void) +{ + /* Remap according to the configuration within .config file */ + + at32_gpioremap(); +} + +/**************************************************************************** + * Name: at32_configgpio + * + * Description: + * Configure a GPIO pin based on bit-encoded description of the pin. + * Once it is configured as Alternative (GPIO_ALT|GPIO_CNF_AFPP|...) + * function, it must be unconfigured with at32_unconfiggpio() with + * the same cfgset first before it can be set to non-alternative function. + * + * Returned Value: + * OK on success + * A negated errno value on invalid port, or when pin is locked as ALT + * function. + * + * To-Do: Auto Power Enable + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_configgpio (for the AT32F43xxx families). + ****************************************************************************/ + +#if defined(CONFIG_AT32_AT32F43XX) +int at32_configgpio(uint32_t cfgset) +{ + uintptr_t base; + uint32_t regval; + uint32_t setting; + uint32_t alt_setting; + unsigned int regoffset; + unsigned int port; + unsigned int pin; + unsigned int pos; + unsigned int pinmode; + irqstate_t flags; + + /* Verify that this hardware supports the select GPIO port */ + + port = (cfgset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + if (port >= AT32_NGPIO_PORTS) + { + return -EINVAL; + } + + /* Get the port base address */ + + base = g_gpiobase[port]; + + /* Get the pin number and select the port configuration register for that + * pin + */ + + pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + /* Set up the mode register (and remember whether the pin mode) */ + + switch (cfgset & GPIO_MODE_MASK) + { + default: + case GPIO_INPUT: /* Input mode */ + pinmode = GPIO_CFGR_INPUT; + break; + + case GPIO_OUTPUT: /* General purpose output mode */ + + /* Set the initial output value */ + + at32_gpiowrite(cfgset, (cfgset & GPIO_OUTPUT_SET) != 0); + pinmode = GPIO_CFGR_OUTPUT; + break; + + case GPIO_ALT: /* Alternate function mode */ + pinmode = GPIO_CFGR_AF; + break; + + case GPIO_ANALOG: /* Analog mode */ + pinmode = GPIO_CFGR_ANALOG; + break; + } + + /* Interrupts must be disabled from here on out so that we have mutually + * exclusive access to all of the GPIO configuration registers. + */ + + flags = enter_critical_section(); + + /* Determine the alternate function (Only alternate function pins) */ + + if (pinmode == GPIO_CFGR_AF) + { + alt_setting = (cfgset & GPIO_AF_MASK) >> GPIO_AF_SHIFT; + } + else + { + alt_setting = 0; + } + + /* Set the alternate function (Only alternate function pins) + * This is done before configuring the Outputs on a change to + * an Alternate function. + */ + + if (alt_setting != 0) + { + if (pin < 8) + { + regoffset = AT32_GPIO_MUXL_OFFSET; + pos = pin; + } + else + { + regoffset = AT32_GPIO_MUXH_OFFSET; + pos = pin - 8; + } + + regval = getreg32(base + regoffset); + regval &= ~GPIO_MUX_MASK(pos); + regval |= (alt_setting << GPIO_MUX_SHIFT(pos)); + putreg32(regval, base + regoffset); + } + + /* Now apply the configuration to the mode register */ + + regval = getreg32(base + AT32_GPIO_CFGR_OFFSET); + regval &= ~GPIO_CFGR_MASK(pin); + regval |= ((uint32_t)pinmode << GPIO_CFGR_SHIFT(pin)); + putreg32(regval, base + AT32_GPIO_CFGR_OFFSET); + + /* Set up the pull-up/pull-down configuration (all but analog pins) */ + + setting = GPIO_PULL_NONE; + if (pinmode != GPIO_CFGR_ANALOG) + { + switch (cfgset & GPIO_PUPD_MASK) + { + default: + case GPIO_FLOAT: /* No pull-up, pull-down */ + break; + + case GPIO_PULLUP: /* Pull-up */ + setting = GPIO_PULL_PULLUP; + break; + + case GPIO_PULLDOWN: /* Pull-down */ + setting = GPIO_PULL_PULLDOWN; + break; + } + } + + regval = getreg32(base + AT32_GPIO_PULL_OFFSET); + regval &= ~GPIO_PULL_MASK(pin); + regval |= (setting << GPIO_PULL_SHIFT(pin)); + putreg32(regval, base + AT32_GPIO_PULL_OFFSET); + + /* Set the alternate function (Only alternate function pins) + * This is done after configuring the the pin's connection + * on a change away from an Alternate function. + */ + + if (alt_setting == 0) + { + if (pin < 8) + { + regoffset = AT32_GPIO_MUXL_OFFSET; + pos = pin; + } + else + { + regoffset = AT32_GPIO_MUXH_OFFSET; + pos = pin - 8; + } + + regval = getreg32(base + regoffset); + regval &= ~GPIO_MUX_MASK(pos); + regval |= (alt_setting << GPIO_MUX_SHIFT(pos)); + putreg32(regval, base + regoffset); + } + + /* Set drive capability */ + + if (pinmode == GPIO_CFGR_OUTPUT || pinmode == GPIO_CFGR_AF) + { + switch (cfgset & GPIO_DRV_MASK) + { + case GPIO_DRV_STRONG: + setting = GPIO_ODRVR_STRONG; + break; + + case GPIO_DRV_MODETATE: + setting = GPIO_ODRVR_MODERATE; + break; + } + } + else + { + setting = 0; + } + + regval = getreg32(base + AT32_GPIO_ODRVR_OFFSET); + regval &= ~GPIO_ODRVR_MASK(pin); + regval |= (setting << GPIO_ODRVR_SHIFT(pin)); + putreg32(regval, base + AT32_GPIO_ODRVR_OFFSET); + + /* Set push-pull/open-drain (Only outputs and alternate function pins) */ + + regval = getreg32(base + AT32_GPIO_OMODER_OFFSET); + setting = GPIO_OMODER_OD(pin); + + if ((pinmode == GPIO_CFGR_OUTPUT || pinmode == GPIO_CFGR_AF) && + (cfgset & GPIO_OPENDRAIN) != 0) + { + regval |= setting; + } + else + { + regval &= ~setting; + } + + putreg32(regval, base + AT32_GPIO_OMODER_OFFSET); + + /* Otherwise, it is an input pin. Should it configured as an EXTI + * interrupt? + */ + + if (pinmode != GPIO_CFGR_OUTPUT && (cfgset & GPIO_EXTI) != 0) + { + uint32_t regaddr; + int shift; + + /* Set the bits in the SYSCFG EXTICR register */ + + regaddr = AT32_SCFG_EXTICR(pin); + regval = getreg32(regaddr); + shift = SCFG_EXINTCR_EXTI_SHIFT(pin); + regval &= ~(SCFG_EXINTCR_PORT_MASK << shift); + regval |= (((uint32_t)port) << shift); + + putreg32(regval, regaddr); + } + + leave_critical_section(flags); + return OK; +} +#endif + +/**************************************************************************** + * Name: at32_unconfiggpio + * + * Description: + * Unconfigure a GPIO pin based on bit-encoded description of the pin, set + * it into default HiZ state (and possibly mark it's unused) and unlock it + * whether it was previously selected as an alternative function + * (GPIO_ALT | GPIO_CNF_AFPP | ...). + * + * This is a safety function and prevents hardware from shocks, as + * unexpected write to the Timer Channel Output GPIO to fixed '1' or '0' + * while it should operate in PWM mode could produce excessive on-board + * currents and trigger over-current/alarm function. + * + * Returned Value: + * OK on success + * A negated errno value on invalid port + * + * To-Do: Auto Power Disable + ****************************************************************************/ + +int at32_unconfiggpio(uint32_t cfgset) +{ + /* Reuse port and pin number and set it to default HiZ INPUT */ + + cfgset &= GPIO_PORT_MASK | GPIO_PIN_MASK; + +#if defined(CONFIG_AT32_AT32F43XX) + cfgset |= GPIO_INPUT | GPIO_FLOAT; +#else +# error "Unsupported AT32 chip" +#endif + + /* To-Do: Mark its unuse for automatic power saving options */ + + return at32_configgpio(cfgset); +} + +/**************************************************************************** + * Name: at32_gpiowrite + * + * Description: + * Write one or zero to the selected GPIO pin + * + ****************************************************************************/ + +void at32_gpiowrite(uint32_t pinset, bool value) +{ + uint32_t base; + +#if defined(CONFIG_AT32_AT32F43XX) + uint32_t bit; +#endif + unsigned int port; + unsigned int pin; + + port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + if (port < AT32_NGPIO_PORTS) + { + /* Get the port base address */ + + base = g_gpiobase[port]; + + /* Get the pin number */ + + pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + /* Set or clear the output on the pin */ + +#if defined(CONFIG_AT32_AT32F43XX) + + if (value) + { + bit = GPIO_SCR_SET(pin); + } + else + { + bit = GPIO_SCR_RESET(pin); + } + + putreg32(bit, base + AT32_GPIO_SCR_OFFSET); + +#else +# error "Unsupported AT32 chip" +#endif + } +} + +/**************************************************************************** + * Name: at32_gpioread + * + * Description: + * Read one or zero from the selected GPIO pin + * + ****************************************************************************/ + +bool at32_gpioread(uint32_t pinset) +{ + uint32_t base; + unsigned int port; + unsigned int pin; + + port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + if (port < AT32_NGPIO_PORTS) + { + /* Get the port base address */ + + base = g_gpiobase[port]; + + /* Get the pin number and return the input state of that pin */ + + pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + return ((getreg32(base + AT32_GPIO_IDT_OFFSET) & (1 << pin)) != 0); + } + + return 0; +} + +/**************************************************************************** + * Name: at32_iocompensation + * + * Description: + * Enable I/O compensation. + * + * By default the I/O compensation cell is not used. However when the I/O + * output buffer speed is configured in 50 MHz or 100 MHz mode, it is + * recommended to use the compensation cell for slew rate control on I/O + * tf(IO)out)/tr(IO)out commutation to reduce the I/O noise on power + * supply. + * + * The I/O compensation cell can be used only when the supply voltage + * ranges from 2.4 to 3.6 V. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_HAVE_IOCOMPENSATION +void at32_iocompensation(void) +{ +} +#endif diff --git a/arch/arm/src/at32/at32_gpio.h b/arch/arm/src/at32/at32_gpio.h new file mode 100644 index 0000000000..f500fa9890 --- /dev/null +++ b/arch/arm/src/at32/at32_gpio.h @@ -0,0 +1,392 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_gpio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_GPIO_H +#define __ARCH_ARM_SRC_AT32_AT32_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +# include +#endif + +#include + +#include "chip.h" + +#if defined(CONFIG_AT32_AT32F43XX) +# include "hardware/at32f43xxx_gpio.h" +#else +# error "Unrecognized AT32 chip" +#endif + +/**************************************************************************** + * Pre-Processor Declarations + ****************************************************************************/ + +/* Bit-encoded input to at32_configgpio() */ + +#if defined(CONFIG_AT32_AT32F43XX) +/* Each port bit of the general-purpose I/O (GPIO) ports can be + * individually configured by software in several modes: + * + * - Input floating + * - Input pull-up + * - Input-pull-down + * - Output open-drain with pull-up or pull-down capability + * - Output push-pull with pull-up or pull-down capability + * - Alternate function push-pull with pull-up or pull-down capability + * - Alternate function open-drain with pull-up or pull-down capability + * - Analog + * + * 20-bit Encoding: 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * Inputs: MMUU .... ...X PPPP BBBB + * Outputs: MMUU .... FFOV PPPP BBBB + * Alternate Functions: MMUU AAAA FFO. PPPP BBBB + * Analog: MM.. .... .... PPPP BBBB + */ + +/* Mode: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * MM.. .... .... .... .... + */ + +#define GPIO_MODE_SHIFT (18) /* Bits 18-19: GPIO port mode */ +#define GPIO_MODE_MASK (3 << GPIO_MODE_SHIFT) +# define GPIO_INPUT (0 << GPIO_MODE_SHIFT) /* Input mode */ +# define GPIO_OUTPUT (1 << GPIO_MODE_SHIFT) /* General purpose output mode */ +# define GPIO_ALT (2 << GPIO_MODE_SHIFT) /* Alternate function mode */ +# define GPIO_ANALOG (3 << GPIO_MODE_SHIFT) /* Analog mode */ + +/* Input/output pull-ups/downs (not used with analog): + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * ..UU .... .... .... .... + */ + +#define GPIO_PUPD_SHIFT (16) /* Bits 16-17: Pull-up/pull down */ +#define GPIO_PUPD_MASK (3 << GPIO_PUPD_SHIFT) +# define GPIO_FLOAT (0 << GPIO_PUPD_SHIFT) /* No pull-up, pull-down */ +# define GPIO_PULLUP (1 << GPIO_PUPD_SHIFT) /* Pull-up */ +# define GPIO_PULLDOWN (2 << GPIO_PUPD_SHIFT) /* Pull-down */ + +/* Alternate Functions: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... AAAA .... .... .... + */ + +#define GPIO_AF_SHIFT (12) /* Bits 12-15: Alternate function */ +#define GPIO_AF_MASK (15 << GPIO_AF_SHIFT) +# define GPIO_AF(n) ((n) << GPIO_AF_SHIFT) +# define GPIO_AF0 (0 << GPIO_AF_SHIFT) +# define GPIO_AF1 (1 << GPIO_AF_SHIFT) +# define GPIO_AF2 (2 << GPIO_AF_SHIFT) +# define GPIO_AF3 (3 << GPIO_AF_SHIFT) +# define GPIO_AF4 (4 << GPIO_AF_SHIFT) +# define GPIO_AF5 (5 << GPIO_AF_SHIFT) +# define GPIO_AF6 (6 << GPIO_AF_SHIFT) +# define GPIO_AF7 (7 << GPIO_AF_SHIFT) +# define GPIO_AF8 (8 << GPIO_AF_SHIFT) +# define GPIO_AF9 (9 << GPIO_AF_SHIFT) +# define GPIO_AF10 (10 << GPIO_AF_SHIFT) +# define GPIO_AF11 (11 << GPIO_AF_SHIFT) +# define GPIO_AF12 (12 << GPIO_AF_SHIFT) +# define GPIO_AF13 (13 << GPIO_AF_SHIFT) +# define GPIO_AF14 (14 << GPIO_AF_SHIFT) +# define GPIO_AF15 (15 << GPIO_AF_SHIFT) + +/* Output/Alt function drive selection: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... FF.. .... .... + */ + +#define GPIO_DRV_SHIFT (10) +#define GPIO_DRV_MASK (3 << GPIO_DRV_SHIFT) + +#define GPIO_DRV_STRONG (1 << GPIO_DRV_SHIFT) +#define GPIO_DRV_MODETATE (0 << GPIO_DRV_SHIFT) + +/* Output/Alt function type selection: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... ..O. .... .... + */ + +#define GPIO_OPENDRAIN (1 << 9) /* Bit9: 1=Open-drain output */ +#define GPIO_PUSHPULL (0) /* Bit9: 0=Push-pull output */ + +/* If the pin is a GPIO digital output, then this identifies the initial + * output value. If the pin is an input, this bit is overloaded to + * provide the qualifier to distinguish input pull-up and -down: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... ...V .... .... + */ + +#define GPIO_OUTPUT_SET (1 << 8) /* Bit 8: If output, initial value of output */ +#define GPIO_OUTPUT_CLEAR (0) + +/* External interrupt selection (GPIO inputs only): + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... ...X .... .... + */ + +#define GPIO_EXTI (1 << 8) /* Bit 8: Configure as EXTI interrupt */ + +/* This identifies the GPIO port: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... .... PPPP .... + */ + +#define GPIO_PORT_SHIFT (4) /* Bit 4-7: Port number */ +#define GPIO_PORT_MASK (15 << GPIO_PORT_SHIFT) +# define GPIO_PORTA (0 << GPIO_PORT_SHIFT) /* GPIOA */ +# define GPIO_PORTB (1 << GPIO_PORT_SHIFT) /* GPIOB */ +# define GPIO_PORTC (2 << GPIO_PORT_SHIFT) /* GPIOC */ +# define GPIO_PORTD (3 << GPIO_PORT_SHIFT) /* GPIOD */ +# define GPIO_PORTE (4 << GPIO_PORT_SHIFT) /* GPIOE */ +# define GPIO_PORTF (5 << GPIO_PORT_SHIFT) /* GPIOF */ +# define GPIO_PORTG (6 << GPIO_PORT_SHIFT) /* GPIOG */ +# define GPIO_PORTH (7 << GPIO_PORT_SHIFT) /* GPIOH */ + +/* This identifies the bit in the port: + * + * 1111 1111 1100 0000 0000 + * 9876 5432 1098 7654 3210 + * ---- ---- ---- ---- ---- + * .... .... .... .... BBBB + */ + +#define GPIO_PIN_SHIFT (0) /* Bits 0-3: GPIO number: 0-15 */ +#define GPIO_PIN_MASK (15 << GPIO_PIN_SHIFT) +# define GPIO_PIN0 (0 << GPIO_PIN_SHIFT) +# define GPIO_PIN1 (1 << GPIO_PIN_SHIFT) +# define GPIO_PIN2 (2 << GPIO_PIN_SHIFT) +# define GPIO_PIN3 (3 << GPIO_PIN_SHIFT) +# define GPIO_PIN4 (4 << GPIO_PIN_SHIFT) +# define GPIO_PIN5 (5 << GPIO_PIN_SHIFT) +# define GPIO_PIN6 (6 << GPIO_PIN_SHIFT) +# define GPIO_PIN7 (7 << GPIO_PIN_SHIFT) +# define GPIO_PIN8 (8 << GPIO_PIN_SHIFT) +# define GPIO_PIN9 (9 << GPIO_PIN_SHIFT) +# define GPIO_PIN10 (10 << GPIO_PIN_SHIFT) +# define GPIO_PIN11 (11 << GPIO_PIN_SHIFT) +# define GPIO_PIN12 (12 << GPIO_PIN_SHIFT) +# define GPIO_PIN13 (13 << GPIO_PIN_SHIFT) +# define GPIO_PIN14 (14 << GPIO_PIN_SHIFT) +# define GPIO_PIN15 (15 << GPIO_PIN_SHIFT) + +#else +# error "Unrecognized AT32 chip" +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* Base addresses for each GPIO block */ + +EXTERN const uint32_t g_gpiobase[AT32_NGPIO_PORTS]; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_configgpio + * + * Description: + * Configure a GPIO pin based on bit-encoded description of the pin. + * Once it is configured as Alternative (GPIO_ALT|GPIO_CNF_AFPP|...) + * function, it must be unconfigured with at32_unconfiggpio() with + * the same cfgset first before it can be set to non-alternative function. + * + * Returned Value: + * OK on success + * ERROR on invalid port, or when pin is locked as ALT function. + * + ****************************************************************************/ + +int at32_configgpio(uint32_t cfgset); + +/**************************************************************************** + * Name: at32_unconfiggpio + * + * Description: + * Unconfigure a GPIO pin based on bit-encoded description of the pin, set + * it into default HiZ state (and possibly mark it's unused) and unlock it + * whether it was previously selected as alternative function + * (GPIO_ALT|GPIO_CNF_AFPP|...). + * + * This is a safety function and prevents hardware from shocks, as + * unexpected write to the Timer Channel Output GPIO to fixed '1' or '0' + * while it should operate in PWM mode could produce excessive on-board + * currents and trigger over-current/alarm function. + * + * Returned Value: + * OK on success + * ERROR on invalid port + * + ****************************************************************************/ + +int at32_unconfiggpio(uint32_t cfgset); + +/**************************************************************************** + * Name: at32_gpiowrite + * + * Description: + * Write one or zero to the selected GPIO pin + * + ****************************************************************************/ + +void at32_gpiowrite(uint32_t pinset, bool value); + +/**************************************************************************** + * Name: at32_gpioread + * + * Description: + * Read one or zero from the selected GPIO pin + * + ****************************************************************************/ + +bool at32_gpioread(uint32_t pinset); + +/**************************************************************************** + * Name: at32_iocompensation + * + * Description: + * Enable I/O compensation. + * + * By default the I/O compensation cell is not used. However when the I/O + * output buffer speed is configured in 50 MHz or 100 MHz mode, it is + * recommended to use the compensation cell for slew rate control on I/O + * tf(IO)out)/tr(IO)out commutation to reduce the I/O noise on power + * supply. + * + * The I/O compensation cell can be used only when the supply voltage + * ranges from 2.4 to 3.6 V. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_HAVE_IOCOMPENSATION +void at32_iocompensation(void); +#endif + +/**************************************************************************** + * Name: at32_gpiosetevent + * + * Description: + * Sets/clears GPIO based event and interrupt triggers. + * + * Input Parameters: + * - pinset: gpio pin configuration + * - rising/falling edge: enables + * - event: generate event when set + * - func: when non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +int at32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, + bool event, xcpt_t func, void *arg); + +/**************************************************************************** + * Function: at32_dumpgpio + * + * Description: + * Dump all GPIO registers associated with the provided base address + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_FEATURES +int at32_dumpgpio(uint32_t pinset, const char *msg); +#else +# define at32_dumpgpio(p,m) +#endif + +/**************************************************************************** + * Function: at32_gpioinit + * + * Description: + * Based on configuration within the .config file, it does: + * - Remaps positions of alternative functions. + * + * Typically called from at32_start(). + * + ****************************************************************************/ + +void at32_gpioinit(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_GPIO_H */ diff --git a/arch/arm/src/at32/at32_i2c.c b/arch/arm/src/at32/at32_i2c.c new file mode 100644 index 0000000000..d35edcf80c --- /dev/null +++ b/arch/arm/src/at32/at32_i2c.c @@ -0,0 +1,2700 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_i2c.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* -------------------------------------------------------------------------- + * + * AT32 I2C Driver + * + * Supports: + * - Master operation: + * Standard-mode (up to 100 kHz) + * Fast-mode (up to 400 kHz) + * Fast-mode Plus (up to 1 MHz) + * fI2CCLK clock source selection is based on APB1 + * default is 144MHz + * + * - Multiple instances (shared bus) + * - Interrupt based operation + * - RELOAD support + * + * Unsupported, possible future work: + * - More effective error reporting to higher layers + * - Slave operation + * - Support of fI2CCLK frequencies other than 8Mhz + * - Polled operation (code present but untested) + * - SMBus support + * - Multi-master support + * - IPMI + * + * + * Implementation: + * + * - Device: structure as defined by the nuttx/i2c/i2c.h + * + * - Instance: represents each individual access to the I2C driver, obtained + * by the i2c_init(); it extends the Device structure from the + * nuttx/i2c/i2c.h; Instance points to OPS, to common I2C Hardware + * private data and contains its own private data including frequency, + * address and mode of operation. + * + * - Private: Private data of an I2C Hardware + * + * High Level Functional Description + * + * This driver works with I2C "messages" (struct i2c_msg_s), which carry a + * buffer intended to transfer data to, or store data read from, the I2C bus. + * + * As the hardware can only transmit or receive one byte at a time the basic + * job of the driver (and the ISR specifically) is to process each message in + * the order they are stored in the message list, one byte at a time. When + * no messages are left the ISR exits and returns the result to the caller. + * + * The order of the list of I2C messages provided to the driver is important + * and dependent upon the hardware in use. A typical I2C transaction between + * the F3 as an I2C Master and some other IC as a I2C Slave requires two + * messages that communicate the: + * + * 1) Subaddress (register offset on the slave device) + * 2) Data sent to or read from the device + * + * These messages will typically be one byte in length but may be up to 2^31 + * bytes in length. Incidentally, the maximum length is limited only because + * i2c_msg_s.length is a signed int for some odd reason. + * + * Interrupt mode relies on the following interrupt events: + * + * TXIS - Transmit interrupt + * (data transmitted to bus and acknowledged) + * NACKF - Not Acknowledge Received + * (data transmitted to bus and NOT acknowledged) + * RXNE - Receive interrupt + * (data received from bus) + * TC - Transfer Complete + * (All bytes in message transferred) + * TCR - Transfer Complete (Reload) + * (Current batch of bytes in message transferred) + * + * The driver currently supports Single Master mode only. Slave mode is not + * supported. Additionally, the driver runs in Software End Mode (AUTOEND + * disabled) so the driver is responsible for telling the hardware what to + * do at the end of a transfer. + * + * -------------------------------------------------------------------------- + * + * Configuration: + * + * To use this driver, enable the following configuration variable: + * + * CONFIG_AT32_I2C1 + * CONFIG_AT32_I2C2 + * CONFIG_AT32_I2C3 + * + * To configure the ISR timeout using fixed values + * (CONFIG_AT32_I2C_DYNTIMEO=n): + * + * CONFIG_AT32_I2CTIMEOSEC (Timeout in seconds) + * CONFIG_AT32_I2CTIMEOMS (Timeout in milliseconds) + * CONFIG_AT32_I2CTIMEOTICKS (Timeout in ticks) + * + * To configure the ISR timeout using dynamic values + * (CONFIG_AT32_I2C_DYNTIMEO=y): + * + * CONFIG_AT32_I2C_DYNTIMEO_USECPERBYTE + * (Timeout in microseconds per byte) + * CONFIG_AT32_I2C_DYNTIMEO_STARTSTOP + * (Timeout for start/stop in milliseconds) + * + * Debugging output enabled with: + * + * CONFIG_DEBUG_FEATURES and CONFIG_DEBUG_I2C_{ERROR|WARN|INFO} + * + * ISR Debugging output may be enabled with: + * + * CONFIG_DEBUG_FEATURES and CONFIG_DEBUG_I2C_INFO + * + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "arm_internal.h" +#include "at32_rcc.h" +#include "at32_i2c.h" +#include "at32_gpio.h" + +/* At least one I2C peripheral must be enabled */ + +#if defined(CONFIG_AT32_I2C1) || defined(CONFIG_AT32_I2C2) || defined(CONFIG_AT32_I2C3) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used. + * Instead, CPU-intensive polling will be used. + */ + +/* Interrupt wait timeout in seconds and milliseconds */ + +#if !defined(CONFIG_AT32_I2CTIMEOSEC) && !defined(CONFIG_AT32_I2CTIMEOMS) +# define CONFIG_AT32_I2CTIMEOSEC 0 +# define CONFIG_AT32_I2CTIMEOMS 500 /* Default is 500 milliseconds */ +# warning "Using Default 500 Ms Timeout" +#elif !defined(CONFIG_AT32_I2CTIMEOSEC) +# define CONFIG_AT32_I2CTIMEOSEC 0 /* User provided milliseconds */ +#elif !defined(CONFIG_AT32_I2CTIMEOMS) +# define CONFIG_AT32_I2CTIMEOMS 0 /* User provided seconds */ +#endif + +/* Interrupt wait time timeout in system timer ticks */ + +#ifndef CONFIG_AT32_I2CTIMEOTICKS +# define CONFIG_AT32_I2CTIMEOTICKS \ + (SEC2TICK(CONFIG_AT32_I2CTIMEOSEC) + MSEC2TICK(CONFIG_AT32_I2CTIMEOMS)) +#endif + +#ifndef CONFIG_AT32_I2C_DYNTIMEO_STARTSTOP +# define CONFIG_AT32_I2C_DYNTIMEO_STARTSTOP TICK2USEC(CONFIG_AT32_I2CTIMEOTICKS) +#endif + +/* Macros to convert a I2C pin to a GPIO output */ + +#define I2C_OUTPUT (GPIO_OUTPUT | GPIO_FLOAT | GPIO_OPENDRAIN |\ + GPIO_DRV_MODETATE | GPIO_OUTPUT_SET) + +#define MKI2C_OUTPUT(p) (((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT) + +#define I2C_CR1_TXRX (I2C_CR1_RXIE | I2C_CR1_TXIE) +#define I2C_CR1_ALLINTS (I2C_CR1_TXRX | I2C_CR1_TCIE | I2C_CR1_ERRIE) + +/* Unused bit in I2c_ISR used to communicate a bad state has occurred in + * the isr processing + */ + +#define I2C_INT_BAD_STATE 0x8000000 + +/* I2C event tracing + * + * To enable tracing statements which show the details of the state machine + * enable the following configuration variable: + * + * CONFIG_I2C_TRACE + * + * Note: This facility uses syslog, which sends output to the console by + * default. No other debug configuration variables are required. + */ + +#ifndef CONFIG_I2C_TRACE +# define at32_i2c_tracereset(p) +# define at32_i2c_tracenew(p,s) +# define at32_i2c_traceevent(p,e,a) +# define at32_i2c_tracedump(p) +#endif + +#ifndef CONFIG_I2C_NTRACE +# define CONFIG_I2C_NTRACE 32 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Interrupt state */ + +enum at32_intstate_e +{ + INTSTATE_IDLE = 0, /* No I2C activity */ + INTSTATE_WAITING, /* Waiting for completion of interrupt activity */ + INTSTATE_DONE, /* Interrupt activity complete */ +}; + +/* Trace events */ + +enum at32_trace_e +{ + I2CEVENT_NONE = 0, + I2CEVENT_STATE_ERROR, + I2CEVENT_ISR_SHUTDOWN, + I2CEVENT_ISR_CALL, + I2CEVENT_ISR_EMPTY_CALL, + I2CEVENT_MSG_HANDLING, + I2CEVENT_POLL_NOT_READY, + I2CEVENT_EMPTY_MSG, + I2CEVENT_START, + I2CEVENT_ADDRESS_ACKED, + I2CEVENT_ADDRESS_NACKED, + I2CEVENT_NACK, + I2CEVENT_READ, + I2CEVENT_READ_ERROR, + I2CEVENT_WRITE_TO_DR, + I2CEVENT_WRITE_STOP, + I2CEVENT_WRITE_RESTART, + I2CEVENT_WRITE_NO_RESTART, + I2CEVENT_WRITE_ERROR, + I2CEVENT_WRITE_FLAG_ERROR, + I2CEVENT_TC_RESTART, + I2CEVENT_TC_NO_RESTART +}; + +/* Trace data */ + +struct at32_trace_s +{ + uint32_t status; /* I2C 32-bit SR2|SR1 status */ + uint32_t count; /* Interrupt count when status change */ + enum at32_intstate_e event; /* Last event that occurred with this status */ + uint32_t parm; /* Parameter associated with the event */ + clock_t time; /* First of event or first status */ +}; + +/* I2C Device hardware configuration */ + +struct at32_i2c_config_s +{ + uint32_t base; /* I2C base address */ + uint32_t clk_bit; /* Clock enable bit */ + uint32_t reset_bit; /* Reset bit */ + uint32_t scl_pin; /* GPIO configuration for SCL as SCL */ + uint32_t sda_pin; /* GPIO configuration for SDA as SDA */ +#ifndef CONFIG_I2C_POLLED + uint32_t ev_irq; /* Event IRQ */ + uint32_t er_irq; /* Error IRQ */ +#endif +}; + +/* I2C Device Private Data */ + +struct at32_i2c_priv_s +{ + /* Port configuration */ + + const struct at32_i2c_config_s *config; + + int refs; /* Reference count */ + mutex_t lock; /* Mutual exclusion mutex */ +#ifndef CONFIG_I2C_POLLED + sem_t sem_isr; /* Interrupt wait semaphore */ +#endif + volatile uint8_t intstate; /* Interrupt handshake (see enum at32_intstate_e) */ + + uint8_t msgc; /* Message count */ + struct i2c_msg_s *msgv; /* Message list */ + uint8_t *ptr; /* Current message buffer */ + uint32_t frequency; /* Current I2C frequency */ + int dcnt; /* Current message bytes remaining to transfer */ + uint16_t flags; /* Current message flags */ + bool astart; /* START sent */ + + /* I2C trace support */ + +#ifdef CONFIG_I2C_TRACE + int tndx; /* Trace array index */ + clock_t start_time; /* Time when the trace was started */ + + /* The actual trace data */ + + struct at32_trace_s trace[CONFIG_I2C_NTRACE]; +#endif + + uint32_t status; /* End of transfer SR2|SR1 status */ + +#ifdef CONFIG_PM + struct pm_callback_s pm_cb; /* PM callbacks */ +#endif +}; + +/* I2C Device, Instance */ + +struct at32_i2c_inst_s +{ + const struct i2c_ops_s *ops; /* Standard I2C operations */ + struct at32_i2c_priv_s *priv; /* Common driver private data structure */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline uint16_t at32_i2c_getreg(struct at32_i2c_priv_s *priv, + uint8_t offset); +static inline void at32_i2c_putreg(struct at32_i2c_priv_s *priv, + uint8_t offset, uint16_t value); +static inline void at32_i2c_putreg32(struct at32_i2c_priv_s *priv, + uint8_t offset, uint32_t value); +static inline void at32_i2c_modifyreg32(struct at32_i2c_priv_s *priv, + uint8_t offset, uint32_t clearbits, + uint32_t setbits); +#ifdef CONFIG_AT32_I2C_DYNTIMEO +static uint32_t at32_i2c_toticks(int msgc, struct i2c_msg_s *msgs); +#endif /* CONFIG_AT32_I2C_DYNTIMEO */ +static inline int at32_i2c_sem_waitdone(struct at32_i2c_priv_s *priv); +static inline void at32_i2c_sem_waitstop(struct at32_i2c_priv_s *priv); +#ifdef CONFIG_I2C_TRACE +static void at32_i2c_tracereset(struct at32_i2c_priv_s *priv); +static void at32_i2c_tracenew(struct at32_i2c_priv_s *priv, + uint32_t status); +static void at32_i2c_traceevent(struct at32_i2c_priv_s *priv, + enum at32_trace_e event, uint32_t parm); +static void at32_i2c_tracedump(struct at32_i2c_priv_s *priv); +#endif /* CONFIG_I2C_TRACE */ +static void at32_i2c_setclock(struct at32_i2c_priv_s *priv, + uint32_t frequency); +static inline void at32_i2c_sendstart(struct at32_i2c_priv_s *priv); +static inline void at32_i2c_sendstop(struct at32_i2c_priv_s *priv); +static inline +uint32_t at32_i2c_getstatus(struct at32_i2c_priv_s *priv); +static int at32_i2c_isr_process(struct at32_i2c_priv_s *priv); +#ifndef CONFIG_I2C_POLLED +static int at32_i2c_isr(int irq, void *context, void *arg); +#endif +static int at32_i2c_init(struct at32_i2c_priv_s *priv); +static int at32_i2c_deinit(struct at32_i2c_priv_s *priv); + +static int at32_i2c_process(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, int count); +static int at32_i2c_transfer(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int at32_i2c_reset(struct i2c_master_s *dev); +#endif +#ifdef CONFIG_PM +static int at32_i2c_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_AT32_I2C1 +static const struct at32_i2c_config_s at32_i2c1_config = +{ + .base = AT32_I2C1_BASE, + .clk_bit = CRM_APB1EN_I2C1EN, + .reset_bit = CRM_APB1RST_I2C1RST, + .scl_pin = GPIO_I2C1_SCL, + .sda_pin = GPIO_I2C1_SDA, +#ifndef CONFIG_I2C_POLLED + .ev_irq = AT32_IRQ_I2C1EV, + .er_irq = AT32_IRQ_I2C1ER +#endif +}; + +static struct at32_i2c_priv_s at32_i2c1_priv = +{ + .config = &at32_i2c1_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .frequency = 0, + .dcnt = 0, + .flags = 0, + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = at32_i2c_pm_prepare, +#endif +}; +#endif + +#ifdef CONFIG_AT32_I2C2 +static const struct at32_i2c_config_s at32_i2c2_config = +{ + .base = AT32_I2C2_BASE, + .clk_bit = CRM_APB1EN_I2C2EN, + .reset_bit = CRM_APB1RST_I2C1RST, + .scl_pin = GPIO_I2C2_SCL, + .sda_pin = GPIO_I2C2_SDA, +#ifndef CONFIG_I2C_POLLED + .ev_irq = AT32_IRQ_I2C2EV, + .er_irq = AT32_IRQ_I2C2ER +#endif +}; + +static struct at32_i2c_priv_s at32_i2c2_priv = +{ + .config = &at32_i2c2_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .frequency = 0, + .dcnt = 0, + .flags = 0, + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = at32_i2c_pm_prepare, +#endif +}; +#endif + +#ifdef CONFIG_AT32_I2C3 +static const struct at32_i2c_config_s at32_i2c3_config = +{ + .base = AT32_I2C3_BASE, + .clk_bit = CRM_APB1EN_I2C3EN, + .reset_bit = CRM_APB1RST_I2C3RST, + .scl_pin = GPIO_I2C3_SCL, + .sda_pin = GPIO_I2C3_SDA, +#ifndef CONFIG_I2C_POLLED + .ev_irq = AT32_IRQ_I2C3EV, + .er_irq = AT32_IRQ_I2C3ER +#endif +}; + +static struct at32_i2c_priv_s at32_i2c3_priv = +{ + .config = &at32_i2c3_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .frequency = 0, + .dcnt = 0, + .flags = 0, + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = at32_i2c_pm_prepare, +#endif +}; +#endif + +/* Device Structures, Instantiation */ + +static const struct i2c_ops_s at32_i2c_ops = +{ + .transfer = at32_i2c_transfer, +#ifdef CONFIG_I2C_RESET + .reset = at32_i2c_reset, +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_i2c_getreg + * + * Description: + * Get a 16-bit register value by offset + * + ****************************************************************************/ + +static inline uint16_t at32_i2c_getreg(struct at32_i2c_priv_s *priv, + uint8_t offset) +{ + return getreg16(priv->config->base + offset); +} + +/**************************************************************************** + * Name: at32_i2c_getreg32 + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static inline uint32_t at32_i2c_getreg32(struct at32_i2c_priv_s *priv, + uint8_t offset) +{ + return getreg32(priv->config->base + offset); +} + +/**************************************************************************** + * Name: at32_i2c_putreg + * + * Description: + * Put a 16-bit register value by offset + * + ****************************************************************************/ + +static inline void at32_i2c_putreg(struct at32_i2c_priv_s *priv, + uint8_t offset, uint16_t value) +{ + putreg16(value, priv->config->base + offset); +} + +/**************************************************************************** + * Name: at32_i2c_putreg32 + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static inline void at32_i2c_putreg32(struct at32_i2c_priv_s *priv, + uint8_t offset, uint32_t value) +{ + putreg32(value, priv->config->base + offset); +} + +/**************************************************************************** + * Name: at32_i2c_modifyreg32 + * + * Description: + * Modify a 32-bit register value by offset + * + ****************************************************************************/ + +static inline void at32_i2c_modifyreg32(struct at32_i2c_priv_s *priv, + uint8_t offset, uint32_t clearbits, + uint32_t setbits) +{ + modifyreg32(priv->config->base + offset, clearbits, setbits); +} + +/**************************************************************************** + * Name: at32_i2c_toticks + * + * Description: + * Return a micro-second delay based on the number of bytes left to be + * processed. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_I2C_DYNTIMEO +static uint32_t at32_i2c_toticks(int msgc, struct i2c_msg_s *msgs) +{ + size_t bytecount = 0; + int i; + + /* Count the number of bytes left to process */ + + for (i = 0; i < msgc; i++) + { + bytecount += msgs[i].length; + } + + /* Then return a number of microseconds based on a user provided scaling + * factor. + */ + + return USEC2TICK(CONFIG_AT32_I2C_DYNTIMEO_USECPERBYTE * bytecount); +} +#endif + +/**************************************************************************** + * Name: at32_i2c_enableinterrupts + * + * Description: + * Enable I2C interrupts + * + ****************************************************************************/ + +#ifndef CONFIG_I2C_POLLED +static inline void at32_i2c_enableinterrupts(struct at32_i2c_priv_s *priv) +{ + at32_i2c_modifyreg32(priv, AT32_I2C_CR1_OFFSET, 0, + (I2C_CR1_TXRX | I2C_CR1_NACKIE)); +} +#endif + +/**************************************************************************** + * Name: at32_i2c_sem_waitdone + * + * Description: + * Wait for a transfer to complete + * + * There are two versions of this function. The first is included when using + * interrupts while the second is used if polling (CONFIG_I2C_POLLED=y). + * + ****************************************************************************/ + +#ifndef CONFIG_I2C_POLLED +static inline int at32_i2c_sem_waitdone(struct at32_i2c_priv_s *priv) +{ + irqstate_t flags; + int ret; + + flags = enter_critical_section(); + + /* Enable I2C interrupts */ + + /* The TXIE and RXIE interrupts are enabled initially in at32_i2c_process. + * The remainder of the interrupts, including error-related, are enabled + * here. + */ + + at32_i2c_modifyreg32(priv, AT32_I2C_CR1_OFFSET, 0, + (I2C_CR1_ALLINTS & ~I2C_CR1_TXRX)); + + /* Signal the interrupt handler that we are waiting */ + + priv->intstate = INTSTATE_WAITING; + do + { + /* Wait until either the transfer is complete or the timeout expires */ + +#ifdef CONFIG_AT32_I2C_DYNTIMEO + ret = nxsem_tickwait_uninterruptible(&priv->sem_isr, + at32_i2c_toticks(priv->msgc, priv->msgv)); +#else + ret = nxsem_tickwait_uninterruptible(&priv->sem_isr, + CONFIG_AT32_I2CTIMEOTICKS); +#endif + if (ret < 0) + { + /* Break out of the loop on irrecoverable errors. This would + * include timeouts and mystery errors reported by + * nxsem_tickwait_uninterruptible. + */ + + break; + } + } + + /* Loop until the interrupt level transfer is complete. */ + + while (priv->intstate != INTSTATE_DONE); + + /* Set the interrupt state back to IDLE */ + + priv->intstate = INTSTATE_IDLE; + + /* Disable I2C interrupts */ + + at32_i2c_modifyreg32(priv, AT32_I2C_CR1_OFFSET, I2C_CR1_ALLINTS, 0); + + leave_critical_section(flags); + return ret; +} +#else +static inline int at32_i2c_sem_waitdone(struct at32_i2c_priv_s *priv) +{ + clock_t timeout; + clock_t start; + clock_t elapsed; + int ret; + + /* Get the timeout value */ + +#ifdef CONFIG_AT32_I2C_DYNTIMEO + timeout = at32_i2c_toticks(priv->msgc, priv->msgv); +#else + timeout = CONFIG_AT32_I2CTIMEOTICKS; +#endif + + /* Signal the interrupt handler that we are waiting. NOTE: Interrupts + * are currently disabled but will be temporarily re-enabled below when + * nxsem_tickwait_uninterruptible() sleeps. + */ + + priv->intstate = INTSTATE_WAITING; + start = clock_systime_ticks(); + + do + { + /* Calculate the elapsed time */ + + elapsed = clock_systime_ticks() - start; + + /* Poll by simply calling the timer interrupt handler until it + * reports that it is done. + */ + + at32_i2c_isr_process(priv); + } + + /* Loop until the transfer is complete. */ + + while (priv->intstate != INTSTATE_DONE && elapsed < timeout); + + i2cinfo("intstate: %d elapsed: %ld threshold: %ld status: 0x%08x\n", + priv->intstate, (long)elapsed, (long)timeout, priv->status); + + /* Set the interrupt state back to IDLE */ + + ret = priv->intstate == INTSTATE_DONE ? OK : -ETIMEDOUT; + priv->intstate = INTSTATE_IDLE; + return ret; +} +#endif + +/**************************************************************************** + * Name: at32_i2c_set_7bit_address + * + * Description: + * + ****************************************************************************/ + +static inline void +at32_i2c_set_7bit_address(struct at32_i2c_priv_s *priv) +{ + at32_i2c_modifyreg32(priv, AT32_I2C_CR2_OFFSET, I2C_CR2_SADD7_MASK, + ((priv->msgv->addr & 0x7f) << I2C_CR2_SADD7_SHIFT)); +} + +/**************************************************************************** + * Name: at32_i2c_set_bytes_to_transfer + * + * Description: + * + ****************************************************************************/ + +static inline void +at32_i2c_set_bytes_to_transfer(struct at32_i2c_priv_s *priv, + uint8_t n_bytes) +{ + at32_i2c_modifyreg32(priv, AT32_I2C_CR2_OFFSET, I2C_CR2_NBYTES_MASK, + (n_bytes << I2C_CR2_NBYTES_SHIFT)); +} + +/**************************************************************************** + * Name: at32_i2c_set_write_transfer_dir + * + * Description: + * + ****************************************************************************/ + +static inline void +at32_i2c_set_write_transfer_dir(struct at32_i2c_priv_s *priv) +{ + at32_i2c_modifyreg32(priv, AT32_I2C_CR2_OFFSET, I2C_CR2_RD_WRN, 0); +} + +/**************************************************************************** + * Name: at32_i2c_set_read_transfer_dir + * + * Description: + * + ****************************************************************************/ + +static inline void +at32_i2c_set_read_transfer_dir(struct at32_i2c_priv_s *priv) +{ + at32_i2c_modifyreg32(priv, AT32_I2C_CR2_OFFSET, 0, I2C_CR2_RD_WRN); +} + +/**************************************************************************** + * Name: at32_i2c_enable_reload + * + * Description: + * + ****************************************************************************/ + +static inline void +at32_i2c_enable_reload(struct at32_i2c_priv_s *priv) +{ + at32_i2c_modifyreg32(priv, AT32_I2C_CR2_OFFSET, 0, I2C_CR2_RELOAD); +} + +/**************************************************************************** + * Name: at32_i2c_disable_reload + * + * Description: + * + ****************************************************************************/ + +static inline void +at32_i2c_disable_reload(struct at32_i2c_priv_s *priv) +{ + at32_i2c_modifyreg32(priv, AT32_I2C_CR2_OFFSET, I2C_CR2_RELOAD, 0); +} + +/**************************************************************************** + * Name: at32_i2c_sem_waitstop + * + * Description: + * Wait for a STOP to complete + * + ****************************************************************************/ + +static inline void at32_i2c_sem_waitstop(struct at32_i2c_priv_s *priv) +{ + clock_t start; + clock_t elapsed; + clock_t timeout; + uint32_t cr; + uint32_t sr; + + /* Select a timeout */ + +#ifdef CONFIG_AT32_I2C_DYNTIMEO + timeout = USEC2TICK(CONFIG_AT32_I2C_DYNTIMEO_STARTSTOP); +#else + timeout = CONFIG_AT32_I2CTIMEOTICKS; +#endif + + /* Wait as stop might still be in progress */ + + start = clock_systime_ticks(); + do + { + /* Calculate the elapsed time */ + + elapsed = clock_systime_ticks() - start; + + /* Check for STOP condition */ + + cr = at32_i2c_getreg32(priv, AT32_I2C_CR2_OFFSET); + if ((cr & I2C_CR2_STOP) == 0) + { + return; + } + + /* Check for timeout error */ + + sr = at32_i2c_getreg(priv, AT32_I2C_ISR_OFFSET); + if ((sr & I2C_INT_TIMEOUT) != 0) + { + return; + } + } + + /* Loop until the stop is complete or a timeout occurs. */ + + while (elapsed < timeout); + + /* If we get here then a timeout occurred with the STOP condition + * still pending. + */ + + i2cinfo("Timeout with CR: %04" PRIx32 " SR: %04" PRIx32 "\n", cr, sr); +} + +/**************************************************************************** + * Name: at32_i2c_trace* + * + * Description: + * I2C trace instrumentation + * + ****************************************************************************/ + +#ifdef CONFIG_I2C_TRACE +static void at32_i2c_traceclear(struct at32_i2c_priv_s *priv) +{ + struct at32_trace_s *trace = &priv->trace[priv->tndx]; + + trace->status = 0; /* I2C 32-bit status */ + trace->count = 0; /* Interrupt count when status change */ + trace->event = I2CEVENT_NONE; /* Last event that occurred with this status */ + trace->parm = 0; /* Parameter associated with the event */ + trace->time = 0; /* Time of first status or event */ +} + +static void at32_i2c_tracereset(struct at32_i2c_priv_s *priv) +{ + /* Reset the trace info for a new data collection */ + + priv->tndx = 0; + priv->start_time = clock_systime_ticks(); + at32_i2c_traceclear(priv); +} + +static void at32_i2c_tracenew(struct at32_i2c_priv_s *priv, + uint32_t status) +{ + struct at32_trace_s *trace = &priv->trace[priv->tndx]; + + /* Is the current entry uninitialized? Has the status changed? */ + + if (trace->count == 0 || status != trace->status) + { + /* Yes.. Was it the status changed? */ + + if (trace->count != 0) + { + /* Yes.. bump up the trace index + * (unless we are out of trace entries) + */ + + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) + { + i2cerr("ERROR: Trace table overflow\n"); + return; + } + + priv->tndx++; + trace = &priv->trace[priv->tndx]; + } + + /* Initialize the new trace entry */ + + at32_i2c_traceclear(priv); + trace->status = status; + trace->count = 1; + trace->time = clock_systime_ticks(); + } + else + { + /* Just increment the count of times that we have seen this status */ + + trace->count++; + } +} + +static void at32_i2c_traceevent(struct at32_i2c_priv_s *priv, + enum at32_trace_e event, uint32_t parm) +{ + struct at32_trace_s *trace; + + if (event != I2CEVENT_NONE) + { + trace = &priv->trace[priv->tndx]; + + /* Initialize the new trace entry */ + + trace->event = event; + trace->parm = parm; + + /* Bump up the trace index (unless we are out of trace entries) */ + + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) + { + i2cerr("ERROR: Trace table overflow\n"); + return; + } + + priv->tndx++; + at32_i2c_traceclear(priv); + } +} + +static void at32_i2c_tracedump(struct at32_i2c_priv_s *priv) +{ + struct at32_trace_s *trace; + int i; + + syslog(LOG_DEBUG, "Elapsed time: %d\n", + (int)(clock_systime_ticks() - priv->start_time)); + + for (i = 0; i < priv->tndx; i++) + { + trace = &priv->trace[i]; + syslog(LOG_DEBUG, + "%2d. STATUS: %08x COUNT: %3d EVENT: %2d PARM: %08x TIME: %d\n", + i + 1, trace->status, trace->count, trace->event, trace->parm, + (int)(trace->time - priv->start_time)); + } +} +#endif /* CONFIG_I2C_TRACE */ + +/**************************************************************************** + * Name: at32_i2c_setclock + * + * Description: + * + * Sets the I2C bus clock frequency by configuring the I2C_TIMINGR register. + * + * This function supports bus clock frequencies of: + * + * 1000Khz (Fast Mode+) + * 400Khz (Fast Mode) + * 100Khz (Standard Mode) + * 10Khz (Standard Mode) + * + * Attempts to set a different frequency will quietly provision the default + * of 10Khz. + * + * The only differences between the various modes of operation (std, fast, + * fast+) are the bus clock speed and setup/hold times. Setup/hold times + * are specified as a MINIMUM time for the given mode, and naturally std + * mode has the longest minimum times. As a result, by provisioning + * setup/hold times for std mode they are also compatible with fast/fast+, + * though some performance degradation occurs in fast/fast+ as a result of + * the times being somewhat longer than strictly required. The values + * remain as they are because reliability is favored over performance. + * + * Clock Selection: + * + * The I2C peripheral clock can be provided by either PCLK1, SYSCLK or the + * HSI. + * + * PCLK1 >------|\ I2CCLK + * SYSCLK >------| |---------> + * HSI >------|/ + * + * HSI is the default and is always 8Mhz. + * + * SYSCLK can, in turn, be derived from the HSI, HSE, PPLCLK. + * + * HSI >------|\ + * | | SYSCLK + * PLL >------| |---------> + * | | + * HSE >------|/ + * + * + * References: + * + * App Note AN4235 and the associated software STSW-AT32126. + * + ****************************************************************************/ + +static void at32_i2c_setclock(struct at32_i2c_priv_s *priv, + uint32_t frequency) +{ + uint8_t presc; + uint8_t scl_delay; + uint8_t sda_delay; + uint8_t scl_h_period; + uint8_t scl_l_period; + + /* I2C peripheral must be disabled to update clocking configuration. + * This will SW reset the device. + */ + + at32_i2c_modifyreg32(priv, AT32_I2C_CR1_OFFSET, I2C_CR1_PE, 0); + + if (frequency != priv->frequency) + { + /* The Speed and timing calculation are based on the following + * APB1 and is 144Mhz + * Analog filter is on, + * Digital filter off + * Rise Time is 120 ns and fall is 10ns + * Mode is FastMode + */ + + if (frequency == 100000) + { + presc = 3; + scl_delay = 14; + sda_delay = 0; + scl_h_period = 177; + scl_l_period = 177; + } + else if (frequency == 400000) + { + presc = 2; + scl_delay = 12; + sda_delay = 0; + scl_h_period = 40; + scl_l_period = 72; + } + else if (frequency == 1000000) + { + presc = 1; + scl_delay = 13; + sda_delay = 0; + scl_h_period = 22; + scl_l_period = 38; + } + else + { + presc = 3; + scl_delay = 14; + sda_delay = 0; + scl_h_period = 177; + scl_l_period = 177; + } + + uint32_t timingr = + ((presc & 0x0f) << I2C_TIMINGR_PRESC_SHIFT) | + ((presc >> 4) << I2C_TIMINGR_PRESCH_SHIFT) | + (scl_delay << I2C_TIMINGR_SCLDEL_SHIFT) | + (sda_delay << I2C_TIMINGR_SDADEL_SHIFT) | + (scl_h_period << I2C_TIMINGR_SCLH_SHIFT) | + (scl_l_period << I2C_TIMINGR_SCLL_SHIFT); + + at32_i2c_putreg32(priv, AT32_I2C_TIMINGR_OFFSET, timingr); + priv->frequency = frequency; + } + + /* Enable I2C peripheral */ + + at32_i2c_modifyreg32(priv, AT32_I2C_CR1_OFFSET, 0, I2C_CR1_PE); +} + +/**************************************************************************** + * Name: at32_i2c_sendstart + * + * Description: + * Send the START condition / force Master mode + * + * A START condition in I2C consists of a single byte that contains both + * the 7 bit slave address and a read/write bit (0 = WRITE, 1 = READ). + * If the address is recognized by one of the slave devices that slave + * device will ACK the byte so that data transfers can begin. + * + * A RESTART (or repeated START per the I2CSPEC) is simply a START + * condition issued in the middle of a transfer (i.e. after the initial + * START and before a STOP). A RESTART sends a new address byte and R/W + * bit to the bus. A RESTART is optional in most cases but mandatory in + * the event the transfer direction is changed. + * + * Most of the time reading data from an I2C slave requires a WRITE of the + * subaddress followed by a READ (and hence a RESTART in between). Writing + * to an I2C slave typically requires only WRITE operations and hence no + * RESTARTs. + * + * This function is therefore called both at the beginning of a transfer + * (START) and at appropriate times during a transfer (RESTART). + * + ****************************************************************************/ + +static inline void at32_i2c_sendstart(struct at32_i2c_priv_s *priv) +{ + bool next_norestart = false; + + /* Set the private "current message" data used in protocol processing. + * + * ptr: A pointer to the start of the current message buffer. This is + * advanced after each byte in the current message is transferred. + * + * dcnt: A running counter of the bytes in the current message waiting to + * be transferred. This is decremented each time a byte is + * transferred. The hardware normally accepts a maximum of 255 bytes + * per transfer but can support more via the RELOAD mechanism. + * If dcnt initially exceeds 255, the RELOAD mechanism will be + * enabled automatically. + * + * flags: Used to characterize handling of the current message. + * + * The default flags value is 0 which specifies: + * + * - A transfer direction of WRITE (R/W bit = 0) + * - RESTARTs between all messages + * + * The following flags can be used to override this behavior as follows: + * + * - I2C_M_READ: Sets the transfer direction to READ (R/W bit = 1) + * - I2C_M_NOSTART: Prevents a RESTART from being issued prior to the + * transfer of the message (where allowed by the protocol). + * + */ + + priv->ptr = priv->msgv->buffer; + priv->dcnt = priv->msgv->length; + priv->flags = priv->msgv->flags; + + if ((priv->flags & I2C_M_NOSTART) == 0) + { + /* Flag the first byte as an address byte */ + + priv->astart = true; + } + + /* Enabling RELOAD allows the transfer of: + * + * - individual messages with a payload exceeding 255 bytes + * - multiple messages back to back without a RESTART in between + * + * so we enable it if either of those conditions exist and disable + * it otherwise. + */ + + /* Check if there are multiple messages and the next is a continuation */ + + if (priv->msgc > 1) + { + next_norestart = (((priv->msgv + 1)->flags & I2C_M_NOSTART) != 0); + } + + if (next_norestart || priv->dcnt > 255) + { + i2cinfo("RELOAD enabled: dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + at32_i2c_enable_reload(priv); + } + else + { + i2cinfo("RELOAD disable: dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + at32_i2c_disable_reload(priv); + } + + /* Set the number of bytes to transfer (I2C_CR2->NBYTES) to the number of + * bytes in the current message or 255, whichever is lower so as to not + * exceed the hardware maximum allowed. + */ + + if (priv->dcnt > 255) + { + at32_i2c_set_bytes_to_transfer(priv, 255); + } + else + { + at32_i2c_set_bytes_to_transfer(priv, priv->dcnt); + } + + /* Set the (7 bit) address. + * 10 bit addressing is not yet supported. + */ + + at32_i2c_set_7bit_address(priv); + + /* The flag of the current message is used to determine the direction of + * transfer required for the current message. + */ + + if (priv->flags & I2C_M_READ) + { + at32_i2c_set_read_transfer_dir(priv); + } + else + { + at32_i2c_set_write_transfer_dir(priv); + } + + /* Set the I2C_CR2->START bit to 1 to instruct the hardware to send the + * START condition using the address and transfer direction data entered. + */ + + i2cinfo("Sending START: dcnt=%i msgc=%i flags=0x%04x\n", + priv->dcnt, priv->msgc, priv->flags); + + at32_i2c_modifyreg32(priv, AT32_I2C_CR2_OFFSET, 0, I2C_CR2_START); +} + +/**************************************************************************** + * Name: at32_i2c_sendstop + * + * Description: + * Send the STOP conditions + * + * A STOP condition can be requested by setting the STOP bit in the I2C_CR2 + * register. Setting the STOP bit clears the TC flag and the STOP condition + * is sent on the bus. + * + ****************************************************************************/ + +static inline void at32_i2c_sendstop(struct at32_i2c_priv_s *priv) +{ + i2cinfo("Sending STOP\n"); + at32_i2c_traceevent(priv, I2CEVENT_WRITE_STOP, 0); + + at32_i2c_modifyreg32(priv, AT32_I2C_CR2_OFFSET, 0, I2C_CR2_STOP); +} + +/**************************************************************************** + * Name: at32_i2c_getstatus + * + * Description: + * Get 32-bit status (SR1 and SR2 combined) + * + ****************************************************************************/ + +static inline uint32_t at32_i2c_getstatus(struct at32_i2c_priv_s *priv) +{ + return getreg32(priv->config->base + AT32_I2C_ISR_OFFSET); +} + +/**************************************************************************** + * Name: at32_i2c_clearinterrupts + * + * Description: + * Clear all interrupts + * + ****************************************************************************/ + +static inline void at32_i2c_clearinterrupts(struct at32_i2c_priv_s *priv) +{ + at32_i2c_modifyreg32(priv, AT32_I2C_ICR_OFFSET, 0, I2C_ICR_CLEARMASK); +} + +/**************************************************************************** + * Name: at32_i2c_isr_process + * + * Description: + * Common interrupt service routine (ISR) that handles I2C protocol logic. + * This is instantiated for each configured I2C interface + * (I2C1, I2C2, I2C3). + * + * This ISR is activated and deactivated by: + * + * at32_i2c_process + * and + * at32_i2c_waitdone + * + * Input Parameters: + * priv - The private struct of the I2C driver. + * + ****************************************************************************/ + +static int at32_i2c_isr_process(struct at32_i2c_priv_s *priv) +{ + uint32_t status; + + /* Get state of the I2C controller */ + + status = at32_i2c_getreg32(priv, AT32_I2C_ISR_OFFSET); + + i2cinfo("ENTER: status = 0x%08" PRIx32 "\n", status); + + /* Update private version of the state assuming a good state */ + + priv->status = status & ~I2C_INT_BAD_STATE; + + /* If this is a new transmission set up the trace table accordingly */ + + at32_i2c_tracenew(priv, status); + at32_i2c_traceevent(priv, I2CEVENT_ISR_CALL, 0); + + /* ------------------- Start of I2C protocol handling ------------------ */ + + /* I2C protocol logic follows. It's organized in an if else chain such + * that only one mode of operation is executed every time the ISR is + * called. + * + * If you need to add additional states to support new features be sure + * they continue the chain (i.e. begin with "else if") and are placed + * before the empty call / error states at the end of the chain. + */ + + /* NACK Handling + * + * This branch is only triggered when the NACK (Not Acknowledge Received) + * interrupt occurs. This interrupt will only fire when the + * I2C_CR1->NACKIE bit is 1. + * + * I2C_ISR->NACKF is set by hardware when a NACK is received after a + * byte is transmitted and the slave fails to acknowledge it. This is + * the opposite of, and mutually exclusive to, the I2C_ISR->TXIS event. + * + * In response to the NACK the hardware automatically triggers generation + * of a STOP condition, terminating the transfer. The only valid response + * to this state is to exit the ISR and report the failure. + * + * To differentiate an "address NACK" from a NACK that might occur during + * the transfer of other bytes the "priv->astart" parameter is + * used. This flag is set to TRUE in sendstart() and set to FALSE when + * the first TXIS event is received, which would be after the first byte + * (the address) is transmitted successfully (acknowledged). + */ + + if (status & I2C_INT_NACK) + { + if (priv->astart == true) + { + /* NACK received on first (address) byte: address is invalid */ + + i2cinfo("NACK: Address invalid: dcnt=%i msgc=%i " + "status=0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + at32_i2c_traceevent(priv, I2CEVENT_ADDRESS_NACKED, + priv->msgv->addr); + } + else + { + /* NACK received on regular byte */ + + i2cinfo("NACK: NACK received: dcnt=%i msgc=%i " + "status=0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + at32_i2c_traceevent(priv, I2CEVENT_ADDRESS_NACKED, + priv->msgv->addr); + } + + /* Set flags to terminate message transmission: + * + * set message length to -1 to indicate last byte of message sent + * set message count to 0 to indicate no more messages to send + * + * As we fall through the logic in the ISR the message handling block + * will be triggered by these flags and signal the ISR to terminate. + */ + + priv->dcnt = -1; + priv->msgc = 0; + } + + /* Transmit Interrupt Status (TXIS) Handler + * + * This branch is only triggered when the TXIS interrupt occurs. This + * interrupt will only fire when the I2C_CR1->TXIE bit is 1. + * + * This indicates the transmit data register I2C_TXDR has been emptied + * following the successful transmission of a byte and slave + * acknowledgment. + * In this state the I2C_TXDR register is ready to accept another byte for + * transmission. The TXIS bit will be cleared automatically when the next + * byte is written to I2C_TXDR. + * + * The number of TXIS events during the transfer corresponds to NBYTES. + * + * The TXIS flag is not set when a NACK is received. + * + * When RELOAD is disabled (RELOAD=0) and NBYTES data have been + * transferred: + * + * - In Automatic End Mode (AUTOEND=1), a STOP is automatically sent. + * + * Note: Automatic End Mode is not currently supported. + * + * - In Software End Mode (AUTOEND=0), the TC event occurs and the SCL + * line is stretched low in order to allow software actions (STOP, + * RESTART). + * + * When RELOAD is enabled (RELOAD=1) and NBYTES bytes have been transferred + * a TCR event occurs instead and that handler simply updates NBYTES which + * causes TXIS events to continue. The process repeats until all bytes in + * the message have been transferred. + */ + + else if ((priv->flags & (I2C_M_READ)) == 0 && + (status & (I2C_ISR_TXIS)) != 0) + { + /* TXIS interrupt occurred, address valid, ready to transmit */ + + at32_i2c_traceevent(priv, I2CEVENT_WRITE, 0); + i2cinfo("TXIS: ENTER dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + + /* The first event after the address byte is sent will be either TXIS + * or NACKF so it's safe to set the astart flag to false on + * the first TXIS event to indicate that it is no longer necessary to + * check for address validity. + */ + + if (priv->astart == true) + { + i2cinfo("TXIS: Address Valid\n"); + at32_i2c_traceevent(priv, I2CEVENT_ADDRESS_ACKED, + priv->msgv->addr); + priv->astart = false; + } + + /* If one or more bytes in the current message are ready to transmit */ + + if (priv->dcnt > 0) + { + /* Prepare to transmit the current byte */ + + at32_i2c_traceevent(priv, I2CEVENT_WRITE_TO_DR, priv->dcnt); + i2cinfo("TXIS: Write Data 0x%02x\n", *priv->ptr); + + /* Decrement byte counter */ + + priv->dcnt--; + + /* If we are about to transmit the last byte in the current + * message + */ + + if (priv->dcnt == 0) + { + /* If this is also the last message to send, disable RELOAD so + * TC fires next and issues STOP condition. If we don't do + * this TCR will fire next, and since there are no bytes to + * send we can't write NBYTES to clear TCR so it will fire + * forever. + */ + + if (priv->msgc == 1) + { + at32_i2c_disable_reload(priv); + } + } + + /* Transmit current byte */ + + at32_i2c_putreg(priv, AT32_I2C_TXDR_OFFSET, *priv->ptr); + + /* Advance to next byte */ + + priv->ptr++; + } + else + { + /* Unsupported state */ + + i2cerr("ERROR: TXIS Unsupported state detected, dcnt=%i, " + "status 0x%08" PRIx32 "\n", + priv->dcnt, status); + at32_i2c_traceevent(priv, I2CEVENT_WRITE_ERROR, 0); + + /* Indicate the bad state, + * so that on termination HW will be reset + */ + + priv->status |= I2C_INT_BAD_STATE; + } + + i2cinfo("TXIS: EXIT dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + } + + /* Receive Buffer Not Empty (RXNE) State Handler + * + * This branch is only triggered when the RXNE interrupt occurs. This + * interrupt will only fire when the I2C_CR1->RXIE bit is 1. + * + * This indicates data has been received from the bus and is waiting to + * be read from the I2C_RXDR register. When I2C_RXDR is read this bit + * is automatically cleared and then an ACK or NACK is sent depending on + * whether we have more bytes to receive. + * + * When RELOAD is disabled and bytes remain to be transferred an + * acknowledge is automatically sent on the bus and the RXNE events + * continue until the last byte is received. + * + * When RELOAD is disabled (RELOAD=0) and BYTES have been transferred: + * + * - In Automatic End Mode (AUTOEND=1), a NACK and a STOP are + * automatically sent after the last received byte. + * + * Note: Automatic End Mode is not currently supported. + * + * - In Software End Mode (AUTOEND=0), a NACK is automatically sent after + * the last received byte, the TC event occurs and the SCL line is + * stretched low in order to allow software actions (STOP, RESTART). + * + * When RELOAD is enabled (RELOAD=1) and NBYTES bytes have been transferred + * a TCR event occurs and that handler simply updates NBYTES which causes + * RXNE events to continue until all bytes have been transferred. + */ + + else if ((priv->flags & (I2C_M_READ)) != 0 && (status & I2C_ISR_RXNE) != 0) + { + /* When read flag is set and the receive buffer is not empty + * (RXNE is set) then the driver can read from the data register. + */ + + at32_i2c_traceevent(priv, I2CEVENT_READ, 0); + i2cinfo("RXNE: ENTER dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + + /* If more bytes in the current message */ + + if (priv->dcnt > 0) + { + at32_i2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->dcnt); + + /* No interrupts or context switches may occur in the following + * sequence. Otherwise, additional bytes may be received. + */ + +#ifdef CONFIG_I2C_POLLED + irqstate_t state = enter_critical_section(); +#endif + /* Receive a byte */ + + *priv->ptr = at32_i2c_getreg(priv, AT32_I2C_RXDR_OFFSET); + + i2cinfo("RXNE: Read Data 0x%02x\n", *priv->ptr); + + /* Advance buffer to the next byte in the message */ + + priv->ptr++; + + /* Signal byte received */ + + priv->dcnt--; + +#ifdef CONFIG_I2C_POLLED + leave_critical_section(state); +#endif + } + else + { + /* Unsupported state */ + + at32_i2c_traceevent(priv, I2CEVENT_READ_ERROR, 0); + status = at32_i2c_getreg(priv, AT32_I2C_ISR_OFFSET); + i2cerr("ERROR: RXNE Unsupported state detected, dcnt=%i, " + "status 0x%08" PRIx32 "\n", + priv->dcnt, status); + + /* Set signals that will terminate ISR and wake waiting thread */ + + priv->status |= I2C_INT_BAD_STATE; + priv->dcnt = -1; + priv->msgc = 0; + } + + i2cinfo("RXNE: EXIT dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + } + + /* Transfer Complete (TC) State Handler + * + * This branch is only triggered when the TC interrupt occurs. This + * interrupt will only fire when: + * + * I2C_CR1->TCIE = 1 (Transfer Complete Interrupts Enabled) + * I2C_CR2->RELOAD = 0 (Reload Mode Disabled) + * I2C_CR2->AUTOEND = 0 (Autoend Mode Disabled, i.e. Software End Mode) + * + * This event indicates that the number of bytes initially defined + * in NBYTES, meaning, the number of bytes in the current message + * (priv->dcnt) has been successfully transmitted or received. + * + * When the TC interrupt occurs we have two choices to clear it and + * move on, regardless of the transfer direction: + * + * - if more messages follow, perform a repeated START if required + * and then fall through to transmit or receive the next message. + * + * - if no messages follow, perform a STOP and set flags needed to + * exit the ISR. + * + * The fact that the hardware must either RESTART or STOP when a TC + * event occurs explains why, when messages must be sent back to back + * (i.e. without a restart by specifying the I2C_M_NOSTART flag), + * RELOAD mode must be enabled and TCR event(s) must be generated + * instead. See the TCR handler for more. + */ + + else if ((status & I2C_ISR_TC) != 0) + { + i2cinfo("TC: ENTER dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + + /* Prior message has been sent successfully. Or there could have + * been an error that set msgc to 0; So test for that case as + * we do not want to decrement msgc less then zero nor move msgv + * past the last message. + */ + + if (priv->msgc > 0) + { + priv->msgc--; + } + + /* Are there additional messages remain to be transmitted / received? */ + + if (priv->msgc > 0) + { + i2cinfo("TC: RESTART: dcnt=%i, msgc=%i\n", + priv->dcnt, priv->msgc); + at32_i2c_traceevent(priv, I2CEVENT_TC_NO_RESTART, priv->msgc); + + /* Issue a START condition. + * + * Note that the first thing sendstart does is update the + * private structure "current message" data (ptr, dcnt, flags) + * so they all reflect the next message in the list so we + * update msgv before we get there. + */ + + /* Advance to the next message in the list */ + + priv->msgv++; + + at32_i2c_sendstart(priv); + } + else + { + /* Issue a STOP conditions. + * + * No additional messages to transmit / receive, so the + * transfer is indeed complete. Nothing else to do but + * issue a STOP and exit. + */ + + i2cinfo("TC: STOP: dcnt=%i msgc=%i\n", + priv->dcnt, priv->msgc); + at32_i2c_traceevent(priv, I2CEVENT_STOP, priv->dcnt); + + at32_i2c_sendstop(priv); + + /* Set signals that will terminate ISR and wake waiting thread */ + + priv->dcnt = -1; + priv->msgc = 0; + } + + i2cinfo("TC: EXIT dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + } + + /* Transfer Complete (Reload) State Handler + * + * This branch is only triggered when the TCR interrupt occurs. This + * interrupt will only fire when: + * + * I2C_CR1->TCIE = 1 (Transfer Complete Interrupts Enabled) + * I2C_CR2->RELOAD = 1 (Reload Mode Active) + * I2C_CR2->AUTOEND = 0 (Autoend Mode Disabled, i.e. Software End Mode) + * + * This is similar to the TC event except that TCR assumes that additional + * bytes are available to transfer. So despite what its name might imply + * the transfer really isn't complete. + * + * There are two reasons RELOAD would be enabled: + * + * 1) We're trying to send a message with a payload greater than 255 + * bytes. + * 2) We're trying to send messages back to back, regardless of their + * payload size, to avoid a RESTART (i.e. I2C_M_NOSTART flag is set). + * + * These conditions may be true simultaneously, as would be the case if + * we're sending multiple messages with payloads > 255 bytes. So we + * only advance to the next message if we arrive here and dcnt is 0, + * meaning, we're finished with the last message and ready to move to + * the next. + * + * This logic supports the transfer of bytes limited only by the size of + * the i2c_msg_s length variable. The SCL line will be stretched low + * until NBYTES is written with a non-zero value, allowing the transfer + * to continue. + * + * TODO: RESTARTs are required by the I2CSPEC if the next message transfer + * direction changes. Right now the NORESTART flag overrides this + * behavior. May have to introduce logic to issue sendstart, assuming it's + * legal with the hardware in the TCR state. + */ + + else if ((status & I2C_ISR_TCR) != 0) + { + i2cinfo("TCR: ENTER dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + + /* If no more bytes in the current message to transfer */ + + if (priv->dcnt == 0) + { + /* Prior message has been sent successfully */ + + priv->msgc--; + + /* Advance to the next message in the list */ + + priv->msgv++; + + /* Update current message data */ + + priv->ptr = priv->msgv->buffer; + priv->dcnt = priv->msgv->length; + priv->flags = priv->msgv->flags; + + /* If this is the last message, disable reload so the + * TC event fires next time. + */ + + if (priv->msgc == 0) + { + i2cinfo("TCR: DISABLE RELOAD: dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + + at32_i2c_disable_reload(priv); + } + + /* Update NBYTES with length of current message */ + + i2cinfo("TCR: NEXT MSG dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + + at32_i2c_set_bytes_to_transfer(priv, priv->dcnt); + } + else + { + /* More bytes in the current (greater than 255 byte payload + * length) message, so set NBYTES according to the bytes + * remaining in the message, up to a maximum each cycle of 255. + */ + + if (priv->dcnt > 255) + { + i2cinfo( + "TCR: ENABLE RELOAD: NBYTES = 255 dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + + /* More than 255 bytes to transfer so the RELOAD bit is + * set in order to generate a TCR event rather than a TC + * event when 255 bytes are successfully transferred. + * This forces us to return here to update NBYTES and + * continue until NBYTES is set to less than 255 bytes, + * at which point RELOAD will be disabled and a TC + * event will (eventually) follow to officially terminate + * the transfer. + */ + + at32_i2c_enable_reload(priv); + + at32_i2c_set_bytes_to_transfer(priv, 255); + } + else + { + /* Less than 255 bytes left to transfer, which means we'll + * complete the transfer of all bytes in the current message + * the next time around. + * + * This means we need to disable the RELOAD functionality so + * we receive a TC event next time which will allow us to + * either RESTART and continue sending the contents of the + * next message or send a STOP condition and exit the ISR. + */ + + i2cinfo("TCR: DISABLE RELOAD: NBYTES = dcnt = %i msgc = %i\n", + priv->dcnt, priv->msgc); + + at32_i2c_disable_reload(priv); + + at32_i2c_set_bytes_to_transfer(priv, priv->dcnt); + } + + i2cinfo("TCR: EXIT dcnt = %i msgc = %i status 0x%08" PRIx32 "\n", + priv->dcnt, priv->msgc, status); + } + } + + /* Empty call handler + * + * Case to handle an empty call to the ISR where it has nothing to + * do and should exit immediately. + */ + + else if (priv->dcnt == -1 && priv->msgc == 0) + { + status = at32_i2c_getreg(priv, AT32_I2C_ISR_OFFSET); + i2cwarn("WARNING: EMPTY CALL: Stopping ISR: status 0x%08" PRIx32 "\n", + status); + at32_i2c_traceevent(priv, I2CEVENT_ISR_EMPTY_CALL, 0); + } + + /* Error handler + * + * We get to this branch only if we can't handle the current state. + * + * This can happen in interrupt based operation on ARLO & BUSY. + * + * This will happen during polled operation when the device is not + * in one of the supported states when polled. + */ + + else + { +#ifdef CONFIG_I2C_POLLED + at32_i2c_traceevent(priv, I2CEVENT_POLL_DEV_NOT_RDY, 0); +#else + /* Read rest of the state */ + + status = at32_i2c_getreg(priv, AT32_I2C_ISR_OFFSET); + + i2cerr("ERROR: Invalid state detected, status 0x%08" PRIx32 "\n", + status); + + /* set condition to terminate ISR and wake waiting thread */ + + priv->status |= I2C_INT_BAD_STATE; + priv->dcnt = -1; + priv->msgc = 0; + at32_i2c_traceevent(priv, I2CEVENT_STATE_ERROR, 0); +#endif + } + + /* --------------------- End of I2C protocol handling ------------------ */ + + /* Message Handling + * + * Transmission of the whole message chain has been completed. We have to + * terminate the ISR and wake up at32_i2c_process() that is waiting for + * the ISR cycle to handle the sending/receiving of the messages. + */ + + if (priv->dcnt == -1 && priv->msgc == 0) + { + i2cinfo("MSG: Shutting down I2C ISR\n"); + + at32_i2c_traceevent(priv, I2CEVENT_ISR_SHUTDOWN, 0); + + /* Clear pointer to message content to reflect we are done + * with the current transaction. + */ + + priv->msgv = NULL; + +#ifdef CONFIG_I2C_POLLED + priv->intstate = INTSTATE_DONE; +#else + + /* We will update private state to capture NACK which is used in + * combination with the astart flag to report the type of NACK received + * (address vs data) to the upper layers once we exit the ISR. + * + * Note: status is captured prior to clearing interrupts because + * the NACKF flag will naturally be cleared by that process. + */ + + status = at32_i2c_getreg32(priv, AT32_I2C_ISR_OFFSET); + + /* Clear all interrupts */ + + at32_i2c_modifyreg32(priv, AT32_I2C_ICR_OFFSET, + 0, I2C_ICR_CLEARMASK); + + /* Was a bad state detected in the processing? */ + + if (priv->status & I2C_INT_BAD_STATE) + { + /* SW reset device */ + + at32_i2c_modifyreg32(priv, AT32_I2C_CR1_OFFSET, I2C_CR1_PE, 0); + } + + /* Update private status from above sans I2C_INT_BAD_STATE */ + + priv->status = status; + + /* If a thread is waiting then inform it transfer is complete */ + + if (priv->intstate == INTSTATE_WAITING) + { + nxsem_post(&priv->sem_isr); + priv->intstate = INTSTATE_DONE; + } +#endif + } + + status = at32_i2c_getreg32(priv, AT32_I2C_ISR_OFFSET); + i2cinfo("EXIT: status = 0x%08" PRIx32 "\n", status); + + return OK; +} + +/**************************************************************************** + * Name: at32_i2c_isr + * + * Description: + * Common I2C interrupt service routine + * + ****************************************************************************/ + +#ifndef CONFIG_I2C_POLLED +static int at32_i2c_isr(int irq, void *context, void *arg) +{ + struct at32_i2c_priv_s *priv = (struct at32_i2c_priv_s *)arg; + + DEBUGASSERT(priv != NULL); + return at32_i2c_isr_process(priv); +} +#endif + +/**************************************************************************** + * Name: at32_i2c_init + * + * Description: + * Setup the I2C hardware, ready for operation with defaults + * + ****************************************************************************/ + +static int at32_i2c_init(struct at32_i2c_priv_s *priv) +{ + /* Power-up and configure GPIOs */ + + /* Enable power and reset the peripheral */ + + modifyreg32(AT32_CRM_APB1EN, 0, priv->config->clk_bit); + modifyreg32(AT32_CRM_APB1RST, 0, priv->config->reset_bit); + modifyreg32(AT32_CRM_APB1RST, priv->config->reset_bit, 0); + + /* Configure pins */ + + if (at32_configgpio(priv->config->scl_pin) < 0) + { + return ERROR; + } + + if (at32_configgpio(priv->config->sda_pin) < 0) + { + at32_unconfiggpio(priv->config->scl_pin); + return ERROR; + } + +#ifndef CONFIG_I2C_POLLED + /* Attach error and event interrupts to the ISRs */ + + irq_attach(priv->config->ev_irq, at32_i2c_isr, priv); + irq_attach(priv->config->er_irq, at32_i2c_isr, priv); + up_enable_irq(priv->config->ev_irq); + up_enable_irq(priv->config->er_irq); +#endif + + /* TODO: + * - Provide means to set peripheral clock source via RCC_CFGR3_I2CxSW + * - Set to HSI by default, make Kconfig option + */ + + /* Force a frequency update */ + + priv->frequency = 0; + at32_i2c_setclock(priv, 100000); + + return OK; +} + +/**************************************************************************** + * Name: at32_i2c_deinit + * + * Description: + * Shutdown the I2C hardware + * + ****************************************************************************/ + +static int at32_i2c_deinit(struct at32_i2c_priv_s *priv) +{ + /* Disable I2C */ + + at32_i2c_putreg32(priv, AT32_I2C_CR1_OFFSET, 0); + + /* Unconfigure GPIO pins */ + + at32_unconfiggpio(priv->config->scl_pin); + at32_unconfiggpio(priv->config->sda_pin); + +#ifndef CONFIG_I2C_POLLED + + /* Disable and detach interrupts */ + + up_disable_irq(priv->config->ev_irq); + up_disable_irq(priv->config->er_irq); + irq_detach(priv->config->ev_irq); + irq_detach(priv->config->er_irq); +#endif + + /* Disable clocking */ + + modifyreg32(AT32_CRM_APB1EN, priv->config->clk_bit, 0); + + return OK; +} + +/**************************************************************************** + * Name: at32_i2c_process + * + * Description: + * Common I2C transfer logic + * + * Initiates a master mode transaction on the I2C bus to transfer the + * provided messages to and from the slave devices. + * + ****************************************************************************/ + +static int at32_i2c_process(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, int count) +{ + struct at32_i2c_inst_s *inst = (struct at32_i2c_inst_s *)dev; + struct at32_i2c_priv_s *priv = inst->priv; + uint32_t status = 0; + uint32_t cr1; + uint32_t cr2; + int errval = 0; + int waitrc = 0; + + DEBUGASSERT(count > 0); + + /* Wait for any STOP in progress */ + + at32_i2c_sem_waitstop(priv); + + /* Clear any pending error interrupts */ + + at32_i2c_clearinterrupts(priv); + + /* Old transfers are done */ + + priv->msgv = msgs; + priv->msgc = count; + + /* Reset I2C trace logic */ + + at32_i2c_tracereset(priv); + + /* Set I2C clock frequency toggles I2C_CR1_PE performing a SW reset! */ + + at32_i2c_setclock(priv, msgs->frequency); + + /* Trigger start condition, then the process moves into the ISR. I2C + * interrupts will be enabled within at32_i2c_waitdone(). + */ + + priv->status = 0; + +#ifndef CONFIG_I2C_POLLED + /* Enable transmit and receive interrupts here so when we send the start + * condition below the ISR will fire if the data was sent and some + * response from the slave received. All other interrupts relevant to + * our needs are enabled in at32_i2c_sem_waitdone() below. + */ + + at32_i2c_enableinterrupts(priv); +#endif + + /* Trigger START condition generation, which also sends the slave address + * with read/write flag and the data in the first message + */ + + at32_i2c_sendstart(priv); + + /* Wait for the ISR to tell us that the transfer is complete by attempting + * to grab the semaphore that is initially locked by the ISR. If the ISR + * does not release the lock so we can obtain it here prior to the end of + * the timeout period waitdone returns error and we report a timeout. + */ + + waitrc = at32_i2c_sem_waitdone(priv); + + cr1 = at32_i2c_getreg32(priv, AT32_I2C_CR1_OFFSET); + cr2 = at32_i2c_getreg32(priv, AT32_I2C_CR2_OFFSET); +#if !defined(CONFIG_DEBUG_I2C) + UNUSED(cr1); + UNUSED(cr2); +#endif + + /* Status after a normal / good exit is usually 0x00000001, meaning the TXE + * bit is set. That occurs as a result of the I2C_TXDR register being + * empty, and it naturally will be after the last byte is transmitted. + * This bit is cleared when we attempt communications again and re-enable + * the peripheral. The priv->status field can hold additional information + * like a NACK, so we reset the status field to include that information. + */ + + status = at32_i2c_getstatus(priv); + + /* The priv->status field can hold additional information like a NACK + * event so we include that information. + */ + + status = priv->status & 0xffffffff; + + if (waitrc < 0) + { + /* Connection timed out */ + + errval = ETIMEDOUT; + i2cerr("ERROR: Waitdone timed out CR1: 0x%08" PRIx32 + " CR2: 0x%08" PRIx32 " status: 0x%08" PRIx32 "\n", + cr1, cr2, status); + } + else + { + i2cinfo("Waitdone success: CR1: 0x%08" PRIx32 + " CR2: 0x%08" PRIx32 " status: 0x%08" PRIx32 "\n", + cr1, cr2, status); + } + + UNUSED(cr1); + UNUSED(cr2); + + i2cinfo("priv->status: 0x%08" PRIx32 "\n", priv->status); + + /* Check for error status conditions */ + + if ((status & (I2C_INT_BERR | + I2C_INT_ARLO | + I2C_INT_OVR | + I2C_INT_PECERR | + I2C_INT_TIMEOUT | + I2C_INT_NACK)) != 0) + + { + /* one or more errors in the mask are present */ + + if (status & I2C_INT_BERR) + { + /* Bus Error, ignore it because of errata (revision A,Z) */ + + i2cerr("ERROR: I2C Bus Error\n"); + + /* errval = EIO; */ + } + else if (status & I2C_INT_ARLO) + { + /* Arbitration Lost (master mode) */ + + i2cerr("ERROR: I2C Arbitration Lost\n"); + errval = EAGAIN; + } + + else if (status & I2C_INT_OVR) + { + /* Overrun/Underrun */ + + i2cerr("ERROR: I2C Overrun/Underrun\n"); + errval = EIO; + } + else if (status & I2C_INT_PECERR) + { + /* PEC Error in reception (SMBus Only) */ + + i2cerr("ERROR: I2C PEC Error\n"); + errval = EPROTO; + } + else if (status & I2C_INT_TIMEOUT) + { + /* Timeout or Tlow Error (SMBus Only) */ + + i2cerr("ERROR: I2C Timeout / Tlow Error\n"); + errval = ETIME; + } + else if (status & I2C_INT_NACK) + { + /* NACK Received, flag as "communication error on send" */ + + if (priv->astart == TRUE) + { + i2cwarn("WARNING: I2C Address NACK\n"); + errval = EADDRNOTAVAIL; + } + else + { + i2cwarn("WARNING: I2C Data NACK\n"); + errval = ECOMM; + } + } + else + { + /* Unrecognized error */ + + i2cerr("ERROR: I2C Unrecognized Error"); + errval = EINTR; + } + } + + /* This is not an error, but should not happen. The BUSY signal can be + * present if devices on the bus are in an odd state and need to be reset. + * NOTE: We will only see this busy indication if at32_i2c_sem_waitdone() + * fails above; Otherwise it is cleared. + */ + + else if ((status & I2C_ISR_BUSY) != 0) + { + /* I2C Bus Busy + * + * This is a status condition rather than an error. + * + * We will only see this busy indication if at32_i2c_sem_waitdone() + * fails above; Otherwise it is cleared by the hardware when the ISR + * wraps up the transfer with a STOP condition. + */ + + clock_t start = clock_systime_ticks(); + clock_t timeout = USEC2TICK(USEC_PER_SEC / priv->frequency) + 1; + + status = at32_i2c_getstatus(priv); + + while (status & I2C_ISR_BUSY) + { + if ((clock_systime_ticks() - start) > timeout) + { + i2cerr("ERROR: I2C Bus busy"); + errval = EBUSY; + break; + } + + status = at32_i2c_getstatus(priv); + } + } + + /* Dump the trace result */ + + at32_i2c_tracedump(priv); + nxmutex_unlock(&priv->lock); + + return -errval; +} + +/**************************************************************************** + * Name: at32_i2c_transfer + * + * Description: + * Generic I2C transfer function + * + ****************************************************************************/ + +static int at32_i2c_transfer(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, int count) +{ + struct at32_i2c_priv_s *priv; + int ret; + + DEBUGASSERT(dev); + + /* Get I2C private structure */ + + priv = ((struct at32_i2c_inst_s *)dev)->priv; + + /* Ensure that address or flags don't change meanwhile */ + + ret = nxmutex_lock(&priv->lock); + if (ret >= 0) + { + ret = at32_i2c_process(dev, msgs, count); + } + + return ret; +} + +/**************************************************************************** + * Name: at32_i2c_reset + * + * Description: + * Reset an I2C bus + * + ****************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int at32_i2c_reset(struct i2c_master_s *dev) +{ + struct at32_i2c_priv_s *priv; + unsigned int clock_count; + unsigned int stretch_count; + uint32_t scl_gpio; + uint32_t sda_gpio; + uint32_t frequency; + int ret; + + DEBUGASSERT(dev); + + /* Get I2C private structure */ + + priv = ((struct at32_i2c_inst_s *)dev)->priv; + + /* Our caller must own a ref */ + + DEBUGASSERT(priv->refs > 0); + + /* Lock out other clients */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + ret = -EIO; + + /* Save the current frequency */ + + frequency = priv->frequency; + + /* De-init the port */ + + at32_i2c_deinit(priv); + + /* Use GPIO configuration to un-wedge the bus */ + + scl_gpio = MKI2C_OUTPUT(priv->config->scl_pin); + sda_gpio = MKI2C_OUTPUT(priv->config->sda_pin); + + at32_configgpio(sda_gpio); + at32_configgpio(scl_gpio); + + /* Let SDA go high */ + + at32_gpiowrite(sda_gpio, 1); + + /* Clock the bus until any slaves currently driving it let it go. */ + + clock_count = 0; + while (!at32_gpioread(sda_gpio)) + { + /* Give up if we have tried too hard */ + + if (clock_count++ > 10) + { + goto out; + } + + /* Sniff to make sure that clock stretching has finished. + * + * If the bus never relaxes, the reset has failed. + */ + + stretch_count = 0; + while (!at32_gpioread(scl_gpio)) + { + /* Give up if we have tried too hard */ + + if (stretch_count++ > 10) + { + goto out; + } + + up_udelay(10); + } + + /* Drive SCL low */ + + at32_gpiowrite(scl_gpio, 0); + up_udelay(10); + + /* Drive SCL high again */ + + at32_gpiowrite(scl_gpio, 1); + up_udelay(10); + } + + /* Generate a start followed by a stop to reset slave + * state machines. + */ + + at32_gpiowrite(sda_gpio, 0); + up_udelay(10); + at32_gpiowrite(scl_gpio, 0); + up_udelay(10); + at32_gpiowrite(scl_gpio, 1); + up_udelay(10); + at32_gpiowrite(sda_gpio, 1); + up_udelay(10); + + /* Revert the GPIO configuration. */ + + at32_unconfiggpio(sda_gpio); + at32_unconfiggpio(scl_gpio); + + /* Re-init the port */ + + at32_i2c_init(priv); + + /* Restore the frequency */ + + at32_i2c_setclock(priv, frequency); + ret = OK; + +out: + + /* Release the port for re-use by other clients */ + + nxmutex_unlock(&priv->lock); + return ret; +} +#endif /* CONFIG_I2C_RESET */ + +/**************************************************************************** + * Name: at32_i2c_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a + * warning that the system is about to enter into a new power state. The + * driver should begin whatever operations that may be required to enter + * power state. The driver may abort the state change mode by returning + * a non-zero value from the callback function. + * + * Input Parameters: + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state + * data at the end of the structure. + * domain - Identifies the activity domain of the state change + * pmstate - Identifies the new PM state + * + * Returned Value: + * 0 (OK) means the event was successfully processed and that the driver + * is prepared for the PM state change. Non-zero means that the driver + * is not prepared to perform the tasks needed achieve this power setting + * and will cause the state change to be aborted. NOTE: The prepare + * method will also be recalled when reverting from lower back to higher + * power consumption modes (say because another driver refused a lower + * power state change). Drivers are not permitted to return non-zero + * values when reverting back to higher power consumption modes! + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static int at32_i2c_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + struct at32_i2c_priv_s *priv = + (struct at32_i2c_priv_s *)((char *)cb - + offsetof(struct at32_i2c_priv_s, pm_cb)); + + /* Logic to prepare for a reduced power state goes here. */ + + switch (pmstate) + { + case PM_NORMAL: + case PM_IDLE: + break; + + case PM_STANDBY: + case PM_SLEEP: + + /* Check if exclusive lock for I2C bus is held. */ + + if (nxmutex_is_locked(&priv->lock)) + { + /* Exclusive lock is held, do not allow entry to deeper PM + * states. + */ + + return -EBUSY; + } + + break; + + default: + + /* Should not get here */ + + break; + } + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_i2cbus_initialize + * + * Description: + * Initialize one I2C bus + * + ****************************************************************************/ + +struct i2c_master_s *at32_i2cbus_initialize(int port) +{ + struct at32_i2c_priv_s *priv = NULL; /* private data of device with multiple instances */ + struct at32_i2c_inst_s *inst = NULL; /* device, single instance */ +#if 0 +#if AT32_HSI_FREQUENCY != 8000000 || defined(INVALID_CLOCK_SOURCE) +# warning AT32_I2C_INIT: Peripheral clock is HSI and it must be 16mHz or the speed/timing calculations need to be redone. + return NULL; +#endif +#endif + /* Get I2C private structure */ + + switch (port) + { +#ifdef CONFIG_AT32_I2C1 + case 1: + priv = (struct at32_i2c_priv_s *)&at32_i2c1_priv; + break; +#endif +#ifdef CONFIG_AT32_I2C2 + case 2: + priv = (struct at32_i2c_priv_s *)&at32_i2c2_priv; + break; +#endif +#ifdef CONFIG_AT32_I2C3 + case 3: + priv = (struct at32_i2c_priv_s *)&at32_i2c3_priv; + break; +#endif + + default: + return NULL; + } + + /* Allocate instance */ + + if (!(inst = kmm_malloc(sizeof(struct at32_i2c_inst_s)))) + { + return NULL; + } + + /* Initialize instance */ + + inst->ops = &at32_i2c_ops; + inst->priv = priv; + + /* Init private data for the first time, increment refs count, + * power-up hardware and configure GPIOs. + */ + + nxmutex_lock(&priv->lock); + if (priv->refs++ == 0) + { + at32_i2c_init(priv); + +#ifdef CONFIG_PM + /* Register to receive power management callbacks */ + + DEBUGVERIFY(pm_register(&priv->pm_cb)); +#endif + } + + nxmutex_unlock(&priv->lock); + return (struct i2c_master_s *)inst; +} + +/**************************************************************************** + * Name: at32_i2cbus_uninitialize + * + * Description: + * Uninitialize an I2C bus + * + ****************************************************************************/ + +int at32_i2cbus_uninitialize(struct i2c_master_s *dev) +{ + struct at32_i2c_priv_s *priv; + + DEBUGASSERT(dev); + priv = ((struct at32_i2c_inst_s *)dev)->priv; + + /* Decrement refs and check for underflow */ + + if (priv->refs == 0) + { + return ERROR; + } + + nxmutex_lock(&priv->lock); + if (--priv->refs) + { + nxmutex_unlock(&priv->lock); + kmm_free(dev); + return OK; + } + +#ifdef CONFIG_PM + /* Unregister power management callbacks */ + + pm_unregister(&priv->pm_cb); +#endif + + /* Disable power and other HW resource (GPIO's) */ + + at32_i2c_deinit(priv); + nxmutex_unlock(&priv->lock); + + kmm_free(dev); + return OK; +} + +#endif /* CONFIG_AT32_I2C1 || CONFIG_AT32_I2C2 || \ + * CONFIG_AT32_I2C3 || CONFIG_AT32_I2C4 */ diff --git a/arch/arm/src/at32/at32_i2c.h b/arch/arm/src/at32/at32_i2c.h new file mode 100644 index 0000000000..511d1c05f1 --- /dev/null +++ b/arch/arm/src/at32/at32_i2c.h @@ -0,0 +1,89 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_i2c.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_I2C_H +#define __ARCH_ARM_SRC_AT32_AT32_I2C_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "chip.h" +#include "hardware/at32_i2c.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* If a dynamic timeout is selected, then a non-negative, non-zero micro- + * seconds per byte value must be provided as well. + */ + +#ifdef CONFIG_AT32_I2C_DYNTIMEO +# if CONFIG_AT32_I2C_DYNTIMEO_USECPERBYTE < 1 +# warning "Ignoring CONFIG_AT32_I2C_DYNTIMEO because of CONFIG_AT32_I2C_DYNTIMEO_USECPERBYTE" +# undef CONFIG_AT32_I2C_DYNTIMEO +# endif +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_i2cbus_initialize + * + * Description: + * Initialize the selected I2C port. And return a unique instance of struct + * struct i2c_master_s. This function may be called to obtain multiple + * instances of the interface, each of which may be set up with a + * different frequency and slave address. + * + * Input Parameters: + * Port number (for hardware that has multiple I2C interfaces) + * + * Returned Value: + * Valid I2C device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct i2c_master_s *at32_i2cbus_initialize(int port); + +/**************************************************************************** + * Name: at32_i2cbus_uninitialize + * + * Description: + * De-initialize the selected I2C port, and power down the device. + * + * Input Parameters: + * Device structure as returned by the at32_i2cbus_initialize() + * + * Returned Value: + * OK on success, ERROR when internal reference count mismatch or dev + * points to invalid hardware device. + * + ****************************************************************************/ + +int at32_i2cbus_uninitialize(struct i2c_master_s *dev); + +#endif /* __ARCH_ARM_SRC_AT32_AT32_I2C_H */ diff --git a/arch/arm/src/at32/at32_idle.c b/arch/arm/src/at32/at32_idle.c new file mode 100644 index 0000000000..58e78dc537 --- /dev/null +++ b/arch/arm/src/at32/at32_idle.c @@ -0,0 +1,189 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_idle.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include + +#include "chip.h" +#include "at32_pm.h" +#include "arm_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Does the board support an IDLE LED to indicate that the board is in the + * IDLE state? + */ + +#if defined(CONFIG_ARCH_LEDS) && defined(LED_IDLE) +# define BEGIN_IDLE() board_autoled_on(LED_IDLE) +# define END_IDLE() board_autoled_off(LED_IDLE) +#else +# define BEGIN_IDLE() +# define END_IDLE() +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_idlepm + * + * Description: + * Perform IDLE state power management. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void up_idlepm(void) +{ + static enum pm_state_e oldstate = PM_NORMAL; + enum pm_state_e newstate; + irqstate_t flags; + int ret; + + /* Decide, which power saving level can be obtained */ + + newstate = pm_checkstate(PM_IDLE_DOMAIN); + + /* Check for state changes */ + + if (newstate != oldstate) + { + flags = enter_critical_section(); + + /* Perform board-specific, state-dependent logic here */ + + _info("newstate= %d oldstate=%d\n", newstate, oldstate); + + /* Then force the global state change */ + + ret = pm_changestate(PM_IDLE_DOMAIN, newstate); + if (ret < 0) + { + /* The new state change failed, revert to the preceding state */ + + pm_changestate(PM_IDLE_DOMAIN, oldstate); + } + else + { + /* Save the new state */ + + oldstate = newstate; + } + + /* MCU-specific power management logic */ + + switch (newstate) + { + case PM_NORMAL: + break; + + case PM_IDLE: + break; + + case PM_STANDBY: + at32_pmstop(true); + break; + + case PM_SLEEP: + at32_pmstandby(); + break; + + default: + break; + } + + leave_critical_section(flags); + } +} +#else +# define up_idlepm() +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_idle + * + * Description: + * up_idle() is the logic that will be executed when there is no other + * ready-to-run task. This is processor idle time and will continue until + * some interrupt occurs to cause a context switch from the idle task. + * + * Processing in this state may be processor-specific. e.g., this is where + * power management operations might be performed. + * + ****************************************************************************/ + +void up_idle(void) +{ +#if defined(CONFIG_SUPPRESS_INTERRUPTS) || defined(CONFIG_SUPPRESS_TIMER_INTS) + /* If the system is idle and there are no timer interrupts, then process + * "fake" timer interrupts. Hopefully, something will wake up. + */ + + nxsched_process_timer(); +#else + + /* Perform IDLE mode power management */ + + up_idlepm(); + + /* Sleep until an interrupt occurs to save power. + * + * + * "2.17.11 Ethernet DMA not working after WFI/WFE instruction + * Description + * If a WFI/WFE instruction is executed to put the system in sleep mode + * while the Ethernet MAC master clock on the AHB bus matrix is ON and + * all remaining masters clocks are OFF, the Ethernet DMA will be not + * able to perform any AHB master accesses during sleep mode." + * + * Workaround + * Enable DMA1 or DMA2 clocks in the RCC_AHBENR register before + * executing the WFI/WFE instruction." + * + */ + +#if !defined(CONFIG_AT32_CONNECTIVITYLINE) || !defined(CONFIG_AT32_ETHMAC) +#if !(defined(CONFIG_DEBUG_SYMBOLS) && defined(CONFIG_AT32_DISABLE_IDLE_SLEEP_DURING_DEBUG)) + BEGIN_IDLE(); + asm("WFI"); + END_IDLE(); +#endif +#endif +#endif +} diff --git a/arch/arm/src/at32/at32_irq.c b/arch/arm/src/at32/at32_irq.c new file mode 100644 index 0000000000..5966aa1cbd --- /dev/null +++ b/arch/arm/src/at32/at32_irq.c @@ -0,0 +1,501 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_irq.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "nvic.h" +#ifdef CONFIG_ARCH_RAMVECTORS +# include "ram_vectors.h" +#endif +#include "arm_internal.h" +#include "at32.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Get a 32-bit version of the default priority */ + +#define DEFPRIORITY32 \ + (NVIC_SYSH_PRIORITY_DEFAULT << 24 | \ + NVIC_SYSH_PRIORITY_DEFAULT << 16 | \ + NVIC_SYSH_PRIORITY_DEFAULT << 8 | \ + NVIC_SYSH_PRIORITY_DEFAULT) + +/* Given the address of a NVIC ENABLE register, this is the offset to + * the corresponding CLEAR ENABLE register. + */ + +#define NVIC_ENA_OFFSET (0) +#define NVIC_CLRENA_OFFSET (NVIC_IRQ0_31_CLEAR - NVIC_IRQ0_31_ENABLE) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_dumpnvic + * + * Description: + * Dump some interesting NVIC registers + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_IRQ_INFO) +static void at32_dumpnvic(const char *msg, int irq) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + irqinfo("NVIC (%s, irq=%d):\n", msg, irq); + irqinfo(" INTCTRL: %08x VECTAB: %08x\n", + getreg32(NVIC_INTCTRL), getreg32(NVIC_VECTAB)); +#if 0 + irqinfo(" SYSH ENABLE MEMFAULT: %08x BUSFAULT: %08x USGFAULT: %08x " + "SYSTICK: %08x\n", + getreg32(NVIC_SYSHCON_MEMFAULTENA), + getreg32(NVIC_SYSHCON_BUSFAULTENA), + getreg32(NVIC_SYSHCON_USGFAULTENA), + getreg32(NVIC_SYSTICK_CTRL_ENABLE)); +#endif + irqinfo(" IRQ ENABLE: %08x %08x %08x\n", + getreg32(NVIC_IRQ0_31_ENABLE), + getreg32(NVIC_IRQ32_63_ENABLE), + getreg32(NVIC_IRQ64_95_ENABLE)); + irqinfo(" SYSH_PRIO: %08x %08x %08x\n", + getreg32(NVIC_SYSH4_7_PRIORITY), + getreg32(NVIC_SYSH8_11_PRIORITY), + getreg32(NVIC_SYSH12_15_PRIORITY)); + irqinfo(" IRQ PRIO: %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ0_3_PRIORITY), + getreg32(NVIC_IRQ4_7_PRIORITY), + getreg32(NVIC_IRQ8_11_PRIORITY), + getreg32(NVIC_IRQ12_15_PRIORITY)); + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ16_19_PRIORITY), + getreg32(NVIC_IRQ20_23_PRIORITY), + getreg32(NVIC_IRQ24_27_PRIORITY), + getreg32(NVIC_IRQ28_31_PRIORITY)); + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ32_35_PRIORITY), + getreg32(NVIC_IRQ36_39_PRIORITY), + getreg32(NVIC_IRQ40_43_PRIORITY), + getreg32(NVIC_IRQ44_47_PRIORITY)); + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ48_51_PRIORITY), + getreg32(NVIC_IRQ52_55_PRIORITY), + getreg32(NVIC_IRQ56_59_PRIORITY), + getreg32(NVIC_IRQ60_63_PRIORITY)); + irqinfo(" %08x\n", + getreg32(NVIC_IRQ64_67_PRIORITY)); + + leave_critical_section(flags); +} +#else +# define at32_dumpnvic(msg, irq) +#endif + +/**************************************************************************** + * Name: at32_nmi, at32_pendsv, + * at32_dbgmonitor, at32_pendsv, at32_reserved + * + * Description: + * Handlers for various exceptions. None are handled and all are fatal + * error conditions. The only advantage these provided over the default + * unexpected interrupt handler is that they provide a diagnostic output. + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_FEATURES +static int at32_nmi(int irq, void *context, void *arg) +{ + up_irq_save(); + _err("PANIC!!! NMI received\n"); + PANIC(); + return 0; +} + +static int at32_pendsv(int irq, void *context, void *arg) +{ + up_irq_save(); + _err("PANIC!!! PendSV received\n"); + PANIC(); + return 0; +} + +static int at32_dbgmonitor(int irq, void *context, void *arg) +{ + up_irq_save(); + _err("PANIC!!! Debug Monitor received\n"); + PANIC(); + return 0; +} + +static int at32_reserved(int irq, void *context, void *arg) +{ + up_irq_save(); + _err("PANIC!!! Reserved interrupt\n"); + PANIC(); + return 0; +} +#endif + +/**************************************************************************** + * Name: at32_prioritize_syscall + * + * Description: + * Set the priority of an exception. This function may be needed + * internally even if support for prioritized interrupts is not enabled. + * + ****************************************************************************/ + +#ifdef CONFIG_ARMV7M_USEBASEPRI +static inline void at32_prioritize_syscall(int priority) +{ + uint32_t regval; + + /* SVCALL is system handler 11 */ + + regval = getreg32(NVIC_SYSH8_11_PRIORITY); + regval &= ~NVIC_SYSH_PRIORITY_PR11_MASK; + regval |= (priority << NVIC_SYSH_PRIORITY_PR11_SHIFT); + putreg32(regval, NVIC_SYSH8_11_PRIORITY); +} +#endif + +/**************************************************************************** + * Name: at32_irqinfo + * + * Description: + * Given an IRQ number, provide the register and bit setting to enable or + * disable the irq. + * + ****************************************************************************/ + +static int at32_irqinfo(int irq, uintptr_t *regaddr, uint32_t *bit, + uintptr_t offset) +{ + int n; + + DEBUGASSERT(irq >= AT32_IRQ_NMI && irq < NR_IRQS); + + /* Check for external interrupt */ + + if (irq >= AT32_IRQ_FIRST) + { + n = irq - AT32_IRQ_FIRST; + *regaddr = NVIC_IRQ_ENABLE(n) + offset; + *bit = (uint32_t)1 << (n & 0x1f); + } + + /* Handle processor exceptions. Only a few can be disabled */ + + else + { + *regaddr = NVIC_SYSHCON; + if (irq == AT32_IRQ_MEMFAULT) + { + *bit = NVIC_SYSHCON_MEMFAULTENA; + } + else if (irq == AT32_IRQ_BUSFAULT) + { + *bit = NVIC_SYSHCON_BUSFAULTENA; + } + else if (irq == AT32_IRQ_USAGEFAULT) + { + *bit = NVIC_SYSHCON_USGFAULTENA; + } + else if (irq == AT32_IRQ_SYSTICK) + { + *regaddr = NVIC_SYSTICK_CTRL; + *bit = NVIC_SYSTICK_CTRL_ENABLE; + } + else + { + return ERROR; /* Invalid or unsupported exception */ + } + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_irqinitialize + ****************************************************************************/ + +void up_irqinitialize(void) +{ + uint32_t regaddr; + int num_priority_registers; + int i; + + /* Disable all interrupts */ + + for (i = 0; i < NR_IRQS - AT32_IRQ_FIRST; i += 32) + { + putreg32(0xffffffff, NVIC_IRQ_CLEAR(i)); + } + +#if defined(__ICCARM__) + putreg32((uint32_t)__vector_table, NVIC_VECTAB); +#else + putreg32((uint32_t)_vectors, NVIC_VECTAB); +#endif + +#ifdef CONFIG_ARCH_RAMVECTORS + /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based + * vector table that requires special initialization. + */ + + arm_ramvec_initialize(); +#endif + + /* Set all interrupts (and exceptions) to the default priority */ + + putreg32(DEFPRIORITY32, NVIC_SYSH4_7_PRIORITY); + putreg32(DEFPRIORITY32, NVIC_SYSH8_11_PRIORITY); + putreg32(DEFPRIORITY32, NVIC_SYSH12_15_PRIORITY); + + /* The NVIC ICTR register (bits 0-4) holds the number of interrupt + * lines that the NVIC supports: + * + * 0 -> 32 interrupt lines, 8 priority registers + * 1 -> 64 " " " ", 16 priority registers + * 2 -> 96 " " " ", 32 priority registers + * ... + */ + + num_priority_registers = (getreg32(NVIC_ICTR) + 1) * 8; + + /* Now set all of the interrupt lines to the default priority */ + + regaddr = NVIC_IRQ0_3_PRIORITY; + while (num_priority_registers--) + { + putreg32(DEFPRIORITY32, regaddr); + regaddr += 4; + } + + /* Attach the SVCall and Hard Fault exception handlers. The SVCall + * exception is used for performing context switches; The Hard Fault + * must also be caught because a SVCall may show up as a Hard Fault + * under certain conditions. + */ + + irq_attach(AT32_IRQ_SVCALL, arm_svcall, NULL); + irq_attach(AT32_IRQ_HARDFAULT, arm_hardfault, NULL); + + /* Set the priority of the SVCall interrupt */ + +#ifdef CONFIG_ARCH_IRQPRIO + /* up_prioritize_irq(AT32_IRQ_PENDSV, NVIC_SYSH_PRIORITY_MIN); */ +#endif +#ifdef CONFIG_ARMV7M_USEBASEPRI + at32_prioritize_syscall(NVIC_SYSH_SVCALL_PRIORITY); +#endif + + /* If the MPU is enabled, then attach and enable the Memory Management + * Fault handler. + */ + +#ifdef CONFIG_ARM_MPU + irq_attach(AT32_IRQ_MEMFAULT, arm_memfault, NULL); + up_enable_irq(AT32_IRQ_MEMFAULT); +#endif + +#if defined(CONFIG_RTC) && !defined(CONFIG_RTC_EXTERNAL) + /* RTC was initialized earlier but IRQs weren't ready at that time */ + + at32_rtc_irqinitialize(); +#endif + + /* Attach all other processor exceptions (except reset and sys tick) */ + +#ifdef CONFIG_DEBUG_FEATURES + irq_attach(AT32_IRQ_NMI, at32_nmi, NULL); +#ifndef CONFIG_ARM_MPU + irq_attach(AT32_IRQ_MEMFAULT, arm_memfault, NULL); +#endif + irq_attach(AT32_IRQ_BUSFAULT, arm_busfault, NULL); + irq_attach(AT32_IRQ_USAGEFAULT, arm_usagefault, NULL); + irq_attach(AT32_IRQ_PENDSV, at32_pendsv, NULL); + irq_attach(AT32_IRQ_DBGMONITOR, at32_dbgmonitor, NULL); + irq_attach(AT32_IRQ_RESERVED, at32_reserved, NULL); +#endif + + at32_dumpnvic("initial", NR_IRQS); + +#ifndef CONFIG_SUPPRESS_INTERRUPTS + + /* And finally, enable interrupts */ + + up_irq_enable(); +#endif +} + +/**************************************************************************** + * Name: up_disable_irq + * + * Description: + * Disable the IRQ specified by 'irq' + * + ****************************************************************************/ + +void up_disable_irq(int irq) +{ + uintptr_t regaddr; + uint32_t regval; + uint32_t bit; + + if (at32_irqinfo(irq, ®addr, &bit, NVIC_CLRENA_OFFSET) == 0) + { + /* Modify the appropriate bit in the register to disable the interrupt. + * For normal interrupts, we need to set the bit in the associated + * Interrupt Clear Enable register. For other exceptions, we need to + * clear the bit in the System Handler Control and State Register. + */ + + if (irq >= AT32_IRQ_FIRST) + { + putreg32(bit, regaddr); + } + else + { + regval = getreg32(regaddr); + regval &= ~bit; + putreg32(regval, regaddr); + } + } +} + +/**************************************************************************** + * Name: up_enable_irq + * + * Description: + * Enable the IRQ specified by 'irq' + * + ****************************************************************************/ + +void up_enable_irq(int irq) +{ + uintptr_t regaddr; + uint32_t regval; + uint32_t bit; + + if (at32_irqinfo(irq, ®addr, &bit, NVIC_ENA_OFFSET) == 0) + { + /* Modify the appropriate bit in the register to enable the interrupt. + * For normal interrupts, we need to set the bit in the associated + * Interrupt Set Enable register. For other exceptions, we need to + * set the bit in the System Handler Control and State Register. + */ + + if (irq >= AT32_IRQ_FIRST) + { + putreg32(bit, regaddr); + } + else + { + regval = getreg32(regaddr); + regval |= bit; + putreg32(regval, regaddr); + } + } +} + +/**************************************************************************** + * Name: arm_ack_irq + * + * Description: + * Acknowledge the IRQ + * + ****************************************************************************/ + +void arm_ack_irq(int irq) +{ +} + +/**************************************************************************** + * Name: up_prioritize_irq + * + * Description: + * Set the priority of an IRQ. + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_IRQPRIO +int up_prioritize_irq(int irq, int priority) +{ + uint32_t regaddr; + uint32_t regval; + int shift; + + DEBUGASSERT(irq >= AT32_IRQ_MEMFAULT && irq < NR_IRQS && + (unsigned)priority <= NVIC_SYSH_PRIORITY_MIN); + + if (irq < AT32_IRQ_FIRST) + { + /* NVIC_SYSH_PRIORITY() maps {0..15} to one of three priority + * registers (0-3 are invalid) + */ + + regaddr = NVIC_SYSH_PRIORITY(irq); + irq -= 4; + } + else + { + /* NVIC_IRQ_PRIORITY() maps {0..} to one of many priority registers */ + + irq -= AT32_IRQ_FIRST; + regaddr = NVIC_IRQ_PRIORITY(irq); + } + + regval = getreg32(regaddr); + shift = ((irq & 3) << 3); + regval &= ~(0xff << shift); + regval |= (priority << shift); + putreg32(regval, regaddr); + + at32_dumpnvic("prioritize", irq); + return OK; +} +#endif diff --git a/arch/arm/src/at32/at32_iwdg.c b/arch/arm/src/at32/at32_iwdg.c new file mode 100644 index 0000000000..1489b510ff --- /dev/null +++ b/arch/arm/src/at32/at32_iwdg.c @@ -0,0 +1,696 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_iwdg.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "arm_internal.h" +#include "at32_rcc.h" +#include "hardware/at32_dbgmcu.h" +#include "at32_wdg.h" + +#if defined(CONFIG_WATCHDOG) && defined(CONFIG_AT32_IWDG) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Clocking *****************************************************************/ + +/* The minimum frequency of the IWDG clock is: + * + * Fmin = Flsi / 256 + * + * So the maximum delay (in milliseconds) is then: + * + * 1000 * IWDG_RLR_MAX / Fmin + * + * For example, if Flsi = 30Khz (the nominal, uncalibrated value), then the + * maximum delay is: + * + * Fmin = 117.1875 + * 1000 * 4095 / Fmin = 34,944 MSec + */ + +#define IWDG_FMIN (AT32_LSI_FREQUENCY / 256) +#define IWDG_MAXTIMEOUT (1000 * IWDG_RLR_MAX / IWDG_FMIN) + +/* Configuration ************************************************************/ + +#ifndef CONFIG_AT32_IWDG_DEFTIMOUT +# define CONFIG_AT32_IWDG_DEFTIMOUT IWDG_MAXTIMEOUT +#endif + +#ifndef CONFIG_DEBUG_WATCHDOG_INFO +# undef CONFIG_AT32_IWDG_REGDEBUG +#endif + +/* REVISIT: It appears that you can only setup the prescaler and reload + * registers once. After that, the SR register's PVU and RVU bits never go + * to zero. So we defer setting up these registers until the watchdog + * is started, then refuse any further attempts to change timeout. + */ + +#define CONFIG_AT32_IWDG_ONETIMESETUP 1 + +/* REVISIT: Another possibility is that we CAN change the prescaler and + * reload values after starting the timer. This option is untested but the + * implementation place conditioned on the following: + */ + +#undef CONFIG_AT32_IWDG_DEFERREDSETUP + +/* But you can only try one at a time */ + +#if defined(CONFIG_AT32_IWDG_ONETIMESETUP) && defined(CONFIG_AT32_IWDG_DEFERREDSETUP) +# error "Both CONFIG_AT32_IWDG_ONETIMESETUP and CONFIG_AT32_IWDG_DEFERREDSETUP are defined" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure provides the private representation of the "lower-half" + * driver state structure. This structure must be cast-compatible with the + * well-known watchdog_lowerhalf_s structure. + */ + +struct at32_lowerhalf_s +{ + const struct watchdog_ops_s *ops; /* Lower half operations */ + uint32_t lsifreq; /* The calibrated frequency of the LSI oscillator */ + uint32_t timeout; /* The (actual) selected timeout */ + uint32_t lastreset; /* The last reset time */ + bool started; /* true: The watchdog timer has been started */ + uint8_t prescaler; /* Clock prescaler value */ + uint16_t reload; /* Timer reload value */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register operations ******************************************************/ + +#ifdef CONFIG_AT32_IWDG_REGDEBUG +static uint16_t at32_getreg(uint32_t addr); +static void at32_putreg(uint16_t val, uint32_t addr); +#else +# define at32_getreg(addr) getreg16(addr) +# define at32_putreg(val,addr) putreg16(val,addr) +#endif + +static inline void at32_setprescaler(struct at32_lowerhalf_s *priv); + +/* "Lower half" driver methods **********************************************/ + +static int at32_start(struct watchdog_lowerhalf_s *lower); +static int at32_stop(struct watchdog_lowerhalf_s *lower); +static int at32_keepalive(struct watchdog_lowerhalf_s *lower); +static int at32_getstatus(struct watchdog_lowerhalf_s *lower, + struct watchdog_status_s *status); +static int at32_settimeout(struct watchdog_lowerhalf_s *lower, + uint32_t timeout); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* "Lower half" driver methods */ + +static const struct watchdog_ops_s g_wdgops = +{ + .start = at32_start, + .stop = at32_stop, + .keepalive = at32_keepalive, + .getstatus = at32_getstatus, + .settimeout = at32_settimeout, + .capture = NULL, + .ioctl = NULL, +}; + +/* "Lower half" driver state */ + +static struct at32_lowerhalf_s g_wdgdev; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_getreg + * + * Description: + * Get the contents of an AT32 IWDG register + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_IWDG_REGDEBUG +static uint16_t at32_getreg(uint32_t addr) +{ + static uint32_t prevaddr = 0; + static uint32_t count = 0; + static uint16_t preval = 0; + + /* Read the value from the register */ + + uint16_t val = getreg16(addr); + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (addr == prevaddr && val == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + wdinfo("...\n"); + } + + return val; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + wdinfo("[repeats %d more times]\n", count - 3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + preval = val; + count = 1; + } + + /* Show the register value read */ + + wdinfo("%08x->%04x\n", addr, val); + return val; +} +#endif + +/**************************************************************************** + * Name: at32_putreg + * + * Description: + * Set the contents of an AT32 register to a value + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_IWDG_REGDEBUG +static void at32_putreg(uint16_t val, uint32_t addr) +{ + /* Show the register value being written */ + + wdinfo("%08x<-%04x\n", addr, val); + + /* Write the value */ + + putreg16(val, addr); +} +#endif + +/**************************************************************************** + * Name: at32_setprescaler + * + * Description: + * Set up the prescaler and reload values. This seems to be something + * that can only be done one time. + * + * Input Parameters: + * priv - A pointer the internal representation of the "lower-half" + * driver state structure. + * + ****************************************************************************/ + +static inline void at32_setprescaler(struct at32_lowerhalf_s *priv) +{ + /* Enable write access to IWDG_PR and IWDG_RLR registers */ + + at32_putreg(IWDG_KR_KEY_ENABLE, AT32_IWDG_KR); + + /* Wait for the PVU and RVU bits to be reset be hardware. These bits + * were set the last time that the PR register was written and may not + * yet be cleared. + * + * If the setup is only permitted one time, then this wait should not + * be necessary. + */ + +#ifndef CONFIG_AT32_IWDG_ONETIMESETUP + while ((at32_getreg(AT32_IWDG_SR) & (IWDG_SR_PVU | IWDG_SR_RVU)) != 0); +#endif + + /* Set the prescaler */ + + at32_putreg((uint16_t)priv->prescaler << IWDG_PR_SHIFT, AT32_IWDG_PR); + + /* Set the reload value */ + + at32_putreg((uint16_t)priv->reload, AT32_IWDG_RLR); + + /* Reload the counter (and disable write access) */ + + at32_putreg(IWDG_KR_KEY_RELOAD, AT32_IWDG_KR); +} + +/**************************************************************************** + * Name: at32_start + * + * Description: + * Start the watchdog timer, resetting the time to the current timeout, + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_start(struct watchdog_lowerhalf_s *lower) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + irqstate_t flags; + + wdinfo("Entry: started\n"); + DEBUGASSERT(priv); + + /* Have we already been started? */ + + if (!priv->started) + { + /* REVISIT: It appears that you can only setup the prescaler and reload + * registers once. After that, the SR register's PVU and RVU bits never + * go to 0. So we defer setting up these registers until the watchdog + * is started, then refuse any further attempts to change timeout. + */ + + /* Set up prescaler and reload value for the selected timeout before + * starting the watchdog timer. + */ + +#if defined(CONFIG_AT32_IWDG_ONETIMESETUP) || defined(CONFIG_AT32_IWDG_DEFERREDSETUP) + at32_setprescaler(priv); +#endif + + /* Enable IWDG (the LSI oscillator will be enabled by hardware). NOTE: + * If the "Hardware watchdog" feature is enabled through the device + * option bits, the watchdog is automatically enabled at power-on. + */ + + flags = enter_critical_section(); + at32_putreg(IWDG_KR_KEY_START, AT32_IWDG_KR); + priv->lastreset = clock_systime_ticks(); + priv->started = true; + leave_critical_section(flags); + } + + return OK; +} + +/**************************************************************************** + * Name: at32_stop + * + * Description: + * Stop the watchdog timer + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_stop(struct watchdog_lowerhalf_s *lower) +{ + /* There is no way to disable the IDWG timer once it has been started */ + + wdinfo("Entry\n"); + return -ENOSYS; +} + +/**************************************************************************** + * Name: at32_keepalive + * + * Description: + * Reset the watchdog timer to the current timeout value, prevent any + * imminent watchdog timeouts. This is sometimes referred as "pinging" + * the watchdog timer or "petting the dog". + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_keepalive(struct watchdog_lowerhalf_s *lower) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + irqstate_t flags; + + wdinfo("Entry\n"); + + /* Reload the IWDG timer */ + + flags = enter_critical_section(); + at32_putreg(IWDG_KR_KEY_RELOAD, AT32_IWDG_KR); + priv->lastreset = clock_systime_ticks(); + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: at32_getstatus + * + * Description: + * Get the current watchdog timer status + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * status - The location to return the watchdog status information. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_getstatus(struct watchdog_lowerhalf_s *lower, + struct watchdog_status_s *status) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + uint32_t ticks; + uint32_t elapsed; + + wdinfo("Entry\n"); + DEBUGASSERT(priv); + + /* Return the status bit */ + + status->flags = WDFLAGS_RESET; + if (priv->started) + { + status->flags |= WDFLAGS_ACTIVE; + } + + /* Return the actual timeout in milliseconds */ + + status->timeout = priv->timeout; + + /* Get the elapsed time since the last ping */ + + ticks = clock_systime_ticks() - priv->lastreset; + elapsed = (int32_t)TICK2MSEC(ticks); + + if (elapsed > priv->timeout) + { + elapsed = priv->timeout; + } + + /* Return the approximate time until the watchdog timer expiration */ + + status->timeleft = priv->timeout - elapsed; + + wdinfo("Status :\n"); + wdinfo(" flags : %08" PRIx32 "\n", status->flags); + wdinfo(" timeout : %" PRId32 "\n", status->timeout); + wdinfo(" timeleft : %" PRId32 "\n", status->timeleft); + return OK; +} + +/**************************************************************************** + * Name: at32_settimeout + * + * Description: + * Set a new timeout value (and reset the watchdog timer) + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * timeout - The new timeout value in milliseconds. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_settimeout(struct watchdog_lowerhalf_s *lower, + uint32_t timeout) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + uint32_t fiwdg; + uint64_t reload; + int prescaler; + int shift; + + wdinfo("Entry: timeout=%" PRId32 "\n", timeout); + DEBUGASSERT(priv); + + /* Can this timeout be represented? */ + + if (timeout < 1 || timeout > IWDG_MAXTIMEOUT) + { + wderr("ERROR: Cannot represent timeout=%" PRId32 " > %d\n", + timeout, IWDG_MAXTIMEOUT); + return -ERANGE; + } + + /* REVISIT: It appears that you can only setup the prescaler and reload + * registers once. After that, the SR register's PVU and RVU bits never go + * to zero. + */ + +#ifdef CONFIG_AT32_IWDG_ONETIMESETUP + if (priv->started) + { + wdwarn("WARNING: Timer is already started\n"); + return -EBUSY; + } +#endif + + /* Select the smallest prescaler that will result in a reload value that is + * less than the maximum. + */ + + for (prescaler = 0; ; prescaler++) + { + /* PR = 0 -> Divider = 4 = 1 << 2 + * PR = 1 -> Divider = 8 = 1 << 3 + * PR = 2 -> Divider = 16 = 1 << 4 + * PR = 3 -> Divider = 32 = 1 << 5 + * PR = 4 -> Divider = 64 = 1 << 6 + * PR = 5 -> Divider = 128 = 1 << 7 + * PR = 6 -> Divider = 256 = 1 << 8 + * PR = n -> Divider = 1 << (n+2) + */ + + shift = prescaler + 2; + + /* Get the IWDG counter frequency in Hz. For a nominal 32Khz LSI clock, + * this is value in the range of 7500 and 125. + */ + + fiwdg = priv->lsifreq >> shift; + + /* We want: + * 1000 * reload / Fiwdg = timeout + * Or: + * reload = Fiwdg * timeout / 1000 + */ + + reload = (uint64_t)fiwdg * (uint64_t)timeout / 1000; + + /* If this reload valid is less than the maximum or we are not ready + * at the prescaler value, then break out of the loop to use these + * settings. + */ + + if (reload <= IWDG_RLR_MAX || prescaler == 6) + { + /* Note that we explicitly break out of the loop rather than using + * the 'for' loop termination logic because we do not want the + * value of prescaler to be incremented. + */ + + break; + } + } + + /* Make sure that the final reload value is within range */ + + if (reload > IWDG_RLR_MAX) + { + reload = IWDG_RLR_MAX; + } + + /* Get the actual timeout value in milliseconds. + * + * We have: + * reload = Fiwdg * timeout / 1000 + * So we want: + * timeout = 1000 * reload / Fiwdg + */ + + priv->timeout = (1000 * (uint32_t)reload) / fiwdg; + + /* Save setup values for later use */ + + priv->prescaler = prescaler; + priv->reload = reload; + + /* Write the prescaler and reload values to the IWDG registers. + * + * REVISIT: It appears that you can only setup the prescaler and reload + * registers once. After that, the SR register's PVU and RVU bits never go + * to zero. + */ + +#ifndef CONFIG_AT32_IWDG_ONETIMESETUP + /* If CONFIG_AT32_IWDG_DEFERREDSETUP is selected, then perform the + * register configuration only if the timer has been started. + */ + +#ifdef CONFIG_AT32_IWDG_DEFERREDSETUP + if (priv->started) +#endif + { + at32_setprescaler(priv); + } +#endif + + wdinfo("prescaler=%d fiwdg=%" PRId32 " reload=%" PRId64 "\n", + prescaler, fiwdg, reload); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_iwdginitialize + * + * Description: + * Initialize the IWDG watchdog timer. The watchdog timer is initialized + * and registers as 'devpath'. The initial state of the watchdog timer is + * disabled. + * + * Input Parameters: + * devpath - The full path to the watchdog. This should be of the form + * /dev/watchdog0 + * lsifreq - The calibrated LSI clock frequency + * + * Returned Value: + * None + * + ****************************************************************************/ + +void at32_iwdginitialize(const char *devpath, uint32_t lsifreq) +{ + struct at32_lowerhalf_s *priv = &g_wdgdev; + + wdinfo("Entry: devpath=%s lsifreq=%" PRId32 "\n", devpath, lsifreq); + + /* NOTE we assume that clocking to the IWDG has already been provided by + * the RCC initialization logic. + */ + + /* Initialize the driver state structure. */ + + priv->ops = &g_wdgops; + priv->lsifreq = lsifreq; + priv->started = false; + + /* Make sure that the LSI oscillator is enabled. NOTE: The LSI oscillator + * is enabled here but is not disabled by this file, because this file does + * not know the global usage of the oscillator. Any clock management + * logic (say, as part of a power management scheme) needs handle other + * LSI controls outside of this file. + */ + + at32_rcc_enablelsi(); + wdinfo("RCC CSR: %08" PRIx32 "\n", getreg32(AT32_CRM_CTRLSTS)); + + /* Select an arbitrary initial timeout value. But don't start the watchdog + * yet. NOTE: If the "Hardware watchdog" feature is enabled through the + * device option bits, the watchdog is automatically enabled at power-on. + */ + + at32_settimeout((struct watchdog_lowerhalf_s *)priv, + CONFIG_AT32_IWDG_DEFTIMOUT); + + /* Register the watchdog driver as /dev/watchdog0 */ + + watchdog_register(devpath, (struct watchdog_lowerhalf_s *)priv); + + /* When the microcontroller enters debug mode (Cortex-M4F core halted), + * the IWDG counter either continues to work normally or stops, depending + * on DBG_IWDG_STOP configuration bit in DBG module. + */ + +#if defined(CONFIG_AT32_JTAG_FULL_ENABLE) || \ + defined(CONFIG_AT32_JTAG_NOJNTRST_ENABLE) || \ + defined(CONFIG_AT32_JTAG_SW_ENABLE) + { +#if defined(CONFIG_AT32_AT32F43XX) + uint32_t cr = getreg32(AT32_DEBUG_APB1_PAUSE); + cr |= DEBUG_APB1_APUSE_WDT_PAUSE; + putreg32(cr, AT32_DEBUG_APB1_PAUSE); +#endif + } +#endif +} + +#endif /* CONFIG_WATCHDOG && CONFIG_AT32_IWDG */ diff --git a/arch/arm/src/at32/at32_lowputc.c b/arch/arm/src/at32/at32_lowputc.c new file mode 100644 index 0000000000..5e31c3279d --- /dev/null +++ b/arch/arm/src/at32/at32_lowputc.c @@ -0,0 +1,403 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_lowputc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +#include "arm_internal.h" +#include "chip.h" + +#include "at32.h" +#include "at32_rcc.h" +#include "at32_gpio.h" +#include "at32_uart.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Select USART parameters for the selected console */ + +#ifdef HAVE_CONSOLE +# if defined(CONFIG_USART1_SERIAL_CONSOLE) +# define AT32_CONSOLE_BASE AT32_USART1_BASE +# define AT32_APBCLOCK AT32_PCLK2_FREQUENCY +# define AT32_CONSOLE_APBREG AT32_CRM_APB2EN +# define AT32_CONSOLE_APBEN CRM_APB2EN_USART1EN +# define AT32_CONSOLE_BAUD CONFIG_USART1_BAUD +# define AT32_CONSOLE_BITS CONFIG_USART1_BITS +# define AT32_CONSOLE_PARITY CONFIG_USART1_PARITY +# define AT32_CONSOLE_2STOP CONFIG_USART1_2STOP +# define AT32_CONSOLE_TX GPIO_USART1_TX +# define AT32_CONSOLE_RX GPIO_USART1_RX +# ifdef CONFIG_USART1_RS485 +# define AT32_CONSOLE_RS485_DIR GPIO_USART1_RS485_DIR +# if (CONFIG_USART1_RS485_DIR_POLARITY == 0) +# define AT32_CONSOLE_RS485_DIR_POLARITY false +# else +# define AT32_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_USART2_SERIAL_CONSOLE) +# define AT32_CONSOLE_BASE AT32_USART2_BASE +# define AT32_APBCLOCK AT32_PCLK1_FREQUENCY +# define AT32_CONSOLE_APBREG AT32_CRM_APB1EN +# define AT32_CONSOLE_APBEN CRM_APB1EN_USART2EN +# define AT32_CONSOLE_BAUD CONFIG_USART2_BAUD +# define AT32_CONSOLE_BITS CONFIG_USART2_BITS +# define AT32_CONSOLE_PARITY CONFIG_USART2_PARITY +# define AT32_CONSOLE_2STOP CONFIG_USART2_2STOP +# define AT32_CONSOLE_TX GPIO_USART2_TX +# define AT32_CONSOLE_RX GPIO_USART2_RX +# ifdef CONFIG_USART2_RS485 +# define AT32_CONSOLE_RS485_DIR GPIO_USART2_RS485_DIR +# if (CONFIG_USART2_RS485_DIR_POLARITY == 0) +# define AT32_CONSOLE_RS485_DIR_POLARITY false +# else +# define AT32_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_USART3_SERIAL_CONSOLE) +# define AT32_CONSOLE_BASE AT32_USART3_BASE +# define AT32_APBCLOCK AT32_PCLK1_FREQUENCY +# define AT32_CONSOLE_APBREG AT32_CRM_APB1EN +# define AT32_CONSOLE_APBEN CRM_APB1EN_USART3EN +# define AT32_CONSOLE_BAUD CONFIG_USART3_BAUD +# define AT32_CONSOLE_BITS CONFIG_USART3_BITS +# define AT32_CONSOLE_PARITY CONFIG_USART3_PARITY +# define AT32_CONSOLE_2STOP CONFIG_USART3_2STOP +# define AT32_CONSOLE_TX GPIO_USART3_TX +# define AT32_CONSOLE_RX GPIO_USART3_RX +# ifdef CONFIG_USART3_RS485 +# define AT32_CONSOLE_RS485_DIR GPIO_USART3_RS485_DIR +# if (CONFIG_USART3_RS485_DIR_POLARITY == 0) +# define AT32_CONSOLE_RS485_DIR_POLARITY false +# else +# define AT32_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_UART4_SERIAL_CONSOLE) +# define AT32_CONSOLE_BASE AT32_UART4_BASE +# define AT32_APBCLOCK AT32_PCLK1_FREQUENCY +# define AT32_CONSOLE_APBREG AT32_CRM_APB1EN +# define AT32_CONSOLE_APBEN CRM_APB1EN_UART4EN +# define AT32_CONSOLE_BAUD CONFIG_UART4_BAUD +# define AT32_CONSOLE_BITS CONFIG_UART4_BITS +# define AT32_CONSOLE_PARITY CONFIG_UART4_PARITY +# define AT32_CONSOLE_2STOP CONFIG_UART4_2STOP +# define AT32_CONSOLE_TX GPIO_UART4_TX +# define AT32_CONSOLE_RX GPIO_UART4_RX +# ifdef CONFIG_UART4_RS485 +# define AT32_CONSOLE_RS485_DIR GPIO_UART4_RS485_DIR +# if (CONFIG_UART4_RS485_DIR_POLARITY == 0) +# define AT32_CONSOLE_RS485_DIR_POLARITY false +# else +# define AT32_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_UART5_SERIAL_CONSOLE) +# define AT32_CONSOLE_BASE AT32_UART5_BASE +# define AT32_APBCLOCK AT32_PCLK1_FREQUENCY +# define AT32_CONSOLE_APBREG AT32_CRM_APB1EN +# define AT32_CONSOLE_APBEN CRM_APB1EN_UART4EN +# define AT32_CONSOLE_BAUD CONFIG_UART5_BAUD +# define AT32_CONSOLE_BITS CONFIG_UART5_BITS +# define AT32_CONSOLE_PARITY CONFIG_UART5_PARITY +# define AT32_CONSOLE_2STOP CONFIG_UART5_2STOP +# define AT32_CONSOLE_TX GPIO_UART5_TX +# define AT32_CONSOLE_RX GPIO_UART5_RX +# ifdef CONFIG_UART5_RS485 +# define AT32_CONSOLE_RS485_DIR GPIO_UART5_RS485_DIR +# if (CONFIG_UART5_RS485_DIR_POLARITY == 0) +# define AT32_CONSOLE_RS485_DIR_POLARITY false +# else +# define AT32_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_USART6_SERIAL_CONSOLE) +# define AT32_CONSOLE_BASE AT32_USART6_BASE +# define AT32_APBCLOCK AT32_PCLK2_FREQUENCY +# define AT32_CONSOLE_APBREG AT32_CRM_APB2EN +# define AT32_CONSOLE_APBEN CRM_APB2EN_USART6EN +# define AT32_CONSOLE_BAUD CONFIG_USART6_BAUD +# define AT32_CONSOLE_BITS CONFIG_USART6_BITS +# define AT32_CONSOLE_PARITY CONFIG_USART6_PARITY +# define AT32_CONSOLE_2STOP CONFIG_USART6_2STOP +# define AT32_CONSOLE_TX GPIO_USART6_TX +# define AT32_CONSOLE_RX GPIO_USART6_RX +# ifdef CONFIG_USART6_RS485 +# define AT32_CONSOLE_RS485_DIR GPIO_USART6_RS485_DIR +# if (CONFIG_USART6_RS485_DIR_POLARITY == 0) +# define AT32_CONSOLE_RS485_DIR_POLARITY false +# else +# define AT32_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_UART7_SERIAL_CONSOLE) +# define AT32_CONSOLE_BASE AT32_UART7_BASE +# define AT32_APBCLOCK AT32_PCLK1_FREQUENCY +# define AT32_CONSOLE_APBREG AT32_CRM_APB1EN +# define AT32_CONSOLE_APBEN CRM_APB1EN_UART7EN +# define AT32_CONSOLE_BAUD CONFIG_UART7_BAUD +# define AT32_CONSOLE_BITS CONFIG_UART7_BITS +# define AT32_CONSOLE_PARITY CONFIG_UART7_PARITY +# define AT32_CONSOLE_2STOP CONFIG_UART7_2STOP +# define AT32_CONSOLE_TX GPIO_UART7_TX +# define AT32_CONSOLE_RX GPIO_UART7_RX +# ifdef CONFIG_UART7_RS485 +# define AT32_CONSOLE_RS485_DIR GPIO_UART7_RS485_DIR +# if (CONFIG_UART7_RS485_DIR_POLARITY == 0) +# define AT32_CONSOLE_RS485_DIR_POLARITY false +# else +# define AT32_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# elif defined(CONFIG_UART8_SERIAL_CONSOLE) +# define AT32_CONSOLE_BASE AT32_UART8_BASE +# define AT32_APBCLOCK AT32_PCLK1_FREQUENCY +# define AT32_CONSOLE_APBREG AT32_CRM_APB1EN +# define AT32_CONSOLE_APBEN CRM_APB1EN_UART8EN +# define AT32_CONSOLE_BAUD CONFIG_UART8_BAUD +# define AT32_CONSOLE_BITS CONFIG_UART8_BITS +# define AT32_CONSOLE_PARITY CONFIG_UART8_PARITY +# define AT32_CONSOLE_2STOP CONFIG_UART8_2STOP +# define AT32_CONSOLE_TX GPIO_UART8_TX +# define AT32_CONSOLE_RX GPIO_UART8_RX +# ifdef CONFIG_UART8_RS485 +# define AT32_CONSOLE_RS485_DIR GPIO_UART8_RS485_DIR +# if (CONFIG_UART8_RS485_DIR_POLARITY == 0) +# define AT32_CONSOLE_RS485_DIR_POLARITY false +# else +# define AT32_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif +# endif + +/* CR1 settings */ + +# if AT32_CONSOLE_BITS == 9 +# define USART_CR1_M_VALUE (USART_CTRL1_DBN0 | (~USART_CTRL1_DBN1)) +# elif AT32_CONSOLE_BITS == 7 +# define USART_CR1_M_VALUE ((~USART_CTRL1_DBN0) | USART_CTRL1_DBN1) +# else +# define USART_CR1_M_VALUE 0 +# endif + +# if AT32_CONSOLE_PARITY == 1 +# define USART_CR1_PARITY_VALUE (USART_CTRL1_PEN|USART_CTRL1_PSEL) +# elif AT32_CONSOLE_PARITY == 2 +# define USART_CR1_PARITY_VALUE USART_CTRL1_PEN +# else +# define USART_CR1_PARITY_VALUE 0 +# endif + +# define USART_CR1_CLRBITS\ + (USART_CTRL1_DBN0 | USART_CTRL1_DBN1 | USART_CTRL1_PEN | USART_CTRL1_PSEL | \ + USART_CTRL1_TEN | USART_CTRL1_REN | USART_CTRL1_IDLEIEN | USART_CTRL1_RDBFIEN | \ + USART_CTRL1_TDCIEN |USART_CTRL1_TDBEIEN | USART_CTRL1_PERRIEN) + +# define USART_CR1_SETBITS (USART_CR1_M_VALUE|USART_CR1_PARITY_VALUE) + +/* CR2 settings */ + +# if AT32_CONSOLE_2STOP != 0 +# define USART_CR2_STOP2_VALUE USART_CTRL2_STOPBN_20 +# else +# define USART_CR2_STOP2_VALUE 0 +# endif + +# define USART_CR2_CLRBITS \ + (USART_CTRL2_STOPBN_MASK | USART_CTRL2_CLKEN | USART_CTRL2_CLKPOL | USART_CTRL2_CLKPHA | \ + USART_CTRL2_LBCP | USART_CTRL2_BFIEN) + +# define USART_CR2_SETBITS USART_CR2_STOP2_VALUE + +/* CR3 settings */ + +# define USART_CR3_CLRBITS \ + (USART_CTRL3_CTSCFIEN | USART_CTRL3_CTSEN | USART_CTRL3_RTSEN | USART_CTRL3_ERRIEN) + +# define USART_CR3_SETBITS 0 + +#endif /* HAVE_CONSOLE */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_lowputc + * + * Description: + * Output one byte on the serial console + * + ****************************************************************************/ + +void arm_lowputc(char ch) +{ +#ifdef HAVE_CONSOLE + /* Wait until the TX data register is empty */ + + while ((getreg32(AT32_CONSOLE_BASE + AT32_USART_STS_OFFSET) & + USART_STS_TDC) == 0); +#ifdef AT32_CONSOLE_RS485_DIR + at32_gpiowrite(AT32_CONSOLE_RS485_DIR, + AT32_CONSOLE_RS485_DIR_POLARITY); +#endif + + /* Then send the character */ + + putreg32((uint32_t)ch, AT32_CONSOLE_BASE + AT32_USART_DT_OFFSET); + +#ifdef AT32_CONSOLE_RS485_DIR + while ((getreg32(AT32_CONSOLE_BASE + AT32_USART_STS_OFFSET) & + USART_STS_TDC) == 0); + at32_gpiowrite(AT32_CONSOLE_RS485_DIR, + !AT32_CONSOLE_RS485_DIR_POLARITY); +#endif + +#endif /* HAVE_CONSOLE */ +} + +/**************************************************************************** + * Name: at32_lowsetup + * + * Description: + * This performs basic initialization of the USART used for the serial + * console. Its purpose is to get the console output available as soon + * as possible. + * + ****************************************************************************/ + +#if defined(CONFIG_AT32_AT32F43XX) + +void at32_lowsetup(void) +{ +#if defined(HAVE_SERIALDRIVER) +#if defined(HAVE_CONSOLE) && !defined(CONFIG_SUPPRESS_UART_CONFIG) + uint32_t cr; +#endif + +#if defined(HAVE_CONSOLE) + /* Enable USART APB1/2 clock */ + + modifyreg32(AT32_CONSOLE_APBREG, 0, AT32_CONSOLE_APBEN); +#endif + + /* Enable the console USART and configure GPIO pins needed for rx/tx. + * + * NOTE: Clocking for selected U[S]ARTs was already provided in at32_rcc.c + */ + +#ifdef AT32_CONSOLE_TX + at32_configgpio(AT32_CONSOLE_TX); +#endif +#ifdef AT32_CONSOLE_RX + at32_configgpio(AT32_CONSOLE_RX); +#endif + +#ifdef AT32_CONSOLE_RS485_DIR + at32_configgpio(AT32_CONSOLE_RS485_DIR); + at32_gpiowrite(AT32_CONSOLE_RS485_DIR, + !AT32_CONSOLE_RS485_DIR_POLARITY); +#endif + + /* Enable and configure the selected console device */ + +#if defined(HAVE_CONSOLE) && !defined(CONFIG_SUPPRESS_UART_CONFIG) + /* Ensure the USART is disabled because some bits of the following + * registers cannot be modified otherwise. + * + * Although the USART is expected to be disabled at power on reset, this + * might not be the case if we boot from a serial bootloader that does not + * clean up properly. + */ + + cr = getreg32(AT32_CONSOLE_BASE + AT32_USART_CTRL1_OFFSET); + cr &= ~USART_CTRL1_UEN; + putreg32(cr, AT32_CONSOLE_BASE + AT32_USART_CTRL1_OFFSET); + + /* Configure CR2 */ + + cr = getreg32(AT32_CONSOLE_BASE + AT32_USART_CTRL2_OFFSET); + cr &= ~USART_CR2_CLRBITS; + cr |= USART_CR2_SETBITS; + putreg32(cr, AT32_CONSOLE_BASE + AT32_USART_CTRL2_OFFSET); + + /* Configure CR1 */ + + cr = getreg32(AT32_CONSOLE_BASE + AT32_USART_CTRL1_OFFSET); + cr &= ~USART_CR1_CLRBITS; + cr |= USART_CR1_SETBITS; + putreg32(cr, AT32_CONSOLE_BASE + AT32_USART_CTRL1_OFFSET); + + /* Configure CR3 */ + + cr = getreg32(AT32_CONSOLE_BASE + AT32_USART_CTRL3_OFFSET); + cr &= ~USART_CR3_CLRBITS; + cr |= USART_CR3_SETBITS; + putreg32(cr, AT32_CONSOLE_BASE + AT32_USART_CTRL3_OFFSET); + + /* Configure the USART Baud Rate */ + + uint32_t temp_val = (AT32_APBCLOCK * 10 / AT32_CONSOLE_BAUD); + temp_val = ((temp_val % 10) < 5) ? (temp_val / 10) : (temp_val / 10 + 1); + + putreg32(temp_val, AT32_CONSOLE_BASE + AT32_USART_BAUDR_OFFSET); + + /* Enable Rx, Tx, and the USART */ + + cr |= (USART_CTRL1_UEN | USART_CTRL1_TEN | USART_CTRL1_REN); + putreg32(cr, AT32_CONSOLE_BASE + AT32_USART_CTRL1_OFFSET); + +#endif /* HAVE_CONSOLE && !CONFIG_SUPPRESS_UART_CONFIG */ +#endif /* HAVE_SERIALDRIVER */ +} + +#else +# error "Unsupported AT32 chip" +#endif diff --git a/arch/arm/src/at32/at32_lowputc.h b/arch/arm/src/at32/at32_lowputc.h new file mode 100644 index 0000000000..2bd5d122aa --- /dev/null +++ b/arch/arm/src/at32/at32_lowputc.h @@ -0,0 +1,64 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_lowputc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_LOWPUTC_H +#define __ARCH_ARM_SRC_AT32_AT32_LOWPUTC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: at32_lowsetup + * + * Description: + * Called at the very beginning of _start. + * Performs low level initialization of serial console. + * + ****************************************************************************/ + +void at32_lowsetup(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_LOWPUTC_H */ diff --git a/arch/arm/src/at32/at32_lse.c b/arch/arm/src/at32/at32_lse.c new file mode 100644 index 0000000000..797e93c244 --- /dev/null +++ b/arch/arm/src/at32/at32_lse.c @@ -0,0 +1,72 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_lse.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "arm_internal.h" +#include "at32_pwr.h" +#include "at32_rcc.h" +#include "at32_waste.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_rcc_enablelse + * + * Description: + * Enable the External Low-Speed (LSE) oscillator. + * + * Todo: + * Check for LSE good timeout and return with -1, + * + ****************************************************************************/ + +void at32_rcc_enablelse(void) +{ + /* The LSE is in the RTC domain and write access is denied to this domain + * after reset, you have to enable write access using DBP bit in the PWR CR + * register before to configuring the LSE. + */ + + at32_pwr_enablebkp(true); + + /* Enable the External Low-Speed (LSE) oscillator by setting the LSEON bit + * the RCC BDCR register. + */ + + modifyreg16(AT32_CRM_BPDC, 0, CRM_BPDC_LEXTEN); + + /* Wait for the LSE clock to be ready */ + + while ((getreg16(AT32_CRM_BPDC) & CRM_BPDC_LEXTSTBL) == 0) + { + at32_waste(); + } + + /* Disable backup domain access if it was disabled on entry */ + + at32_pwr_enablebkp(false); +} diff --git a/arch/arm/src/at32/at32_lsi.c b/arch/arm/src/at32/at32_lsi.c new file mode 100644 index 0000000000..7e23d77e01 --- /dev/null +++ b/arch/arm/src/at32/at32_lsi.c @@ -0,0 +1,84 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_lsi.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "arm_internal.h" +#include "at32_rcc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_rcc_enablelsi + * + * Description: + * Enable the Internal Low-Speed (LSI) RC Oscillator. + * + ****************************************************************************/ + +void at32_rcc_enablelsi(void) +{ + /* Enable the Internal Low-Speed (LSI) RC Oscillator by setting the LSION + * bit in the CRM CTRLSTS register. + */ + + modifyreg32(AT32_CRM_CTRLSTS, 0, CRM_CTRLSTS_LICKEN); + + /* Wait for the internal RC 40 kHz oscillator to be stable. */ + + while ((getreg32(AT32_CRM_CTRLSTS) & CRM_CTRLSTS_LICKSTBL) == 0); +} + +/**************************************************************************** + * Name: at32_rcc_disablelsi + * + * Description: + * Disable the Internal Low-Speed (LSI) RC Oscillator. + * + ****************************************************************************/ + +void at32_rcc_disablelsi(void) +{ + /* Enable the Internal Low-Speed (LSI) RC Oscillator by setting the LSION + * bit in the CRM CTRLSTS register. + */ + + modifyreg32(AT32_CRM_CTRLSTS, CRM_CTRLSTS_LICKEN, 0); + + /* LSIRDY should go low after 3 LSI clock cycles */ +} diff --git a/arch/arm/src/at32/at32_mpuinit.c b/arch/arm/src/at32/at32_mpuinit.c new file mode 100644 index 0000000000..ec6f4c941f --- /dev/null +++ b/arch/arm/src/at32/at32_mpuinit.c @@ -0,0 +1,101 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_mpuinit.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include "mpu.h" +#include "at32_mpuinit.h" + +#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_ARM_MPU) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_mpuinitialize + * + * Description: + * Configure the MPU to permit user-space access to only restricted SAM3U + * resources. + * + ****************************************************************************/ + +void at32_mpuinitialize(void) +{ + uintptr_t datastart = MIN(USERSPACE->us_datastart, USERSPACE->us_bssstart); + uintptr_t dataend = MAX(USERSPACE->us_dataend, USERSPACE->us_bssend); + + DEBUGASSERT(USERSPACE->us_textend >= USERSPACE->us_textstart && + dataend >= datastart); + + /* Show MPU information */ + + mpu_showtype(); + + /* Reset MPU if enabled */ + + mpu_reset(); + + /* Configure user flash and SRAM space */ + + mpu_user_flash(USERSPACE->us_textstart, + USERSPACE->us_textend - USERSPACE->us_textstart); + + mpu_user_intsram(datastart, dataend - datastart); + + /* Then enable the MPU */ + + mpu_control(true, false, true); +} + +/**************************************************************************** + * Name: at32_mpu_uheap + * + * Description: + * Map the user-heap region. + * + * This logic may need an extension to handle external SDRAM). + * + ****************************************************************************/ + +void at32_mpu_uheap(uintptr_t start, size_t size) +{ + mpu_user_intsram(start, size); +} + +#endif /* CONFIG_BUILD_PROTECTED && CONFIG_ARM_MPU */ diff --git a/arch/arm/src/at32/at32_mpuinit.h b/arch/arm/src/at32/at32_mpuinit.h new file mode 100644 index 0000000000..d1c498eb5f --- /dev/null +++ b/arch/arm/src/at32/at32_mpuinit.h @@ -0,0 +1,75 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_mpuinit.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_MPUINIT_H +#define __ARCH_ARM_SRC_AT32_AT32_MPUINIT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_mpuinitialize + * + * Description: + * Configure the MPU to permit user-space access to only unrestricted MCU + * resources. + * + ****************************************************************************/ + +#ifdef CONFIG_BUILD_PROTECTED +void at32_mpuinitialize(void); +#else +# define at32_mpuinitialize() +#endif + +/**************************************************************************** + * Name: at32_mpu_uheap + * + * Description: + * Map the user heap region. + * + ****************************************************************************/ + +#ifdef CONFIG_BUILD_PROTECTED +void at32_mpu_uheap(uintptr_t start, size_t size); +#else +# define at32_mpu_uheap(start,size) +#endif + +#endif /* __ARCH_ARM_SRC_AT32_AT32_MPUINIT_H */ diff --git a/arch/arm/src/at32/at32_otgfs.h b/arch/arm/src/at32/at32_otgfs.h new file mode 100644 index 0000000000..9bab3469b5 --- /dev/null +++ b/arch/arm/src/at32/at32_otgfs.h @@ -0,0 +1,104 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_otgfs.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_OTGFS_H +#define __ARCH_ARM_SRC_AT32_AT32_OTGFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "at32.h" + +#include "hardware/at32fxxxxx_otgfs.h" + +#if defined(CONFIG_AT32_OTGFS) + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: at32_otgfshost_initialize + * + * Description: + * Initialize USB host device controller hardware. + * + * Input Parameters: + * controller -- If the device supports more than USB host controller, + * then this identifies which controller is being initializeed. + * Normally, this is just zero. + * + * Returned Value: + * And instance of the USB host interface. The controlling task should + * use this interface to (1) call the wait() method to wait for a device + * to be connected, and (2) call the enumerate() method to bind the device + * to a class driver. + * + * Assumptions: + * - This function should called in the initialization sequence in order to + * initialize the USB device functionality. + * - Class drivers should be initialized prior to calling this function. + * Otherwise, there is a race condition if the device is already + * connected. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_USBHOST +struct usbhost_connection_s; +struct usbhost_connection_s *at32_otgfshost_initialize(int controller); +#endif + +/**************************************************************************** + * Name: at32_usbsuspend + * + * Description: + * Board logic must provide the at32_usbsuspend logic if the OTG FS + * device driver is used. This function is called whenever the USB enters + * or leaves suspend mode. This is an opportunity for the board logic to + * shutdown clocks, power, etc. while the USB is suspended. + * + ****************************************************************************/ + +void at32_usbsuspend(struct usbdev_s *dev, bool resume); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_AT32_OTGFS */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_OTGFS_H */ diff --git a/arch/arm/src/at32/at32_otgfsdev.c b/arch/arm/src/at32/at32_otgfsdev.c new file mode 100644 index 0000000000..86182afa57 --- /dev/null +++ b/arch/arm/src/at32/at32_otgfsdev.c @@ -0,0 +1,5875 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_otgfsdev.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "chip.h" +#include "arm_internal.h" +#include "at32_otgfs.h" + +#if defined(CONFIG_USBDEV) && (defined(CONFIG_AT32_OTGFS)) +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_USBDEV_EP0_MAXSIZE +# define CONFIG_USBDEV_EP0_MAXSIZE 64 +#endif + +#ifndef CONFIG_USBDEV_SETUP_MAXDATASIZE +# define CONFIG_USBDEV_SETUP_MAXDATASIZE CONFIG_USBDEV_EP0_MAXSIZE +#endif + +#ifndef CONFIG_USBDEV_MAXPOWER +# define CONFIG_USBDEV_MAXPOWER 100 /* mA */ +#endif + +#ifndef CONFIG_DEBUG_USB_INFO +# undef CONFIG_AT32_USBDEV_REGDEBUG +#endif + +/* There is 1.25Kb of FIFO memory. The default partitions this memory + * so that there is a TxFIFO allocated for each endpoint and with more + * memory provided for the common RxFIFO. A more knowledge-able + * configuration would not allocate any TxFIFO space to OUT endpoints. + */ + +#ifndef CONFIG_USBDEV_RXFIFO_SIZE +# define CONFIG_USBDEV_RXFIFO_SIZE 512 +#endif + +#ifndef CONFIG_USBDEV_EP0_TXFIFO_SIZE +# define CONFIG_USBDEV_EP0_TXFIFO_SIZE 96 +#endif + +#ifndef CONFIG_USBDEV_EP1_TXFIFO_SIZE +# define CONFIG_USBDEV_EP1_TXFIFO_SIZE 96 +#endif + +#ifndef CONFIG_USBDEV_EP2_TXFIFO_SIZE +# define CONFIG_USBDEV_EP2_TXFIFO_SIZE 96 +#endif + +#ifndef CONFIG_USBDEV_EP3_TXFIFO_SIZE +# define CONFIG_USBDEV_EP3_TXFIFO_SIZE 96 +#endif + +#ifndef CONFIG_USBDEV_EP4_TXFIFO_SIZE +# define CONFIG_USBDEV_EP4_TXFIFO_SIZE 96 +#endif + +#ifndef CONFIG_USBDEV_EP5_TXFIFO_SIZE +# define CONFIG_USBDEV_EP5_TXFIFO_SIZE 96 +#endif + +#ifndef CONFIG_USBDEV_EP6_TXFIFO_SIZE +# define CONFIG_USBDEV_EP6_TXFIFO_SIZE 96 +#endif + +#ifndef CONFIG_USBDEV_EP7_TXFIFO_SIZE +# define CONFIG_USBDEV_EP7_TXFIFO_SIZE 96 +#endif + +#if (CONFIG_USBDEV_RXFIFO_SIZE + \ + CONFIG_USBDEV_EP0_TXFIFO_SIZE + CONFIG_USBDEV_EP1_TXFIFO_SIZE + \ + CONFIG_USBDEV_EP2_TXFIFO_SIZE + CONFIG_USBDEV_EP3_TXFIFO_SIZE + \ + CONFIG_USBDEV_EP4_TXFIFO_SIZE + CONFIG_USBDEV_EP5_TXFIFO_SIZE + \ + CONFIG_USBDEV_EP6_TXFIFO_SIZE + CONFIG_USBDEV_EP7_TXFIFO_SIZE ) > 1280 +# error "FIFO allocations exceed FIFO memory size" +#endif + +/* The actual FIFO addresses that we use must be aligned to 4-byte + * boundaries; + * FIFO sizes must be provided in units of 32-bit words. + */ + +#define AT32_RXFIFO_BYTES ((CONFIG_USBDEV_RXFIFO_SIZE + 3) & ~3) +#define AT32_RXFIFO_WORDS ((CONFIG_USBDEV_RXFIFO_SIZE + 3) >> 2) + +#define AT32_EP0_TXFIFO_BYTES ((CONFIG_USBDEV_EP0_TXFIFO_SIZE + 3) & ~3) +#define AT32_EP0_TXFIFO_WORDS ((CONFIG_USBDEV_EP0_TXFIFO_SIZE + 3) >> 2) + +#if AT32_EP0_TXFIFO_WORDS < 16 || AT32_EP0_TXFIFO_WORDS > 256 +# error "CONFIG_USBDEV_EP0_TXFIFO_SIZE is out of range" +#endif + +#define AT32_EP1_TXFIFO_BYTES ((CONFIG_USBDEV_EP1_TXFIFO_SIZE + 3) & ~3) +#define AT32_EP1_TXFIFO_WORDS ((CONFIG_USBDEV_EP1_TXFIFO_SIZE + 3) >> 2) + +#if AT32_EP1_TXFIFO_WORDS < 16 +# error "CONFIG_USBDEV_EP1_TXFIFO_SIZE is out of range" +#endif + +#define AT32_EP2_TXFIFO_BYTES ((CONFIG_USBDEV_EP2_TXFIFO_SIZE + 3) & ~3) +#define AT32_EP2_TXFIFO_WORDS ((CONFIG_USBDEV_EP2_TXFIFO_SIZE + 3) >> 2) + +#if AT32_EP2_TXFIFO_WORDS < 16 +# error "CONFIG_USBDEV_EP2_TXFIFO_SIZE is out of range" +#endif + +#define AT32_EP3_TXFIFO_BYTES ((CONFIG_USBDEV_EP3_TXFIFO_SIZE + 3) & ~3) +#define AT32_EP3_TXFIFO_WORDS ((CONFIG_USBDEV_EP3_TXFIFO_SIZE + 3) >> 2) + +#if AT32_EP3_TXFIFO_WORDS < 16 +# error "CONFIG_USBDEV_EP3_TXFIFO_SIZE is out of range" +#endif + +#define AT32_EP4_TXFIFO_BYTES ((CONFIG_USBDEV_EP4_TXFIFO_SIZE + 3) & ~3) +#define AT32_EP4_TXFIFO_WORDS ((CONFIG_USBDEV_EP4_TXFIFO_SIZE + 3) >> 2) + +#if AT32_EP4_TXFIFO_WORDS < 16 +# error "CONFIG_USBDEV_EP4_TXFIFO_SIZE is out of range" +#endif + +#define AT32_EP5_TXFIFO_BYTES ((CONFIG_USBDEV_EP5_TXFIFO_SIZE + 3) & ~3) +#define AT32_EP5_TXFIFO_WORDS ((CONFIG_USBDEV_EP5_TXFIFO_SIZE + 3) >> 2) + +#if AT32_EP5_TXFIFO_WORDS < 16 +# error "CONFIG_USBDEV_EP5_TXFIFO_SIZE is out of range" +#endif + +#define AT32_EP6_TXFIFO_BYTES ((CONFIG_USBDEV_EP6_TXFIFO_SIZE + 3) & ~3) +#define AT32_EP6_TXFIFO_WORDS ((CONFIG_USBDEV_EP6_TXFIFO_SIZE + 3) >> 2) + +#if AT32_EP6_TXFIFO_WORDS < 16 +# error "CONFIG_USBDEV_EP6_TXFIFO_SIZE is out of range" +#endif + +#define AT32_EP7_TXFIFO_BYTES ((CONFIG_USBDEV_EP7_TXFIFO_SIZE + 3) & ~3) +#define AT32_EP7_TXFIFO_WORDS ((CONFIG_USBDEV_EP7_TXFIFO_SIZE + 3) >> 2) + +#if AT32_EP7_TXFIFO_WORDS < 16 +# error "CONFIG_USBDEV_EP7_TXFIFO_SIZE is out of range" +#endif + +#if defined(CONFIG_AT32_AT32F446) || defined(CONFIG_AT32_AT32F469) +# define OTGFS_GINT_RESETS (OTGFS_GINT_USBRST | OTGFS_GINT_RSTDET) +# define OTGFS_GINT_RESERVED (OTGFS_GINT_RES89 | OTGFS_GINT_RES16 | \ + OTGFS_GINTMSK_EPMISM | OTGFS_GINT_RES22) + +# define OTGFS_GINT_RC_W1 (OTGFS_GINT_MMIS | \ + OTGFS_GINT_SOF | \ + OTGFS_GINT_ESUSP | \ + OTGFS_GINT_USBSUSP | \ + OTGFS_GINT_USBRST | \ + OTGFS_GINT_ENUMDNE | \ + OTGFS_GINT_ISOODRP | \ + OTGFS_GINT_EOPF | \ + OTGFS_GINT_IISOIXFR | \ + OTGFS_GINT_IISOOXFR | \ + OTGFS_GINT_RSTDET | \ + OTGFS_GINT_LPMINT | \ + OTGFS_GINT_CIDSCHG | \ + OTGFS_GINT_DISC | \ + OTGFS_GINT_SRQ | \ + OTGFS_GINT_WKUP) +#else +# define OTGFS_GINT_RESETS OTGFS_GINT_USBRST + +#if 0 +# define OTGFS_GINT_RESERVED (OTGFS_GINT_RES89 | OTGFS_GINT_RES16 | \ + OTGFS_GINTMSK_EPMISM | OTGFS_GINT_RES2223 | \ + OTGFS_GINT_RES27) +#endif + +# define OTGFS_GINT_RESERVED ( OTGFS_GINT_RES16 | OTGFS_GINTMSK_EPMISM ) + +# define OTGFS_GINT_RC_W1 (OTGFS_GINT_MMIS | \ + OTGFS_GINT_SOF | \ + OTGFS_GINT_ESUSP | \ + OTGFS_GINT_USBSUSP | \ + OTGFS_GINT_USBRST | \ + OTGFS_GINT_ENUMDNE | \ + OTGFS_GINT_ISOODRP | \ + OTGFS_GINT_EOPF | \ + OTGFS_GINT_IISOIXFR | \ + OTGFS_GINT_IISOOXFR | \ + OTGFS_GINT_CIDSCHG | \ + OTGFS_GINT_DISC | \ + OTGFS_GINT_SRQ | \ + OTGFS_GINT_WKUP) +#endif + +/* Debug ********************************************************************/ + +/* Trace error codes */ + +#define AT32_TRACEERR_ALLOCFAIL 0x01 +#define AT32_TRACEERR_BADCLEARFEATURE 0x02 +#define AT32_TRACEERR_BADDEVGETSTATUS 0x03 +#define AT32_TRACEERR_BADEPNO 0x04 +#define AT32_TRACEERR_BADEPGETSTATUS 0x05 +#define AT32_TRACEERR_BADGETCONFIG 0x06 +#define AT32_TRACEERR_BADGETSETDESC 0x07 +#define AT32_TRACEERR_BADGETSTATUS 0x08 +#define AT32_TRACEERR_BADSETADDRESS 0x09 +#define AT32_TRACEERR_BADSETCONFIG 0x0a +#define AT32_TRACEERR_BADSETFEATURE 0x0b +#define AT32_TRACEERR_BADTESTMODE 0x0c +#define AT32_TRACEERR_BINDFAILED 0x0d +#define AT32_TRACEERR_DISPATCHSTALL 0x0e +#define AT32_TRACEERR_DRIVER 0x0f +#define AT32_TRACEERR_DRIVERREGISTERED 0x10 +#define AT32_TRACEERR_EP0NOSETUP 0x11 +#define AT32_TRACEERR_EP0SETUPSTALLED 0x12 +#define AT32_TRACEERR_EPINNULLPACKET 0x13 +#define AT32_TRACEERR_EPINUNEXPECTED 0x14 +#define AT32_TRACEERR_EPOUTNULLPACKET 0x15 +#define AT32_TRACEERR_EPOUTUNEXPECTED 0x16 +#define AT32_TRACEERR_INVALIDCTRLREQ 0x17 +#define AT32_TRACEERR_INVALIDPARMS 0x18 +#define AT32_TRACEERR_IRQREGISTRATION 0x19 +#define AT32_TRACEERR_NOEP 0x1a +#define AT32_TRACEERR_NOTCONFIGURED 0x1b +#define AT32_TRACEERR_EPOUTQEMPTY 0x1c +#define AT32_TRACEERR_EPINREQEMPTY 0x1d +#define AT32_TRACEERR_NOOUTSETUP 0x1e +#define AT32_TRACEERR_POLLTIMEOUT 0x1f + +/* Trace interrupt codes */ + +#define AT32_TRACEINTID_USB 1 /* USB Interrupt entry/exit */ +#define AT32_TRACEINTID_INTPENDING 2 /* On each pass through the loop */ + +#define AT32_TRACEINTID_EPOUT (10 + 0) /* First level interrupt decode */ +#define AT32_TRACEINTID_EPIN (10 + 1) +#define AT32_TRACEINTID_MISMATCH (10 + 2) +#define AT32_TRACEINTID_WAKEUP (10 + 3) +#define AT32_TRACEINTID_SUSPEND (10 + 4) +#define AT32_TRACEINTID_SOF (10 + 5) +#define AT32_TRACEINTID_RXFIFO (10 + 6) +#define AT32_TRACEINTID_DEVRESET (10 + 7) +#define AT32_TRACEINTID_ENUMDNE (10 + 8) +#define AT32_TRACEINTID_IISOIXFR (10 + 9) +#define AT32_TRACEINTID_IISOOXFR (10 + 10) +#define AT32_TRACEINTID_SRQ (10 + 11) +#define AT32_TRACEINTID_OTG (10 + 12) + +#define AT32_TRACEINTID_EPOUT_XFRC (40 + 0) /* EPOUT second level decode */ +#define AT32_TRACEINTID_EPOUT_EPDISD (40 + 1) +#define AT32_TRACEINTID_EPOUT_SETUP (40 + 2) +#define AT32_TRACEINTID_DISPATCH (40 + 3) + +#define AT32_TRACEINTID_GETSTATUS (50 + 0) /* EPOUT third level decode */ +#define AT32_TRACEINTID_EPGETSTATUS (50 + 1) +#define AT32_TRACEINTID_DEVGETSTATUS (50 + 2) +#define AT32_TRACEINTID_IFGETSTATUS (50 + 3) +#define AT32_TRACEINTID_CLEARFEATURE (50 + 4) +#define AT32_TRACEINTID_SETFEATURE (50 + 5) +#define AT32_TRACEINTID_SETADDRESS (50 + 6) +#define AT32_TRACEINTID_GETSETDESC (50 + 7) +#define AT32_TRACEINTID_GETCONFIG (50 + 8) +#define AT32_TRACEINTID_SETCONFIG (50 + 9) +#define AT32_TRACEINTID_GETSETIF (50 + 10) +#define AT32_TRACEINTID_SYNCHFRAME (50 + 11) + +#define AT32_TRACEINTID_EPIN_XFRC (70 + 0) /* EPIN second level decode */ +#define AT32_TRACEINTID_EPIN_TOC (70 + 1) +#define AT32_TRACEINTID_EPIN_ITTXFE (70 + 2) +#define AT32_TRACEINTID_EPIN_EPDISD (70 + 3) +#define AT32_TRACEINTID_EPIN_TXFE (70 + 4) + +#define AT32_TRACEINTID_EPIN_EMPWAIT (80 + 0) /* EPIN second level decode */ + +#define AT32_TRACEINTID_OUTNAK (90 + 0) /* RXFLVL second level decode */ +#define AT32_TRACEINTID_OUTRECVD (90 + 1) +#define AT32_TRACEINTID_OUTDONE (90 + 2) +#define AT32_TRACEINTID_SETUPDONE (90 + 3) +#define AT32_TRACEINTID_SETUPRECVD (90 + 4) + +/* Endpoints ****************************************************************/ + +/* Number of endpoints */ + +#define AT32_NENDPOINTS (8) /* ep0-3 x 2 for IN and OUT */ + +/* Odd physical endpoint numbers are IN; even are OUT */ + +#define AT32_EPPHYIN2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_IN) +#define AT32_EPPHYOUT2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_OUT) + +/* Endpoint 0 */ + +#define EP0 (0) + +/* The set of all endpoints available to the class implementation (1-3) */ + +#define AT32_EP_AVAILABLE (0x0f) /* All available endpoints */ + +/* Maximum packet sizes for full speed endpoints */ + +#define AT32_MAXPACKET (64) /* Max packet size (1-64) */ + +/* Delays *******************************************************************/ + +#define AT32_READY_DELAY 400000 +#define AT32_FLUSH_DELAY 400000 + +/* Request queue operations *************************************************/ + +#define at32_rqempty(ep) ((ep)->head == NULL) +#define at32_rqpeek(ep) ((ep)->head) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Overall device state */ + +enum at32_devstate_e +{ + DEVSTATE_DEFAULT = 0, /* Power-up, unconfigured state. This state simply + * means that the device is not yet been given an + * address. + * SET: At initialization, uninitialization, + * reset, and whenever the device address + * is set to zero + * TESTED: Never + */ + DEVSTATE_ADDRESSED, /* Device address has been assigned, not no + * configuration has yet been selected. + * SET: When either a non-zero device address + * is first assigned or when the device + * is unconfigured (with configuration == 0) + * TESTED: never + */ + DEVSTATE_CONFIGURED, /* Address assigned and configured: + * SET: When the device has been addressed and + * an non-zero configuration has been selected. + * TESTED: In many places to assure that the USB device + * has been properly configured by the host. + */ +}; + +/* Endpoint 0 states */ + +enum at32_ep0state_e +{ + EP0STATE_IDLE = 0, /* Idle State, leave on receiving a SETUP packet or + * epsubmit: + * SET: In at32_epin() and at32_epout() when + * we revert from request processing to + * SETUP processing. + * TESTED: Never + */ + EP0STATE_SETUP_OUT, /* OUT SETUP packet received. Waiting for the DATA + * OUT phase of SETUP Packet to complete before + * processing a SETUP command (without a USB request): + * SET: Set in at32_rxinterrupt() when SETUP OUT + * packet is received. + * TESTED: In at32_ep0out_receive() + */ + EP0STATE_SETUP_READY, /* IN SETUP packet received -OR- OUT SETUP packet and + * accompanying data have been received. Processing + * of SETUP command will happen soon. + * SET: (1) at32_ep0out_receive() when the OUT + * SETUP data phase completes, or (2) + * at32_rxinterrupt() when an IN SETUP is + * packet received. + * TESTED: Tested in at32_epout_interrupt() when + * SETUP phase is done to see if the SETUP + * command is ready to be processed. Also + * tested in at32_ep0out_setup() just to + * double-check that we have a SETUP request + * and any accompanying data. + */ + EP0STATE_SETUP_PROCESS, /* SETUP Packet is being processed by at32_ep0out_setup(): + * SET: When SETUP packet received in EP0 OUT + * TESTED: Never + */ + EP0STATE_SETUPRESPONSE, /* Short SETUP response write (without a USB request): + * SET: When SETUP response is sent by + * at32_ep0in_setupresponse() + * TESTED: Never + */ + EP0STATE_DATA_IN, /* Waiting for data out stage (with a USB request): + * SET: In at32_epin_request() when a write + * request is processed on EP0. + * TESTED: In at32_epin() to see if we should + * revert to SETUP processing. + */ + EP0STATE_DATA_OUT /* Waiting for data in phase to complete ( with a + * USB request) + * SET: In at32_epout_request() when a read + * request is processed on EP0. + * TESTED: In at32_epout() to see if we should + * revert to SETUP processing + */ +}; + +/* Parsed control request */ + +struct at32_ctrlreq_s +{ + uint8_t type; + uint8_t req; + uint16_t value; + uint16_t index; + uint16_t len; +}; + +/* A container for a request so that the request may be retained in a list */ + +struct at32_req_s +{ + struct usbdev_req_s req; /* Standard USB request */ + struct at32_req_s *flink; /* Supports a singly linked list */ +}; + +/* This is the internal representation of an endpoint */ + +struct at32_ep_s +{ + /* Common endpoint fields. This must be the first thing defined in the + * structure so that it is possible to simply cast from struct usbdev_ep_s + * to struct at32_ep_s. + */ + + struct usbdev_ep_s ep; /* Standard endpoint structure */ + + /* AT32-specific fields */ + + struct at32_usbdev_s *dev; /* Reference to private driver data */ + struct at32_req_s *head; /* Request list for this endpoint */ + struct at32_req_s *tail; + uint8_t epphy; /* Physical EP address */ + uint8_t eptype:2; /* Endpoint type */ + uint8_t active:1; /* 1: A request is being processed */ + uint8_t stalled:1; /* 1: Endpoint is stalled */ + uint8_t isin:1; /* 1: IN Endpoint */ + uint8_t odd:1; /* 1: Odd frame */ + uint8_t zlp:1; /* 1: Transmit a zero-length-packet (IN EPs only) */ +}; + +/* This structure retains the state of the USB device controller */ + +struct at32_usbdev_s +{ + /* Common device fields. This must be the first thing defined in the + * structure so that it is possible to simply cast from struct usbdev_s + * to struct at32_usbdev_s. + */ + + struct usbdev_s usbdev; + + /* The bound device class driver */ + + struct usbdevclass_driver_s *driver; + + /* AT32-specific fields */ + + uint8_t stalled:1; /* 1: Protocol stalled */ + uint8_t selfpowered:1; /* 1: Device is self powered */ + uint8_t addressed:1; /* 1: Peripheral address has been set */ + uint8_t configured:1; /* 1: Class driver has been configured */ + uint8_t wakeup:1; /* 1: Device remote wake-up */ + uint8_t dotest:1; /* 1: Test mode selected */ + + uint8_t devstate:4; /* See enum at32_devstate_e */ + uint8_t ep0state:4; /* See enum at32_ep0state_e */ + uint8_t testmode:4; /* Selected test mode */ + uint8_t epavail[2]; /* Bitset of available OUT/IN endpoints */ + + /* E0 SETUP data buffering. + * + * ctrlreq: + * The 8-byte SETUP request is received on the EP0 OUT endpoint and is + * saved. + * + * ep0data + * For OUT SETUP requests, the SETUP data phase must also complete before + * the SETUP command can be processed. The pack receipt logic will save + * the accompanying EP0 OUT data in ep0data[] before the SETUP command is + * processed. The data length is specified in the SETUP packet payload, + * and can consist of multiple DATA packets. + * + * For IN SETUP requests, the DATA phase will occur AFTER the SETUP + * control request is processed. In that case, ep0data[] may be used as + * the response buffer. + * + * ep0datlen + * Length of data received part of OUT SETUP request. During transfer + * it is the total number of bytes received, which can be more than + * CONFIG_USBDEV_SETUP_MAXDATASIZE. The value is clamped to valid length + * of data in ep0data[] before SETUP OUT handler is called. Bytes that + * exceed the maximum length are discarded, but must be read out of the + * USB peripheral FIFO. + */ + + struct usb_ctrlreq_s ctrlreq; + uint8_t ep0data[CONFIG_USBDEV_SETUP_MAXDATASIZE]; + uint16_t ep0datlen; + + /* The endpoint lists */ + + struct at32_ep_s epin[AT32_NENDPOINTS]; + struct at32_ep_s epout[AT32_NENDPOINTS]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register operations ******************************************************/ + +#ifdef CONFIG_AT32_USBDEV_REGDEBUG +static uint32_t at32_getreg(uint32_t addr); +static void at32_putreg(uint32_t val, uint32_t addr); +#else +# define at32_getreg(addr) getreg32(addr) +# define at32_putreg(val,addr) putreg32(val,addr) +#endif + +/* Request queue operations *************************************************/ + +static struct at32_req_s *at32_req_remfirst( + struct at32_ep_s *privep); +static bool at32_req_addlast(struct at32_ep_s *privep, + struct at32_req_s *req); + +/* Low level data transfers and request operations **************************/ + +/* Special endpoint 0 data transfer logic */ + +static void at32_ep0in_setupresponse(struct at32_usbdev_s *priv, + uint8_t *data, uint32_t nbytes); +static inline void at32_ep0in_transmitzlp(struct at32_usbdev_s *priv); +static void at32_ep0in_activate(void); + +static void at32_ep0out_ctrlsetup(struct at32_usbdev_s *priv); + +/* IN request and TxFIFO handling */ + +static void at32_txfifo_write(struct at32_ep_s *privep, + uint8_t *buf, int nbytes); +static void at32_epin_transfer(struct at32_ep_s *privep, + uint8_t *buf, int nbytes); +static void at32_epin_request(struct at32_usbdev_s *priv, + struct at32_ep_s *privep); + +/* OUT request and RxFIFO handling */ + +static void at32_rxfifo_read(struct at32_ep_s *privep, + uint8_t *dest, uint16_t len); +static void at32_rxfifo_discard(struct at32_ep_s *privep, + int len); +static void at32_epout_complete(struct at32_usbdev_s *priv, + struct at32_ep_s *privep); +static inline void at32_ep0out_receive(struct at32_ep_s *privep, + int bcnt); +static inline void at32_epout_receive(struct at32_ep_s *privep, + int bcnt); +static void at32_epout_request(struct at32_usbdev_s *priv, + struct at32_ep_s *privep); + +/* General request handling */ + +static void at32_ep_flush(struct at32_ep_s *privep); +static void at32_req_complete(struct at32_ep_s *privep, + int16_t result); +static void at32_req_cancel(struct at32_ep_s *privep, + int16_t status); + +/* Interrupt handling *******************************************************/ + +static struct at32_ep_s *at32_ep_findbyaddr( + struct at32_usbdev_s *priv, + uint16_t eplog); +static int at32_req_dispatch(struct at32_usbdev_s *priv, + const struct usb_ctrlreq_s *ctrl); +static void at32_usbreset(struct at32_usbdev_s *priv); + +/* Second level OUT endpoint interrupt processing */ + +static inline void at32_ep0out_testmode(struct at32_usbdev_s *priv, + uint16_t index); +static inline void at32_ep0out_stdrequest(struct at32_usbdev_s *priv, + struct at32_ctrlreq_s *ctrlreq); +static inline void at32_ep0out_setup(struct at32_usbdev_s *priv); +static inline void at32_epout(struct at32_usbdev_s *priv, + uint8_t epno); +static inline void at32_epout_interrupt(struct at32_usbdev_s *priv); + +/* Second level IN endpoint interrupt processing */ + +static inline void at32_epin_runtestmode(struct at32_usbdev_s *priv); +static inline void at32_epin(struct at32_usbdev_s *priv, uint8_t epno); +static inline void at32_epin_txfifoempty(struct at32_usbdev_s *priv, + int epno); +static inline void at32_epin_interrupt(struct at32_usbdev_s *priv); + +/* Other second level interrupt processing */ + +static inline void at32_resumeinterrupt(struct at32_usbdev_s *priv); +static inline void at32_suspendinterrupt(struct at32_usbdev_s *priv); +static inline void at32_rxinterrupt(struct at32_usbdev_s *priv); +static inline void at32_enuminterrupt(struct at32_usbdev_s *priv); +#ifdef CONFIG_USBDEV_ISOCHRONOUS +static inline void at32_isocininterrupt(struct at32_usbdev_s *priv); +static inline void at32_isocoutinterrupt(struct at32_usbdev_s *priv); +#endif +#ifdef CONFIG_USBDEV_VBUSSENSING +static inline void at32_sessioninterrupt(struct at32_usbdev_s *priv); +static inline void at32_otginterrupt(struct at32_usbdev_s *priv); +#endif + +/* First level interrupt processing */ + +static int at32_usbinterrupt(int irq, void *context, + void *arg); + +/* Endpoint operations ******************************************************/ + +/* Global OUT NAK controls */ + +static void at32_enablegonak(struct at32_ep_s *privep); +static void at32_disablegonak(struct at32_ep_s *privep); + +/* Endpoint configuration */ + +static int at32_epout_configure(struct at32_ep_s *privep, + uint8_t eptype, uint16_t maxpacket); +static int at32_epin_configure(struct at32_ep_s *privep, + uint8_t eptype, uint16_t maxpacket); +static int at32_ep_configure(struct usbdev_ep_s *ep, + const struct usb_epdesc_s *desc, bool last); +static void at32_ep0_configure(struct at32_usbdev_s *priv); + +/* Endpoint disable */ + +static void at32_epout_disable(struct at32_ep_s *privep); +static void at32_epin_disable(struct at32_ep_s *privep); +static int at32_ep_disable(struct usbdev_ep_s *ep); + +/* Endpoint request management */ + +static struct usbdev_req_s *at32_ep_allocreq( + struct usbdev_ep_s *ep); +static void at32_ep_freereq(struct usbdev_ep_s *ep, + struct usbdev_req_s *); + +/* Endpoint buffer management */ + +#ifdef CONFIG_USBDEV_DMA +static void *at32_ep_allocbuffer(struct usbdev_ep_s *ep, + uint16_t bytes); +static void at32_ep_freebuffer(struct usbdev_ep_s *ep, + void *buf); +#endif + +/* Endpoint request submission */ + +static int at32_ep_submit(struct usbdev_ep_s *ep, + struct usbdev_req_s *req); + +/* Endpoint request cancellation */ + +static int at32_ep_cancel(struct usbdev_ep_s *ep, + struct usbdev_req_s *req); + +/* Stall handling */ + +static int at32_epout_setstall(struct at32_ep_s *privep); +static int at32_epin_setstall(struct at32_ep_s *privep); +static int at32_ep_setstall(struct at32_ep_s *privep); +static int at32_ep_clrstall(struct at32_ep_s *privep); +static int at32_ep_stall(struct usbdev_ep_s *ep, bool resume); +static void at32_ep0_stall(struct at32_usbdev_s *priv); + +/* Endpoint allocation */ + +static struct usbdev_ep_s *at32_ep_alloc(struct usbdev_s *dev, + uint8_t epno, bool in, uint8_t eptype); +static void at32_ep_free(struct usbdev_s *dev, + struct usbdev_ep_s *ep); + +/* USB device controller operations *****************************************/ + +static int at32_getframe(struct usbdev_s *dev); +static int at32_wakeup(struct usbdev_s *dev); +static int at32_selfpowered(struct usbdev_s *dev, bool selfpowered); +static int at32_pullup(struct usbdev_s *dev, bool enable); +static void at32_setaddress(struct at32_usbdev_s *priv, + uint16_t address); +static int at32_txfifo_flush(uint32_t txfnum); +static int at32_rxfifo_flush(void); + +/* Initialization ***********************************************************/ + +static void at32_swinitialize(struct at32_usbdev_s *priv); +static void at32_hwinitialize(struct at32_usbdev_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Since there is only a single USB interface, all status information can be + * be simply retained in a single global instance. + */ + +static struct at32_usbdev_s g_otgfsdev; + +static const struct usbdev_epops_s g_epops = +{ + .configure = at32_ep_configure, + .disable = at32_ep_disable, + .allocreq = at32_ep_allocreq, + .freereq = at32_ep_freereq, +#ifdef CONFIG_USBDEV_DMA + .allocbuffer = at32_ep_allocbuffer, + .freebuffer = at32_ep_freebuffer, +#endif + .submit = at32_ep_submit, + .cancel = at32_ep_cancel, + .stall = at32_ep_stall, +}; + +static const struct usbdev_ops_s g_devops = +{ + .allocep = at32_ep_alloc, + .freeep = at32_ep_free, + .getframe = at32_getframe, + .wakeup = at32_wakeup, + .selfpowered = at32_selfpowered, + .pullup = at32_pullup, +}; + +/* Device error strings that may be enabled for more descriptive USB trace + * output. + */ + +#ifdef CONFIG_USBDEV_TRACE_STRINGS +const struct trace_msg_t g_usb_trace_strings_deverror[] = +{ + TRACE_STR(AT32_TRACEERR_ALLOCFAIL), + TRACE_STR(AT32_TRACEERR_BADCLEARFEATURE), + TRACE_STR(AT32_TRACEERR_BADDEVGETSTATUS), + TRACE_STR(AT32_TRACEERR_BADEPNO), + TRACE_STR(AT32_TRACEERR_BADEPGETSTATUS), + TRACE_STR(AT32_TRACEERR_BADGETCONFIG), + TRACE_STR(AT32_TRACEERR_BADGETSETDESC), + TRACE_STR(AT32_TRACEERR_BADGETSTATUS), + TRACE_STR(AT32_TRACEERR_BADSETADDRESS), + TRACE_STR(AT32_TRACEERR_BADSETCONFIG), + TRACE_STR(AT32_TRACEERR_BADSETFEATURE), + TRACE_STR(AT32_TRACEERR_BADTESTMODE), + TRACE_STR(AT32_TRACEERR_BINDFAILED), + TRACE_STR(AT32_TRACEERR_DISPATCHSTALL), + TRACE_STR(AT32_TRACEERR_DRIVER), + TRACE_STR(AT32_TRACEERR_DRIVERREGISTERED), + TRACE_STR(AT32_TRACEERR_EP0NOSETUP), + TRACE_STR(AT32_TRACEERR_EP0SETUPSTALLED), + TRACE_STR(AT32_TRACEERR_EPINNULLPACKET), + TRACE_STR(AT32_TRACEERR_EPINUNEXPECTED), + TRACE_STR(AT32_TRACEERR_EPOUTNULLPACKET), + TRACE_STR(AT32_TRACEERR_EPOUTUNEXPECTED), + TRACE_STR(AT32_TRACEERR_INVALIDCTRLREQ), + TRACE_STR(AT32_TRACEERR_INVALIDPARMS), + TRACE_STR(AT32_TRACEERR_IRQREGISTRATION), + TRACE_STR(AT32_TRACEERR_NOEP), + TRACE_STR(AT32_TRACEERR_NOTCONFIGURED), + TRACE_STR(AT32_TRACEERR_EPOUTQEMPTY), + TRACE_STR(AT32_TRACEERR_EPINREQEMPTY), + TRACE_STR(AT32_TRACEERR_NOOUTSETUP), + TRACE_STR(AT32_TRACEERR_POLLTIMEOUT), + TRACE_STR_END +}; +#endif + +/* Interrupt event strings that may be enabled for more descriptive USB trace + * output. + */ + +#ifdef CONFIG_USBDEV_TRACE_STRINGS +const struct trace_msg_t g_usb_trace_strings_intdecode[] = +{ + TRACE_STR(AT32_TRACEINTID_USB), + TRACE_STR(AT32_TRACEINTID_INTPENDING), + TRACE_STR(AT32_TRACEINTID_EPOUT), + TRACE_STR(AT32_TRACEINTID_EPIN), + TRACE_STR(AT32_TRACEINTID_MISMATCH), + TRACE_STR(AT32_TRACEINTID_WAKEUP), + TRACE_STR(AT32_TRACEINTID_SUSPEND), + TRACE_STR(AT32_TRACEINTID_SOF), + TRACE_STR(AT32_TRACEINTID_RXFIFO), + TRACE_STR(AT32_TRACEINTID_DEVRESET), + TRACE_STR(AT32_TRACEINTID_ENUMDNE), + TRACE_STR(AT32_TRACEINTID_IISOIXFR), + TRACE_STR(AT32_TRACEINTID_IISOOXFR), + TRACE_STR(AT32_TRACEINTID_SRQ), + TRACE_STR(AT32_TRACEINTID_OTG), + TRACE_STR(AT32_TRACEINTID_EPOUT_XFRC), + TRACE_STR(AT32_TRACEINTID_EPOUT_EPDISD), + TRACE_STR(AT32_TRACEINTID_EPOUT_SETUP), + TRACE_STR(AT32_TRACEINTID_DISPATCH), + TRACE_STR(AT32_TRACEINTID_GETSTATUS), + TRACE_STR(AT32_TRACEINTID_EPGETSTATUS), + TRACE_STR(AT32_TRACEINTID_DEVGETSTATUS), + TRACE_STR(AT32_TRACEINTID_IFGETSTATUS), + TRACE_STR(AT32_TRACEINTID_CLEARFEATURE), + TRACE_STR(AT32_TRACEINTID_SETFEATURE), + TRACE_STR(AT32_TRACEINTID_SETADDRESS), + TRACE_STR(AT32_TRACEINTID_GETSETDESC), + TRACE_STR(AT32_TRACEINTID_GETCONFIG), + TRACE_STR(AT32_TRACEINTID_SETCONFIG), + TRACE_STR(AT32_TRACEINTID_GETSETIF), + TRACE_STR(AT32_TRACEINTID_SYNCHFRAME), + TRACE_STR(AT32_TRACEINTID_EPIN_XFRC), + TRACE_STR(AT32_TRACEINTID_EPIN_TOC), + TRACE_STR(AT32_TRACEINTID_EPIN_ITTXFE), + TRACE_STR(AT32_TRACEINTID_EPIN_EPDISD), + TRACE_STR(AT32_TRACEINTID_EPIN_TXFE), + TRACE_STR(AT32_TRACEINTID_EPIN_EMPWAIT), + TRACE_STR(AT32_TRACEINTID_OUTNAK), + TRACE_STR(AT32_TRACEINTID_OUTRECVD), + TRACE_STR(AT32_TRACEINTID_OUTDONE), + TRACE_STR(AT32_TRACEINTID_SETUPDONE), + TRACE_STR(AT32_TRACEINTID_SETUPRECVD), + TRACE_STR_END +}; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_getreg + * + * Description: + * Get the contents of an AT32 register + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_USBDEV_REGDEBUG +static uint32_t at32_getreg(uint32_t addr) +{ + static uint32_t prevaddr = 0; + static uint32_t preval = 0; + static uint32_t count = 0; + + /* Read the value from the register */ + + uint32_t val = getreg32(addr); + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (addr == prevaddr && val == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + uinfo("...\n"); + } + + return val; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + uinfo("[repeats %d more times]\n", count - 3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + preval = val; + count = 1; + } + + /* Show the register value read */ + + uinfo("%08x->%08x\n", addr, val); + return val; +} +#endif + +/**************************************************************************** + * Name: at32_putreg + * + * Description: + * Set the contents of an AT32 register to a value + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_USBDEV_REGDEBUG +static void at32_putreg(uint32_t val, uint32_t addr) +{ + /* Show the register value being written */ + + uinfo("%08x<-%08x\n", addr, val); + + /* Write the value */ + + putreg32(val, addr); +} +#endif + +/**************************************************************************** + * Name: at32_req_remfirst + * + * Description: + * Remove a request from the head of an endpoint request queue + * + ****************************************************************************/ + +static struct at32_req_s *at32_req_remfirst( + struct at32_ep_s *privep) +{ + struct at32_req_s *ret = privep->head; + + if (ret) + { + privep->head = ret->flink; + if (!privep->head) + { + privep->tail = NULL; + } + + ret->flink = NULL; + } + + return ret; +} + +/**************************************************************************** + * Name: at32_req_addlast + * + * Description: + * Add a request to the end of an endpoint request queue + * + ****************************************************************************/ + +static bool at32_req_addlast(struct at32_ep_s *privep, + struct at32_req_s *req) +{ + bool is_empty = !privep->head; + + req->flink = NULL; + if (is_empty) + { + privep->head = req; + privep->tail = req; + } + else + { + privep->tail->flink = req; + privep->tail = req; + } + + return is_empty; +} + +/**************************************************************************** + * Name: at32_ep0in_setupresponse + * + * Description: + * Schedule a short transfer on Endpoint 0 (IN or OUT) + * + ****************************************************************************/ + +static void at32_ep0in_setupresponse(struct at32_usbdev_s *priv, + uint8_t *buf, uint32_t nbytes) +{ + at32_epin_transfer(&priv->epin[EP0], buf, nbytes); + priv->ep0state = EP0STATE_SETUPRESPONSE; + at32_ep0out_ctrlsetup(priv); +} + +/**************************************************************************** + * Name: at32_ep0in_transmitzlp + * + * Description: + * Send a zero length packet (ZLP) on endpoint 0 IN + * + ****************************************************************************/ + +static inline void at32_ep0in_transmitzlp(struct at32_usbdev_s *priv) +{ + at32_ep0in_setupresponse(priv, NULL, 0); +} + +/**************************************************************************** + * Name: at32_ep0in_activate + * + * Description: + * Activate the endpoint 0 IN endpoint. + * + ****************************************************************************/ + +static void at32_ep0in_activate(void) +{ + uint32_t regval; + + /* Set the max packet size of the IN EP. */ + + regval = at32_getreg(AT32_OTGFS_DIEPCTL0); + regval &= ~OTGFS_DIEPCTL0_MPSIZ_MASK; + +#if CONFIG_USBDEV_EP0_MAXSIZE == 8 + regval |= OTGFS_DIEPCTL0_MPSIZ_8; +#elif CONFIG_USBDEV_EP0_MAXSIZE == 16 + regval |= OTGFS_DIEPCTL0_MPSIZ_16; +#elif CONFIG_USBDEV_EP0_MAXSIZE == 32 + regval |= OTGFS_DIEPCTL0_MPSIZ_32; +#elif CONFIG_USBDEV_EP0_MAXSIZE == 64 + regval |= OTGFS_DIEPCTL0_MPSIZ_64; +#else +# error "Unsupported value of CONFIG_USBDEV_EP0_MAXSIZE" +#endif + + at32_putreg(regval, AT32_OTGFS_DIEPCTL0); + + /* Clear global IN NAK */ + + regval = at32_getreg(AT32_OTGFS_DCTL); + regval |= OTGFS_DCTL_CGINAK; + at32_putreg(regval, AT32_OTGFS_DCTL); +} + +/**************************************************************************** + * Name: at32_ep0out_ctrlsetup + * + * Description: + * Setup to receive a SETUP packet. + * + ****************************************************************************/ + +static void at32_ep0out_ctrlsetup(struct at32_usbdev_s *priv) +{ + uint32_t regval; + + /* Setup the hardware to perform the SETUP transfer */ + + regval = (USB_SIZEOF_CTRLREQ * 3 << OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT) | + (OTGFS_DOEPTSIZ0_PKTCNT) | + (3 << OTGFS_DOEPTSIZ0_STUPCNT_SHIFT); + at32_putreg(regval, AT32_OTGFS_DOEPTSIZ0); + + /* Then clear NAKing and enable the transfer */ + + regval = at32_getreg(AT32_OTGFS_DOEPCTL0); + regval |= (OTGFS_DOEPCTL0_CNAK | OTGFS_DOEPCTL0_EPENA); + at32_putreg(regval, AT32_OTGFS_DOEPCTL0); +} + +/**************************************************************************** + * Name: at32_txfifo_write + * + * Description: + * Send data to the endpoint's TxFIFO. + * + ****************************************************************************/ + +static void at32_txfifo_write(struct at32_ep_s *privep, + uint8_t *buf, int nbytes) +{ + uint32_t regaddr; + uint32_t regval; + int nwords; + int i; + + /* Convert the number of bytes to words */ + + nwords = (nbytes + 3) >> 2; + + /* Get the TxFIFO for this endpoint (same as the endpoint number) */ + + regaddr = AT32_OTGFS_DFIFO_DEP(privep->epphy); + + /* Then transfer each word to the TxFIFO */ + + for (i = 0; i < nwords; i++) + { + /* Read four bytes from the source buffer (to avoid unaligned accesses) + * and pack these into one 32-bit word (little endian). + */ + + regval = (uint32_t)*buf++; + regval |= ((uint32_t)*buf++) << 8; + regval |= ((uint32_t)*buf++) << 16; + regval |= ((uint32_t)*buf++) << 24; + + /* Then write the packet data to the TxFIFO */ + + at32_putreg(regval, regaddr); + } +} + +/**************************************************************************** + * Name: at32_epin_transfer + * + * Description: + * Start the Tx data transfer + * + ****************************************************************************/ + +static void at32_epin_transfer(struct at32_ep_s *privep, + uint8_t *buf, int nbytes) +{ + uint32_t pktcnt; + uint32_t regval; + + /* Read the DIEPSIZx register */ + + regval = at32_getreg(AT32_OTGFS_DIEPTSIZ(privep->epphy)); + + /* Clear the XFRSIZ, PKTCNT, and MCNT field of the DIEPSIZx register */ + + regval &= ~(OTGFS_DIEPTSIZ_XFRSIZ_MASK | OTGFS_DIEPTSIZ_PKTCNT_MASK | + OTGFS_DIEPTSIZ_MCNT_MASK); + + /* Are we sending a zero length packet (ZLP) */ + + if (nbytes == 0) + { + /* Yes.. leave the transfer size at zero and set the packet count to + * 1 + */ + + pktcnt = 1; + } + else + { + /* No.. Program the transfer size and packet count . First calculate: + * + * xfrsize = The total number of bytes to be sent. + * pktcnt = the number of packets (of maxpacket bytes) required to + * perform the transfer. + */ + + pktcnt = ((uint32_t)nbytes + (privep->ep.maxpacket - 1)) / + privep->ep.maxpacket; + } + + /* Set the XFRSIZ and PKTCNT */ + + regval |= (pktcnt << OTGFS_DIEPTSIZ_PKTCNT_SHIFT); + regval |= ((uint32_t)nbytes << OTGFS_DIEPTSIZ_XFRSIZ_SHIFT); + + /* If this is an isochronous endpoint, then set the multi-count field to + * the PKTCNT as well. + */ + + if (privep->eptype == USB_EP_ATTR_XFER_ISOC) + { + regval |= (pktcnt << OTGFS_DIEPTSIZ_MCNT_SHIFT); + } + + /* Save DIEPSIZx register value */ + + at32_putreg(regval, AT32_OTGFS_DIEPTSIZ(privep->epphy)); + + /* Read the DIEPCTLx register */ + + regval = at32_getreg(AT32_OTGFS_DIEPCTL(privep->epphy)); + + /* If this is an isochronous endpoint, then set the even/odd frame bit + * the DIEPCTLx register. + */ + + if (privep->eptype == USB_EP_ATTR_XFER_ISOC) + { + /* Check bit 0 of the frame number of the received SOF and set the + * even/odd frame to match. + */ + + uint32_t status = at32_getreg(AT32_OTGFS_DSTS); + if ((status & OTGFS_DSTS_SOFFN0) == OTGFS_DSTS_SOFFN_EVEN) + { + regval |= OTGFS_DIEPCTL_SEVNFRM; + } + else + { + regval |= OTGFS_DIEPCTL_SODDFRM; + } + } + + /* EP enable, IN data in FIFO */ + + regval &= ~OTGFS_DIEPCTL_EPDIS; + regval |= (OTGFS_DIEPCTL_CNAK | OTGFS_DIEPCTL_EPENA); + at32_putreg(regval, AT32_OTGFS_DIEPCTL(privep->epphy)); + + /* Transfer the data to the TxFIFO. At this point, the caller has already + * assured that there is sufficient space in the TxFIFO to hold the + * transfer we can just blindly continue. + */ + + at32_txfifo_write(privep, buf, nbytes); +} + +/**************************************************************************** + * Name: at32_epin_request + * + * Description: + * Begin or continue write request processing. + * + ****************************************************************************/ + +static void at32_epin_request(struct at32_usbdev_s *priv, + struct at32_ep_s *privep) +{ + struct at32_req_s *privreq; + uint32_t regaddr; + uint32_t regval; + uint8_t *buf; + int nbytes; + int nwords; + int bytesleft; + + /* We get here in one of four possible ways. From three interrupting + * events: + * + * 1. From at32_epin as part of the transfer complete interrupt processing + * This interrupt indicates that the last transfer has completed. + * 2. As part of the ITTXFE interrupt processing. That interrupt indicates + * that an IN token was received when the associated TxFIFO was empty. + * 3. From at32_epin_txfifoempty as part of the TXFE interrupt processing. + * The TXFE interrupt is only enabled when the TxFIFO is full and the + * software must wait for space to become available in the TxFIFO. + * + * And this function may be called immediately when the write request is + * queue to start up the next transaction. + * + * 4. From at32_ep_submit when a new write request is received WHILE the + * endpoint is not active (privep->active == false). + */ + + /* Check the request from the head of the endpoint request queue */ + + privreq = at32_rqpeek(privep); + if (!privreq) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_EPINREQEMPTY), privep->epphy); + + /* There is no TX transfer in progress and no new pending TX + * requests to send. To stop transmitting any data on a particular + * IN endpoint, the application must set the IN NAK bit. To set this + * bit, the following field must be programmed. + */ + + regaddr = AT32_OTGFS_DIEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + regval |= OTGFS_DIEPCTL_SNAK; + at32_putreg(regval, regaddr); + + /* The endpoint is no longer active */ + + privep->active = false; + return; + } + + uinfo("EP%d req=%p: len=%d xfrd=%d zlp=%d\n", + privep->epphy, privreq, privreq->req.len, + privreq->req.xfrd, privep->zlp); + + /* Check for a special case: If we are just starting a request (xfrd==0) + * and the class driver is trying to send a zero-length packet (len==0). + * Then set the ZLP flag so that the packet will be sent. + */ + + if (privreq->req.len == 0) + { + /* The ZLP flag is set TRUE whenever we want to force the driver to + * send a zero-length-packet on the next pass through the loop (below). + * The flag is cleared whenever a packet is sent in the loop below. + */ + + privep->zlp = true; + } + + /* Add one more packet to the TxFIFO. We will wait for the transfer + * complete event before we add the next packet (or part of a packet + * to the TxFIFO). + * + * The documentation says that we can can multiple packets to the TxFIFO, + * but it seems that we need to get the transfer complete event before + * we can add the next (or maybe I have got something wrong?) + */ + +#if 0 + while (privreq->req.xfrd < privreq->req.len || privep->zlp) +#else + if (privreq->req.xfrd < privreq->req.len || privep->zlp) +#endif + { + /* Get the number of bytes left to be sent in the request */ + + bytesleft = privreq->req.len - privreq->req.xfrd; + nbytes = bytesleft; + + /* Assume no zero-length-packet on the next pass through this loop */ + + privep->zlp = false; + + /* Limit the size of the transfer to one full packet and handle + * zero-length packets (ZLPs). + */ + + if (nbytes > 0) + { + /* Either send the maxpacketsize or all of the remaining data in + * the request. + */ + + if (nbytes >= privep->ep.maxpacket) + { + nbytes = privep->ep.maxpacket; + + /* Handle the case where this packet is exactly the + * maxpacketsize. Do we need to send a zero-length packet + * in this case? + */ + + if (bytesleft == privep->ep.maxpacket && + (privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0) + { + /* The ZLP flag is set TRUE whenever we want to force + * the driver to send a zero-length-packet on the next + * pass through this loop. The flag is cleared (above) + * whenever we are committed to sending any packet and + * set here when we want to force one more pass through + * the loop. + */ + + privep->zlp = true; + } + } + } + + /* Get the transfer size in 32-bit words */ + + nwords = (nbytes + 3) >> 2; + + /* Get the number of 32-bit words available in the TxFIFO. The + * DXTFSTS indicates the amount of free space available in the + * endpoint TxFIFO. Values are in terms of 32-bit words: + * + * 0: Endpoint TxFIFO is full + * 1: 1 word available + * 2: 2 words available + * n: n words available + */ + + regaddr = AT32_OTGFS_DTXFSTS(privep->epphy); + + /* Check for space in the TxFIFO. If space in the TxFIFO is not + * available, then set up an interrupt to resume the transfer when + * the TxFIFO is empty. + */ + + regval = at32_getreg(regaddr); + if ((int)(regval & OTGFS_DTXFSTS_MASK) < nwords) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPIN_EMPWAIT), + (uint16_t)regval); + + /* There is insufficient space in the TxFIFO. Wait for a TxFIFO + * empty interrupt and try again. + */ + + uint32_t empmsk = at32_getreg(AT32_OTGFS_DIEPEMPMSK); + empmsk |= OTGFS_DIEPEMPMSK(privep->epphy); + at32_putreg(empmsk, AT32_OTGFS_DIEPEMPMSK); + + /* Terminate the transfer. We will try again when the TxFIFO empty + * interrupt is received. + */ + + return; + } + + /* Transfer data to the TxFIFO */ + + buf = privreq->req.buf + privreq->req.xfrd; + at32_epin_transfer(privep, buf, nbytes); + + /* If it was not before, the OUT endpoint is now actively transferring + * data. + */ + + privep->active = true; + + /* EP0 is a special case */ + + if (privep->epphy == EP0) + { + priv->ep0state = EP0STATE_DATA_IN; + } + + /* Update for the next time through the loop */ + + privreq->req.xfrd += nbytes; + } + + /* Note that the ZLP, if any, must be sent as a separate transfer. The + * need for a ZLP is indicated by privep->zlp. If all of the bytes were + * sent (including any final null packet) then we are finished with the + * transfer + */ + + if (privreq->req.xfrd >= privreq->req.len && !privep->zlp) + { + usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); + + /* We are finished with the request (although the transfer has not + * yet completed). + */ + + at32_req_complete(privep, OK); + } +} + +/**************************************************************************** + * Name: at32_rxfifo_read + * + * Description: + * Read packet from the RxFIFO into a read request. + * + ****************************************************************************/ + +static void at32_rxfifo_read(struct at32_ep_s *privep, + uint8_t *dest, uint16_t len) +{ + uint32_t regaddr; + int i; + + /* Get the address of the RxFIFO. Note: there is only one RxFIFO so + * we might as well use the address associated with EP0. + */ + + regaddr = AT32_OTGFS_DFIFO_DEP(EP0); + + /* Read 32-bits and write 4 x 8-bits at time (to avoid unaligned + * accesses) + */ + + for (i = 0; i < len; i += 4) + { + union + { + uint32_t w; + uint8_t b[4]; + } data; + + /* Read 1 x 32-bits of EP0 packet data */ + + data.w = at32_getreg(regaddr); + + /* Write 4 x 8-bits of EP0 packet data */ + + *dest++ = data.b[0]; + *dest++ = data.b[1]; + *dest++ = data.b[2]; + *dest++ = data.b[3]; + } +} + +/**************************************************************************** + * Name: at32_rxfifo_discard + * + * Description: + * Discard packet data from the RxFIFO. + * + ****************************************************************************/ + +static void at32_rxfifo_discard(struct at32_ep_s *privep, int len) +{ + if (len > 0) + { + uint32_t regaddr; + int i; + + /* Get the address of the RxFIFO Note: there is only one RxFIFO so + * we might as well use the address associated with EP0. + */ + + regaddr = AT32_OTGFS_DFIFO_DEP(EP0); + + /* Read 32-bits at time */ + + for (i = 0; i < len; i += 4) + { + volatile uint32_t data = at32_getreg(regaddr); + UNUSED(data); + } + } +} + +/**************************************************************************** + * Name: at32_epout_complete + * + * Description: + * This function is called when an OUT transfer complete interrupt is + * received. It completes the read request at the head of the endpoint's + * request queue. + * + ****************************************************************************/ + +static void at32_epout_complete(struct at32_usbdev_s *priv, + struct at32_ep_s *privep) +{ + struct at32_req_s *privreq; + + /* Since a transfer just completed, there must be a read request at the + * head of the endpoint request queue. + */ + + privreq = at32_rqpeek(privep); + DEBUGASSERT(privreq); + + if (!privreq) + { + /* An OUT transfer completed, but no packet to receive the data. This + * should not happen. + */ + + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_EPOUTQEMPTY), privep->epphy); + privep->active = false; + return; + } + + uinfo("EP%d: len=%d xfrd=%d\n", + privep->epphy, privreq->req.len, privreq->req.xfrd); + + /* Return the completed read request to the class driver and mark the state + * IDLE. + */ + + usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); + at32_req_complete(privep, OK); + privep->active = false; + + /* Now set up the next read request (if any) */ + + at32_epout_request(priv, privep); +} + +/**************************************************************************** + * Name: at32_ep0out_receive + * + * Description: + * This function is called from the RXFLVL interrupt handler when new + * incoming data is available in the endpoint's RxFIFO. This function + * will simply copy the incoming data into pending request's data buffer. + * + ****************************************************************************/ + +static inline void at32_ep0out_receive(struct at32_ep_s *privep, + int bcnt) +{ + struct at32_usbdev_s *priv; + + /* Sanity Checking */ + + DEBUGASSERT(privep && privep->ep.priv); + priv = (struct at32_usbdev_s *)privep->ep.priv; + + uinfo("EP0: bcnt=%d\n", bcnt); + usbtrace(TRACE_READ(EP0), bcnt); + + /* Verify that an OUT SETUP request as received before this data was + * received in the RxFIFO. + */ + + if (priv->ep0state == EP0STATE_SETUP_OUT) + { + if (priv->ep0datlen < CONFIG_USBDEV_SETUP_MAXDATASIZE) + { + /* Read the data into our special buffer for SETUP data */ + + int bufspace = CONFIG_USBDEV_SETUP_MAXDATASIZE - priv->ep0datlen; + int readlen = MIN(bufspace, bcnt); + at32_rxfifo_read(privep, priv->ep0data, readlen); + priv->ep0datlen += readlen; + bcnt -= readlen; + } + + /* Do we have to discard any excess bytes? */ + + if (bcnt > 0) + { + at32_rxfifo_discard(privep, bcnt); + priv->ep0datlen += bcnt; + } + + /* Is the transfer complete? */ + + if (priv->ep0datlen >= GETUINT16(priv->ctrlreq.len)) + { + /* Now we can process the setup command */ + + privep->active = false; + priv->ep0state = EP0STATE_SETUP_READY; + priv->ep0datlen = MIN(CONFIG_USBDEV_SETUP_MAXDATASIZE, + priv->ep0datlen); + + at32_ep0out_setup(priv); + } + else + { + /* More data to come, clear NAKSTS */ + + uint32_t regval = at32_getreg(AT32_OTGFS_DOEPCTL0); + regval |= OTGFS_DOEPCTL0_CNAK; + at32_putreg(regval, AT32_OTGFS_DOEPCTL0); + } + } + else + { + /* This is an error. We don't have any idea what to do with the EP0 + * data in this case. Just read and discard it so that the RxFIFO + * does not become constipated. + */ + + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_NOOUTSETUP), priv->ep0state); + at32_rxfifo_discard(privep, bcnt); + privep->active = false; + } +} + +/**************************************************************************** + * Name: at32_epout_receive + * + * Description: + * This function is called from the RXFLVL interrupt handler when new + * incoming data is available in the endpoint's RxFIFO. This function + * will simply copy the incoming data into pending request's data buffer. + * + ****************************************************************************/ + +static inline void at32_epout_receive(struct at32_ep_s *privep, + int bcnt) +{ + struct at32_req_s *privreq; + uint8_t *dest; + int buflen; + int readlen; + + /* Get a reference to the request at the head of the endpoint's request + * queue. + */ + + privreq = at32_rqpeek(privep); + if (!privreq) + { + /* Incoming data is available in the RxFIFO, but there is no read setup + * to receive the receive the data. This should not happen for data + * endpoints; those endpoints should have been NAKing any OUT data + * tokens. + * + * We should get here normally on OUT data phase following an OUT + * SETUP command. EP0 data will still receive data in this case and it + * should not be NAKing. + */ + + if (privep->epphy == 0) + { + at32_ep0out_receive(privep, bcnt); + } + else + { + /* Otherwise, the data is lost. This really should not happen if + * NAKing is working as expected. + */ + + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_EPOUTQEMPTY), + privep->epphy); + + /* Discard the data in the RxFIFO */ + + at32_rxfifo_discard(privep, bcnt); + } + + privep->active = false; + return; + } + + uinfo("EP%d: len=%d xfrd=%d\n", + privep->epphy, privreq->req.len, privreq->req.xfrd); + usbtrace(TRACE_READ(privep->epphy), bcnt); + + /* Get the number of bytes to transfer from the RxFIFO */ + + buflen = privreq->req.len - privreq->req.xfrd; + DEBUGASSERT(buflen > 0 && buflen >= bcnt); + readlen = MIN(buflen, bcnt); + + /* Get the destination of the data transfer */ + + dest = privreq->req.buf + privreq->req.xfrd; + + /* Transfer the data from the RxFIFO to the request's data buffer */ + + at32_rxfifo_read(privep, dest, readlen); + + /* If there were more bytes in the RxFIFO than could be held in the read + * request, then we will have to discard those. + */ + + at32_rxfifo_discard(privep, bcnt - readlen); + + /* Update the number of bytes transferred */ + + privreq->req.xfrd += readlen; +} + +/**************************************************************************** + * Name: at32_epout_request + * + * Description: + * This function is called when either (1) new read request is received, or + * (2) a pending receive request completes. If there is no read in + * pending, then this function will initiate the next OUT (read) operation. + * + ****************************************************************************/ + +static void at32_epout_request(struct at32_usbdev_s *priv, + struct at32_ep_s *privep) +{ + struct at32_req_s *privreq; + uint32_t regaddr; + uint32_t regval; + uint32_t xfrsize; + uint32_t pktcnt; + + /* Make sure that there is not already a pending request request. If + * there is, just return, leaving the newly received request in the + * request queue. + */ + + if (!privep->active) + { + /* Loop until a valid request is found (or the request queue is empty). + * The loop is only need to look at the request queue again is an + * invalid read request is encountered. + */ + + for (; ; ) + { + /* Get a reference to the request at the head of the endpoint's + * request queue + */ + + privreq = at32_rqpeek(privep); + if (!privreq) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_EPOUTQEMPTY), + privep->epphy); + + /* There are no read requests to be setup. Configure the + * hardware to NAK any incoming packets. (This should already + * be the case. I think that the hardware will automatically + * NAK after a transfer is completed until SNAK is cleared). + */ + + regaddr = AT32_OTGFS_DOEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + regval |= OTGFS_DOEPCTL_SNAK; + at32_putreg(regval, regaddr); + + /* This endpoint is no longer actively transferring */ + + privep->active = false; + return; + } + + uinfo("EP%d: len=%d\n", privep->epphy, privreq->req.len); + + /* Ignore any attempt to receive a zero length packet (this really + * should not happen. + */ + + if (privreq->req.len <= 0) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_EPOUTNULLPACKET), 0); + at32_req_complete(privep, OK); + } + + /* Otherwise, we have a usable read request... break out of the + * loop + */ + + else + { + break; + } + } + + /* Setup the pending read into the request buffer. First calculate: + * + * pktcnt = the number of packets (of maxpacket bytes) required to + * perform the transfer. + * xfrsize = The total number of bytes required (in units of + * maxpacket bytes). + */ + + pktcnt = (privreq->req.len + (privep->ep.maxpacket - 1)) / + privep->ep.maxpacket; + xfrsize = pktcnt * privep->ep.maxpacket; + + /* Then setup the hardware to perform this transfer */ + + regaddr = AT32_OTGFS_DOEPTSIZ(privep->epphy); + regval = at32_getreg(regaddr); + regval &= ~(OTGFS_DOEPTSIZ_XFRSIZ_MASK | OTGFS_DOEPTSIZ_PKTCNT_MASK); + regval |= (xfrsize << OTGFS_DOEPTSIZ_XFRSIZ_SHIFT); + regval |= (pktcnt << OTGFS_DOEPTSIZ_PKTCNT_SHIFT); + at32_putreg(regval, regaddr); + + /* Then enable the transfer */ + + regaddr = AT32_OTGFS_DOEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + + /* When an isochronous transfer is enabled the Even/Odd frame bit must + * also be set appropriately. + */ + +#ifdef CONFIG_USBDEV_ISOCHRONOUS + if (privep->eptype == USB_EP_ATTR_XFER_ISOC) + { + if (privep->odd) + { + regval |= OTGFS_DOEPCTL_SODDFRM; + } + else + { + regval |= OTGFS_DOEPCTL_SEVNFRM; + } + } +#endif + + /* Clearing NAKing and enable the transfer. */ + + regval |= (OTGFS_DOEPCTL_CNAK | OTGFS_DOEPCTL_EPENA); + at32_putreg(regval, regaddr); + + /* A transfer is now active on this endpoint */ + + privep->active = true; + + /* EP0 is a special case. We need to know when to switch back to + * normal SETUP processing. + */ + + if (privep->epphy == EP0) + { + priv->ep0state = EP0STATE_DATA_OUT; + } + } +} + +/**************************************************************************** + * Name: at32_ep_flush + * + * Description: + * Flush any primed descriptors from this ep + * + ****************************************************************************/ + +static void at32_ep_flush(struct at32_ep_s *privep) +{ + if (privep->isin) + { + at32_txfifo_flush(OTGFS_GRSTCTL_TXFNUM_D(privep->epphy)); + } + else + { + at32_rxfifo_flush(); + } +} + +/**************************************************************************** + * Name: at32_req_complete + * + * Description: + * Handle termination of the request at the head of the endpoint request + * queue. + * + ****************************************************************************/ + +static void at32_req_complete(struct at32_ep_s *privep, int16_t result) +{ + struct at32_req_s *privreq; + + /* Remove the request at the head of the request list */ + + privreq = at32_req_remfirst(privep); + DEBUGASSERT(privreq != NULL); + + /* If endpoint 0, temporarily reflect the state of protocol stalled + * in the callback. + */ + + bool stalled = privep->stalled; + if (privep->epphy == EP0) + { + privep->stalled = privep->dev->stalled; + } + + /* Save the result in the request structure */ + + privreq->req.result = result; + + /* Callback to the request completion handler */ + + privreq->req.callback(&privep->ep, &privreq->req); + + /* Restore the stalled indication */ + + privep->stalled = stalled; +} + +/**************************************************************************** + * Name: at32_req_cancel + * + * Description: + * Cancel all pending requests for an endpoint + * + ****************************************************************************/ + +static void at32_req_cancel(struct at32_ep_s *privep, int16_t status) +{ + if (!at32_rqempty(privep)) + { + at32_ep_flush(privep); + } + + while (!at32_rqempty(privep)) + { + usbtrace(TRACE_COMPLETE(privep->epphy), + (at32_rqpeek(privep))->req.xfrd); + at32_req_complete(privep, status); + } +} + +/**************************************************************************** + * Name: at32_ep_findbyaddr + * + * Description: + * Find the physical endpoint structure corresponding to a logic endpoint + * address + * + ****************************************************************************/ + +static struct at32_ep_s *at32_ep_findbyaddr(struct at32_usbdev_s *priv, + uint16_t eplog) +{ + struct at32_ep_s *privep; + uint8_t epphy = USB_EPNO(eplog); + + if (epphy >= AT32_NENDPOINTS) + { + return NULL; + } + + /* Is this an IN or an OUT endpoint? */ + + if (USB_ISEPIN(eplog)) + { + privep = &priv->epin[epphy]; + } + else + { + privep = &priv->epout[epphy]; + } + + /* Return endpoint reference */ + + DEBUGASSERT(privep->epphy == epphy); + return privep; +} + +/**************************************************************************** + * Name: at32_req_dispatch + * + * Description: + * Provide unhandled setup actions to the class driver. This is logically + * part of the USB interrupt handler. + * + ****************************************************************************/ + +static int at32_req_dispatch(struct at32_usbdev_s *priv, + const struct usb_ctrlreq_s *ctrl) +{ + int ret = -EIO; + + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_DISPATCH), 0); + if (priv->driver) + { + /* Forward to the control request to the class driver implementation */ + + ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl, + priv->ep0data, priv->ep0datlen); + } + + if (ret < 0) + { + /* Stall on failure */ + + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_DISPATCHSTALL), 0); + priv->stalled = true; + } + + return ret; +} + +/**************************************************************************** + * Name: at32_usbreset + * + * Description: + * Reset Usb engine + * + ****************************************************************************/ + +static void at32_usbreset(struct at32_usbdev_s *priv) +{ + struct at32_ep_s *privep; + uint32_t regval; + int i; + + /* Clear the Remote Wake-up Signaling */ + + regval = at32_getreg(AT32_OTGFS_DCTL); + regval &= ~OTGFS_DCTL_RWUSIG; + at32_putreg(regval, AT32_OTGFS_DCTL); + + /* Flush the EP0 Tx FIFO */ + + at32_txfifo_flush(OTGFS_GRSTCTL_TXFNUM_D(EP0)); + + /* Tell the class driver that we are disconnected. The class + * driver should then accept any new configurations. + */ + + if (priv->driver) + { + CLASS_DISCONNECT(priv->driver, &priv->usbdev); + } + + /* Mark all endpoints as available */ + + priv->epavail[0] = AT32_EP_AVAILABLE; + priv->epavail[1] = AT32_EP_AVAILABLE; + + /* Disable all end point interrupts */ + + for (i = 0; i < AT32_NENDPOINTS ; i++) + { + /* Disable endpoint interrupts */ + + at32_putreg(0xff, AT32_OTGFS_DIEPINT(i)); + at32_putreg(0xff, AT32_OTGFS_DOEPINT(i)); + + /* Return write requests to the class implementation */ + + privep = &priv->epin[i]; + at32_req_cancel(privep, -ESHUTDOWN); + + /* Reset IN endpoint status */ + + privep->stalled = false; + privep->active = false; + privep->zlp = false; + + /* Return read requests to the class implementation */ + + privep = &priv->epout[i]; + at32_req_cancel(privep, -ESHUTDOWN); + + /* Reset endpoint status */ + + privep->stalled = false; + privep->active = false; + privep->zlp = false; + } + + at32_putreg(0xffffffff, AT32_OTGFS_DAINT); + + /* Mask all device endpoint interrupts except EP0 */ + + regval = (OTGFS_DAINT_IEP(EP0) | OTGFS_DAINT_OEP(EP0)); + at32_putreg(regval, AT32_OTGFS_DAINTMSK); + + /* Unmask OUT interrupts */ + + regval = (OTGFS_DOEPMSK_XFRCM | OTGFS_DOEPMSK_STUPM | OTGFS_DOEPMSK_EPDM); + at32_putreg(regval, AT32_OTGFS_DOEPMSK); + + /* Unmask IN interrupts */ + + regval = (OTGFS_DIEPMSK_XFRCM | OTGFS_DIEPMSK_EPDM | OTGFS_DIEPMSK_TOM); + at32_putreg(regval, AT32_OTGFS_DIEPMSK); + + /* Reset device address to 0 */ + + at32_setaddress(priv, 0); + priv->devstate = DEVSTATE_DEFAULT; + priv->usbdev.speed = USB_SPEED_FULL; + + /* Re-configure EP0 */ + + at32_ep0_configure(priv); + + /* Setup EP0 to receive SETUP packets */ + + at32_ep0out_ctrlsetup(priv); +} + +/**************************************************************************** + * Name: at32_ep0out_testmode + * + * Description: + * Select test mode + * + ****************************************************************************/ + +static inline void at32_ep0out_testmode(struct at32_usbdev_s *priv, + uint16_t index) +{ + uint8_t testmode; + + testmode = index >> 8; + switch (testmode) + { + case 1: + priv->testmode = OTGFS_TESTMODE_J; + break; + + case 2: + priv->testmode = OTGFS_TESTMODE_K; + break; + + case 3: + priv->testmode = OTGFS_TESTMODE_SE0_NAK; + break; + + case 4: + priv->testmode = OTGFS_TESTMODE_PACKET; + break; + + case 5: + priv->testmode = OTGFS_TESTMODE_FORCE; + break; + + default: + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BADTESTMODE), testmode); + priv->dotest = false; + priv->testmode = OTGFS_TESTMODE_DISABLED; + priv->stalled = true; + } + + priv->dotest = true; + at32_ep0in_transmitzlp(priv); +} + +/**************************************************************************** + * Name: at32_ep0out_stdrequest + * + * Description: + * Handle a stanard request on EP0. Pick off the things of interest to the + * USB device controller driver; pass what is left to the class driver. + * + ****************************************************************************/ + +static inline void at32_ep0out_stdrequest(struct at32_usbdev_s *priv, + struct at32_ctrlreq_s * + ctrlreq) +{ + struct at32_ep_s *privep; + + /* Handle standard request */ + + switch (ctrlreq->req) + { + case USB_REQ_GETSTATUS: + { + /* type: device-to-host; recipient = device, interface, endpoint + * value: 0 + * index: zero interface endpoint + * len: 2; data = status + */ + + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_GETSTATUS), 0); + if (!priv->addressed || + ctrlreq->len != 2 || + USB_REQ_ISOUT(ctrlreq->type) || + ctrlreq->value != 0) + { + priv->stalled = true; + } + else + { + switch (ctrlreq->type & USB_REQ_RECIPIENT_MASK) + { + case USB_REQ_RECIPIENT_ENDPOINT: + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPGETSTATUS), 0); + privep = at32_ep_findbyaddr(priv, ctrlreq->index); + if (!privep) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BADEPGETSTATUS), + 0); + priv->stalled = true; + } + else + { + if (privep->stalled) + { + priv->ep0data[0] = (1 << USB_FEATURE_ENDPOINTHALT); + } + else + { + priv->ep0data[0] = 0; /* Not stalled */ + } + + priv->ep0data[1] = 0; + at32_ep0in_setupresponse(priv, priv->ep0data, 2); + } + } + break; + + case USB_REQ_RECIPIENT_DEVICE: + { + if (ctrlreq->index == 0) + { + usbtrace(TRACE_INTDECODE( + AT32_TRACEINTID_DEVGETSTATUS), + 0); + + /* Features: Remote Wakeup and self-powered */ + + priv->ep0data[0] = (priv->selfpowered << + USB_FEATURE_SELFPOWERED); + priv->ep0data[0] |= (priv->wakeup << + USB_FEATURE_REMOTEWAKEUP); + priv->ep0data[1] = 0; + + at32_ep0in_setupresponse(priv, priv->ep0data, 2); + } + else + { + usbtrace(TRACE_DEVERROR( + AT32_TRACEERR_BADDEVGETSTATUS), + 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_RECIPIENT_INTERFACE: + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_IFGETSTATUS), 0); + priv->ep0data[0] = 0; + priv->ep0data[1] = 0; + + at32_ep0in_setupresponse(priv, priv->ep0data, 2); + } + break; + + default: + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BADGETSTATUS), 0); + priv->stalled = true; + } + break; + } + } + } + break; + + case USB_REQ_CLEARFEATURE: + { + /* type: host-to-device; recipient = device, interface or endpoint + * value: feature selector + * index: zero interface endpoint; + * len: zero, data = none + */ + + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_CLEARFEATURE), 0); + if (priv->addressed != 0 && ctrlreq->len == 0) + { + uint8_t recipient = ctrlreq->type & USB_REQ_RECIPIENT_MASK; + if (recipient == USB_REQ_RECIPIENT_ENDPOINT && + ctrlreq->value == USB_FEATURE_ENDPOINTHALT && + (privep = at32_ep_findbyaddr(priv, ctrlreq->index)) != NULL) + { + at32_ep_clrstall(privep); + at32_ep0in_transmitzlp(priv); + } + else if (recipient == USB_REQ_RECIPIENT_DEVICE && + ctrlreq->value == USB_FEATURE_REMOTEWAKEUP) + { + priv->wakeup = 0; + at32_ep0in_transmitzlp(priv); + } + else + { + /* Actually, I think we could just stall here. */ + + at32_req_dispatch(priv, &priv->ctrlreq); + } + } + else + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BADCLEARFEATURE), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_SETFEATURE: + { + /* type: host-to-device; recipient = device, interface, endpoint + * value: feature selector + * index: zero interface endpoint; + * len: 0; data = none + */ + + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_SETFEATURE), 0); + if (priv->addressed != 0 && ctrlreq->len == 0) + { + uint8_t recipient = ctrlreq->type & USB_REQ_RECIPIENT_MASK; + if (recipient == USB_REQ_RECIPIENT_ENDPOINT && + ctrlreq->value == USB_FEATURE_ENDPOINTHALT && + (privep = at32_ep_findbyaddr(priv, ctrlreq->index)) != NULL) + { + at32_ep_setstall(privep); + at32_ep0in_transmitzlp(priv); + } + else if (recipient == USB_REQ_RECIPIENT_DEVICE && + ctrlreq->value == USB_FEATURE_REMOTEWAKEUP) + { + priv->wakeup = 1; + at32_ep0in_transmitzlp(priv); + } + else if (recipient == USB_REQ_RECIPIENT_DEVICE && + ctrlreq->value == USB_FEATURE_TESTMODE && + ((ctrlreq->index & 0xff) == 0)) + { + at32_ep0out_testmode(priv, ctrlreq->index); + } + else if (priv->configured) + { + /* Actually, I think we could just stall here. */ + + at32_req_dispatch(priv, &priv->ctrlreq); + } + else + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BADSETFEATURE), 0); + priv->stalled = true; + } + } + else + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BADSETFEATURE), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_SETADDRESS: + { + /* type: host-to-device; recipient = device + * value: device address + * index: 0 + * len: 0; data = none + */ + + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_SETADDRESS), + ctrlreq->value); + if ((ctrlreq->type & USB_REQ_RECIPIENT_MASK) == + USB_REQ_RECIPIENT_DEVICE && + ctrlreq->index == 0 && + ctrlreq->len == 0 && + ctrlreq->value < 128 && + priv->devstate != DEVSTATE_CONFIGURED) + { + /* Save the address. We cannot actually change to the next + * address until the completion of the status phase. + */ + + at32_setaddress(priv, (uint16_t)priv->ctrlreq.value[0]); + at32_ep0in_transmitzlp(priv); + } + else + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BADSETADDRESS), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_GETDESCRIPTOR: + /* type: device-to-host; recipient = device + * value: descriptor type and index + * index: 0 or language ID; + * len: descriptor len; data = descriptor + */ + + case USB_REQ_SETDESCRIPTOR: + /* type: host-to-device; recipient = device + * value: descriptor type and index + * index: 0 or language ID; + * len: descriptor len; data = descriptor + */ + + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_GETSETDESC), 0); + if ((ctrlreq->type & USB_REQ_RECIPIENT_MASK) == + USB_REQ_RECIPIENT_DEVICE) + { + at32_req_dispatch(priv, &priv->ctrlreq); + } + else + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BADGETSETDESC), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_GETCONFIGURATION: + /* type: device-to-host; recipient = device + * value: 0; + * index: 0; + * len: 1; data = configuration value + */ + + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_GETCONFIG), 0); + if (priv->addressed && + (ctrlreq->type & USB_REQ_RECIPIENT_MASK) == + USB_REQ_RECIPIENT_DEVICE && + ctrlreq->value == 0 && + ctrlreq->index == 0 && + ctrlreq->len == 1) + { + at32_req_dispatch(priv, &priv->ctrlreq); + } + else + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BADGETCONFIG), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_SETCONFIGURATION: + /* type: host-to-device; recipient = device + * value: configuration value + * index: 0; + * len: 0; data = none + */ + + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_SETCONFIG), 0); + if (priv->addressed && + (ctrlreq->type & USB_REQ_RECIPIENT_MASK) == + USB_REQ_RECIPIENT_DEVICE && + ctrlreq->index == 0 && + ctrlreq->len == 0) + { + /* Give the configuration to the class driver */ + + int ret = at32_req_dispatch(priv, &priv->ctrlreq); + + /* If the class driver accepted the configuration, then mark the + * device state as configured (or not, depending on the + * configuration). + */ + + if (ret == OK) + { + uint8_t cfg = (uint8_t)ctrlreq->value; + if (cfg != 0) + { + priv->devstate = DEVSTATE_CONFIGURED; + priv->configured = true; + } + else + { + priv->devstate = DEVSTATE_ADDRESSED; + priv->configured = false; + } + } + } + else + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BADSETCONFIG), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_GETINTERFACE: + /* type: device-to-host; recipient = interface + * value: 0 + * index: interface; + * len: 1; data = alt interface + */ + + case USB_REQ_SETINTERFACE: + /* type: host-to-device; recipient = interface + * value: alternate setting + * index: interface; + * len: 0; data = none + */ + + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_GETSETIF), 0); + at32_req_dispatch(priv, &priv->ctrlreq); + } + break; + + case USB_REQ_SYNCHFRAME: + /* type: device-to-host; recipient = endpoint + * value: 0 + * index: endpoint; + * len: 2; data = frame number + */ + + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_SYNCHFRAME), 0); + } + break; + + default: + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_INVALIDCTRLREQ), 0); + priv->stalled = true; + } + break; + } +} + +/**************************************************************************** + * Name: at32_ep0out_setup + * + * Description: + * USB Ctrl EP Setup Event. This is logically part of the USB interrupt + * handler. This event occurs when a setup packet is receive on EP0 OUT. + * + ****************************************************************************/ + +static inline void at32_ep0out_setup(struct at32_usbdev_s *priv) +{ + struct at32_ctrlreq_s ctrlreq; + + /* Verify that a SETUP was received */ + + if (priv->ep0state != EP0STATE_SETUP_READY) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_EP0NOSETUP), priv->ep0state); + return; + } + + /* Terminate any pending requests */ + + at32_req_cancel(&priv->epout[EP0], -EPROTO); + at32_req_cancel(&priv->epin[EP0], -EPROTO); + + /* Assume NOT stalled */ + + priv->epout[EP0].stalled = false; + priv->epin[EP0].stalled = false; + priv->stalled = false; + + /* Starting to process a control request - update state */ + + priv->ep0state = EP0STATE_SETUP_PROCESS; + + /* And extract the little-endian 16-bit values to host order */ + + ctrlreq.type = priv->ctrlreq.type; + ctrlreq.req = priv->ctrlreq.req; + ctrlreq.value = GETUINT16(priv->ctrlreq.value); + ctrlreq.index = GETUINT16(priv->ctrlreq.index); + ctrlreq.len = GETUINT16(priv->ctrlreq.len); + + uinfo("type=%02x req=%02x value=%04x index=%04x len=%04x\n", + ctrlreq.type, ctrlreq.req, ctrlreq.value, ctrlreq.index, + ctrlreq.len); + + /* Check for a standard request */ + + if ((ctrlreq.type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) + { + /* Dispatch any non-standard requests */ + + at32_req_dispatch(priv, &priv->ctrlreq); + } + else + { + /* Handle standard requests. */ + + at32_ep0out_stdrequest(priv, &ctrlreq); + } + + /* Check if the setup processing resulted in a STALL */ + + if (priv->stalled) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_EP0SETUPSTALLED), + priv->ep0state); + at32_ep0_stall(priv); + } + + /* Reset state/data associated with the SETUP request */ + + priv->ep0datlen = 0; +} + +/**************************************************************************** + * Name: at32_epout + * + * Description: + * This is part of the OUT endpoint interrupt processing. This function + * handles the OUT event for a single endpoint. + * + ****************************************************************************/ + +static inline void at32_epout(struct at32_usbdev_s *priv, uint8_t epno) +{ + struct at32_ep_s *privep; + + /* Endpoint 0 is a special case. */ + + if (epno == 0) + { + privep = &priv->epout[EP0]; + + /* In the EP0STATE_DATA_OUT state, we are receiving data into the + * request buffer. In that case, we must continue the request + * processing. + */ + + if (priv->ep0state == EP0STATE_DATA_OUT) + { + /* Continue processing data from the EP0 OUT request queue */ + + at32_epout_complete(priv, privep); + + /* If we are not actively processing an OUT request, then we + * need to setup to receive the next control request. + */ + + if (!privep->active) + { + at32_ep0out_ctrlsetup(priv); + priv->ep0state = EP0STATE_IDLE; + } + } + } + + /* For other endpoints, the only possibility is that we are continuing + * or finishing an OUT request. + */ + + else if (priv->devstate == DEVSTATE_CONFIGURED) + { + at32_epout_complete(priv, &priv->epout[epno]); + } +} + +/**************************************************************************** + * Name: at32_epout_interrupt + * + * Description: + * USB OUT endpoint interrupt handler. The core generates this interrupt + * when there is an interrupt is pending on one of the OUT endpoints of + * the core. + * The driver must read the OTGFS DAINT register to determine the exact + * number of the OUT endpoint on which the interrupt occurred, and then + * read the corresponding OTGFS DOEPINTx register to determine the exact + * cause of the interrupt. + * + ****************************************************************************/ + +static inline void at32_epout_interrupt(struct at32_usbdev_s *priv) +{ + uint32_t daint; + uint32_t regval; + uint32_t doepint; + int epno; + + /* Get the pending, enabled interrupts for the OUT endpoint from the + * endpoint interrupt status register. + */ + + regval = at32_getreg(AT32_OTGFS_DAINT); + regval &= at32_getreg(AT32_OTGFS_DAINTMSK); + daint = (regval & OTGFS_DAINT_OEP_MASK) >> OTGFS_DAINT_OEP_SHIFT; + + if (daint == 0) + { + /* We got an interrupt, but there is no unmasked endpoint that caused + * it ?! When this happens, the interrupt flag never gets cleared and + * we are stuck in infinite interrupt loop. + * + * This shouldn't happen if we are diligent about handling timing + * issues when masking endpoint interrupts. However, this workaround + * avoids infinite loop and allows operation to continue normally. It + * works by clearing each endpoint flags, masked or not. + */ + + regval = at32_getreg(AT32_OTGFS_DAINT); + daint = (regval & OTGFS_DAINT_OEP_MASK) >> OTGFS_DAINT_OEP_SHIFT; + + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_EPOUTUNEXPECTED), + (uint16_t)regval); + + epno = 0; + while (daint) + { + if ((daint & 1) != 0) + { + regval = at32_getreg(AT32_OTGFS_DOEPINT(epno)); + uinfo("DOEPINT(%d) = %08" PRIx32 "\n", epno, regval); + at32_putreg(0xff, AT32_OTGFS_DOEPINT(epno)); + } + + epno++; + daint >>= 1; + } + + return; + } + + /* Process each pending IN endpoint interrupt */ + + epno = 0; + while (daint) + { + /* Is an OUT interrupt pending for this endpoint? */ + + if ((daint & 1) != 0) + { + /* Yes.. get the OUT endpoint interrupt status */ + + doepint = at32_getreg(AT32_OTGFS_DOEPINT(epno)); + doepint &= at32_getreg(AT32_OTGFS_DOEPMSK); + + /* Transfer completed interrupt. This interrupt is triggered when + * at32_rxinterrupt() removes the last packet data from the + * RxFIFO. In this case, core internally sets the NAK bit for this + * endpoint to prevent it from receiving any more packets. + */ + + if ((doepint & OTGFS_DOEPINT_XFRC) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPOUT_XFRC), + (uint16_t)doepint); + + /* Clear the bit in DOEPINTn for this interrupt */ + + at32_putreg(OTGFS_DOEPINT_XFRC, AT32_OTGFS_DOEPINT(epno)); + + /* Handle the RX transfer data ready event */ + + at32_epout(priv, epno); + } + + /* Endpoint disabled interrupt (ignored because this interrupt is + * used in polled mode by the endpoint disable logic). + */ +#if 1 + /* REVISIT: */ + + if ((doepint & OTGFS_DOEPINT_EPDISD) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPOUT_EPDISD), + (uint16_t)doepint); + + /* Clear the bit in DOEPINTn for this interrupt */ + + at32_putreg(OTGFS_DOEPINT_EPDISD, AT32_OTGFS_DOEPINT(epno)); + } +#endif + + /* Setup Phase Done (control EPs) */ + + if ((doepint & OTGFS_DOEPINT_SETUP) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPOUT_SETUP), + priv->ep0state); + + /* Handle the receipt of the IN SETUP packets now (OUT setup + * packet processing may be delayed until the accompanying + * OUT DATA is received) + */ + + if (priv->ep0state == EP0STATE_SETUP_READY) + { + at32_ep0out_setup(priv); + } + + at32_putreg(OTGFS_DOEPINT_SETUP, AT32_OTGFS_DOEPINT(epno)); + } + } + + epno++; + daint >>= 1; + } +} + +/**************************************************************************** + * Name: at32_epin_runtestmode + * + * Description: + * Execute the test mode setup by the SET FEATURE request + * + ****************************************************************************/ + +static inline void at32_epin_runtestmode(struct at32_usbdev_s *priv) +{ + uint32_t regval = at32_getreg(AT32_OTGFS_DCTL); + regval &= OTGFS_DCTL_TCTL_MASK; + regval |= (uint32_t)priv->testmode << OTGFS_DCTL_TCTL_SHIFT; + at32_putreg(regval , AT32_OTGFS_DCTL); + + priv->dotest = 0; + priv->testmode = OTGFS_TESTMODE_DISABLED; +} + +/**************************************************************************** + * Name: at32_epin + * + * Description: + * This is part of the IN endpoint interrupt processing. This function + * handles the IN event for a single endpoint. + * + ****************************************************************************/ + +static inline void at32_epin(struct at32_usbdev_s *priv, uint8_t epno) +{ + struct at32_ep_s *privep = &priv->epin[epno]; + + /* Endpoint 0 is a special case. */ + + if (epno == 0) + { + /* In the EP0STATE_DATA_IN state, we are sending data from request + * buffer. In that case, we must continue the request processing. + */ + + if (priv->ep0state == EP0STATE_DATA_IN) + { + /* Continue processing data from the EP0 OUT request queue */ + + at32_epin_request(priv, privep); + + /* If we are not actively processing an OUT request, then we + * need to setup to receive the next control request. + */ + + if (!privep->active) + { + at32_ep0out_ctrlsetup(priv); + priv->ep0state = EP0STATE_IDLE; + } + } + + /* Test mode is another special case */ + + if (priv->dotest) + { + at32_epin_runtestmode(priv); + } + } + + /* For other endpoints, the only possibility is that we are continuing + * or finishing an IN request. + */ + + else if (priv->devstate == DEVSTATE_CONFIGURED) + { + /* Continue processing data from the endpoint write request queue */ + + at32_epin_request(priv, privep); + } +} + +/**************************************************************************** + * Name: at32_epin_txfifoempty + * + * Description: + * TxFIFO empty interrupt handling + * + ****************************************************************************/ + +static inline void at32_epin_txfifoempty(struct at32_usbdev_s *priv, + int epno) +{ + struct at32_ep_s *privep = &priv->epin[epno]; + + /* Continue processing the write request queue. This may mean sending + * more data from the existing request or terminating the current requests + * and (perhaps) starting the IN transfer from the next write request. + */ + + at32_epin_request(priv, privep); +} + +/**************************************************************************** + * Name: at32_epin_interrupt + * + * Description: + * USB IN endpoint interrupt handler. The core generates this interrupt + * when an interrupt is pending on one of the IN endpoints of the core. + * The driver must read the OTGFS DAINT register to determine the exact + * number of the IN endpoint on which the interrupt occurred, and then + * read the corresponding OTGFS DIEPINTx register to determine the exact + * cause of the interrupt. + * + ****************************************************************************/ + +static inline void at32_epin_interrupt(struct at32_usbdev_s *priv) +{ + uint32_t diepint; + uint32_t daint; + uint32_t mask; + uint32_t empty; + int epno; + + /* Get the pending, enabled interrupts for the IN endpoint from the + * endpoint interrupt status register. + */ + + daint = at32_getreg(AT32_OTGFS_DAINT); + daint &= at32_getreg(AT32_OTGFS_DAINTMSK); + daint &= OTGFS_DAINT_IEP_MASK; + + if (daint == 0) + { + /* We got an interrupt, but there is no unmasked endpoint that caused + * it ?! When this happens, the interrupt flag never gets cleared and + * we are stuck in infinite interrupt loop. + * + * This shouldn't happen if we are diligent about handling timing + * issues when masking endpoint interrupts. However, this workaround + * avoids infinite loop and allows operation to continue normally. It + * works by clearing each endpoint flags, masked or not. + */ + + daint = at32_getreg(AT32_OTGFS_DAINT); + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_EPINUNEXPECTED), + (uint16_t)daint); + + daint &= OTGFS_DAINT_IEP_MASK; + epno = 0; + + while (daint) + { + if ((daint & 1) != 0) + { + uinfo("DIEPINT(%d) = %08" PRIx32 "\n", + epno, at32_getreg(AT32_OTGFS_DIEPINT(epno))); + at32_putreg(0xff, AT32_OTGFS_DIEPINT(epno)); + } + + epno++; + daint >>= 1; + } + + return; + } + + /* Process each pending IN endpoint interrupt */ + + epno = 0; + while (daint) + { + /* Is an IN interrupt pending for this endpoint? */ + + if ((daint & 1) != 0) + { + /* Get IN interrupt mask register. Bits 0-6 correspond to enabled + * interrupts as will be found in the DIEPINT interrupt status + * register. + */ + + mask = at32_getreg(AT32_OTGFS_DIEPMSK); + + /* Check if the TxFIFO not empty interrupt is enabled for this + * endpoint in the DIEPMSK register. Bits n corresponds to + * endpoint n in the register. That condition corresponds to + * bit 7 of the DIEPINT interrupt status register. There is + * no TXFE bit in the mask register, so we fake one here. + */ + + empty = at32_getreg(AT32_OTGFS_DIEPEMPMSK); + if ((empty & OTGFS_DIEPEMPMSK(epno)) != 0) + { + mask |= OTGFS_DIEPINT_TXFE; + } + + /* Now, read the interrupt status and mask out all disabled + * interrupts. + */ + + diepint = at32_getreg(AT32_OTGFS_DIEPINT(epno)) & mask; + + /* Decode and process the enabled, pending interrupts */ + + /* Transfer completed interrupt */ + + if ((diepint & OTGFS_DIEPINT_XFRC) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPIN_XFRC), + (uint16_t)diepint); + + /* It is possible that logic may be waiting for a the + * TxFIFO to become empty. We disable the TxFIFO empty + * interrupt here; it will be re-enabled if there is still + * insufficient space in the TxFIFO. + */ + + empty &= ~OTGFS_DIEPEMPMSK(epno); + at32_putreg(empty, AT32_OTGFS_DIEPEMPMSK); + at32_putreg(OTGFS_DIEPINT_XFRC, AT32_OTGFS_DIEPINT(epno)); + + /* IN transfer complete */ + + at32_epin(priv, epno); + } + + /* Timeout condition */ + + if ((diepint & OTGFS_DIEPINT_TOC) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPIN_TOC), + (uint16_t)diepint); + at32_putreg(OTGFS_DIEPINT_TOC, AT32_OTGFS_DIEPINT(epno)); + } + + /* IN token received when TxFIFO is empty. Applies to + * non-periodic IN endpoints only. This interrupt indicates + * that an IN token was received when the associated TxFIFO + * (periodic/non-periodic) was empty. This interrupt is asserted + * on the endpoint for which the IN token was received. + */ + + if ((diepint & OTGFS_DIEPINT_ITTXFE) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPIN_ITTXFE), + (uint16_t)diepint); + at32_epin_request(priv, &priv->epin[epno]); + at32_putreg(OTGFS_DIEPINT_ITTXFE, AT32_OTGFS_DIEPINT(epno)); + } + + /* IN endpoint NAK effective (ignored as this used only in polled + * mode) + */ +#if 0 + if ((diepint & OTGFS_DIEPINT_INEPNE) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPIN_INEPNE), + (uint16_t)diepint); + at32_putreg(OTGFS_DIEPINT_INEPNE, AT32_OTGFS_DIEPINT(epno)); + } +#endif + + /* Endpoint disabled interrupt (ignored as this used only in polled + * mode) + */ +#if 0 + if ((diepint & OTGFS_DIEPINT_EPDISD) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPIN_EPDISD), + (uint16_t)diepint); + at32_putreg(OTGFS_DIEPINT_EPDISD, AT32_OTGFS_DIEPINT(epno)); + } +#endif + + /* Transmit FIFO empty */ + + if ((diepint & OTGFS_DIEPINT_TXFE) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPIN_TXFE), + (uint16_t)diepint); + + /* If we were waiting for TxFIFO to become empty, the we might + * have both XFRC and TXFE interrupts pending. Since we do + * the same thing for both cases, ignore the TXFE if we have + * already processed the XFRC. + */ + + if ((diepint & OTGFS_DIEPINT_XFRC) == 0) + { + /* Mask further FIFO empty interrupts. This will be + * re-enabled whenever we need to wait for a FIFO event. + */ + + empty &= ~OTGFS_DIEPEMPMSK(epno); + at32_putreg(empty, AT32_OTGFS_DIEPEMPMSK); + + /* Handle TxFIFO empty */ + + at32_epin_txfifoempty(priv, epno); + } + + /* Clear the pending TxFIFO empty interrupt */ + + at32_putreg(OTGFS_DIEPINT_TXFE, AT32_OTGFS_DIEPINT(epno)); + } + } + + epno++; + daint >>= 1; + } +} + +/**************************************************************************** + * Name: at32_resumeinterrupt + * + * Description: + * Resume/remote wakeup detected interrupt + * + ****************************************************************************/ + +static inline void at32_resumeinterrupt(struct at32_usbdev_s *priv) +{ + uint32_t regval; + + /* Clear remote wake-up signaling */ + + regval = at32_getreg(AT32_OTGFS_DCTL); + regval &= ~OTGFS_DCTL_RWUSIG; + at32_putreg(regval, AT32_OTGFS_DCTL); + + /* Restore full power -- whatever that means for this particular board */ + + at32_usbsuspend((struct usbdev_s *)priv, true); + + /* Notify the class driver of the resume event */ + + if (priv->driver) + { + CLASS_RESUME(priv->driver, &priv->usbdev); + } +} + +/**************************************************************************** + * Name: at32_suspendinterrupt + * + * Description: + * USB suspend interrupt + * + ****************************************************************************/ + +static inline void at32_suspendinterrupt(struct at32_usbdev_s *priv) +{ + /* Notify the class driver of the suspend event */ + + if (priv->driver) + { + CLASS_SUSPEND(priv->driver, &priv->usbdev); + } + + /* Let the board-specific logic know that we have entered the suspend + * state + */ + + at32_usbsuspend((struct usbdev_s *)priv, false); +} + +/**************************************************************************** + * Name: at32_rxinterrupt + * + * Description: + * RxFIFO non-empty interrupt. This interrupt indicates that there is at + * least one packet pending to be read from the RxFIFO. + * + ****************************************************************************/ + +static inline void at32_rxinterrupt(struct at32_usbdev_s *priv) +{ + struct at32_ep_s *privep; + uint32_t regval; + int bcnt; + int epphy; + + /* Disable the Rx status queue level interrupt */ + + while (0 != (at32_getreg(AT32_OTGFS_GINTSTS) & OTGFS_GINT_RXFLVL)) + { + /* Get the status from the top of the FIFO */ + + regval = at32_getreg(AT32_OTGFS_GRXSTSP); + + /* Decode status fields */ + + epphy = (regval & OTGFS_GRXSTSD_EPNUM_MASK) >> + OTGFS_GRXSTSD_EPNUM_SHIFT; + + /* Workaround for bad values read from the AT32_OTGFS_GRXSTSP register + * happens regval is 0xb4e48168 or 0xa80c9367 or 267E781c + * All of which provide out of range indexes for epout[epphy] + */ + + if (epphy < AT32_NENDPOINTS) + { + privep = &priv->epout[epphy]; + + /* Handle the RX event according to the packet status field */ + + switch (regval & OTGFS_GRXSTSD_PKTSTS_MASK) + { + /* Global OUT NAK. This indicate that the global OUT NAK bit + * has taken effect. + * + * PKTSTS = Global OUT NAK, BCNT = 0, EPNUM = Don't Care, + * DPID = Don't Care. + */ + + case OTGFS_GRXSTSD_PKTSTS_OUTNAK: + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_OUTNAK), 0); + } + break; + + /* OUT data packet received. + * + * PKTSTS = DataOUT, BCNT = size of the received data OUT packet, + * EPNUM = EPNUM on which the packet was received, DPID = Actual + * Data PID. + */ + + case OTGFS_GRXSTSD_PKTSTS_OUTRECVD: + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_OUTRECVD), epphy); + bcnt = (regval & OTGFS_GRXSTSD_BCNT_MASK) >> + OTGFS_GRXSTSD_BCNT_SHIFT; + if (bcnt > 0) + { + at32_epout_receive(privep, bcnt); + } + } + break; + + /* OUT transfer completed. This indicates that an OUT data + * transfer for the specified OUT endpoint has completed. + * After this entry is popped from the receive FIFO, the core + * asserts a Transfer Completed interrupt on the specified OUT + * endpoint. + * + * PKTSTS = Data OUT Transfer Done, BCNT = 0, EPNUM = OUT EP + * Num on which the data transfer is complete, DPID = Don't Care. + */ + + case OTGFS_GRXSTSD_PKTSTS_OUTDONE: + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_OUTDONE), epphy); + } + break; + + /* SETUP transaction completed. This indicates that the Setup + * stage for the specified endpoint has completed and the Data + * stage has started. + * After this entry is popped from the receive FIFO, the core + * asserts a Setup interrupt on the specified control OUT + * endpoint (triggers an interrupt). + * + * PKTSTS = Setup Stage Done, BCNT = 0, EPNUM = Control EP Num, + * DPID = Don't Care. + */ + + case OTGFS_GRXSTSD_PKTSTS_SETUPDONE: + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_SETUPDONE), epphy); + + /* Now that the Setup Phase is complete if it was an OUT + * enable the endpoint + * (Doing this here prevents the loss of the first FIFO word) + */ + + if (priv->ep0state == EP0STATE_SETUP_OUT) + { + /* Clear NAKSTS so that we can receive the data */ + + regval = at32_getreg(AT32_OTGFS_DOEPCTL0); + regval |= OTGFS_DOEPCTL0_CNAK; + at32_putreg(regval, AT32_OTGFS_DOEPCTL0); + } + } + break; + + /* SETUP data packet received. This indicates that a SETUP + * packet for the specified endpoint is now available for + * reading from the receive FIFO. + * + * PKTSTS = SETUP, BCNT = 8, EPNUM = Control EP Num, DPID = D0. + */ + + case OTGFS_GRXSTSD_PKTSTS_SETUPRECVD: + { + uint16_t datlen; + + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_SETUPRECVD), + epphy); + + /* Read EP0 setup data. NOTE: If multiple SETUP packets are + * received, the last one overwrites the previous setup + * packets and only that last SETUP packet will be processed. + */ + + at32_rxfifo_read(&priv->epout[EP0], + (uint8_t *)&priv->ctrlreq, + USB_SIZEOF_CTRLREQ); + + /* Was this an IN or an OUT SETUP packet. If it is an OUT + * SETUP, then we need to wait for the completion of the + * data phase to process the setup command. If it is an + * IN SETUP packet, then we must processing the command + * BEFORE we enter the DATA phase. + * + * If the data associated with the OUT SETUP packet is zero + * length, then, of course, we don't need to wait. + */ + + datlen = GETUINT16(priv->ctrlreq.len); + if (USB_REQ_ISOUT(priv->ctrlreq.type) && datlen > 0) + { + /* Wait for the data phase. */ + + priv->ep0state = EP0STATE_SETUP_OUT; + priv->ep0datlen = 0; + } + else + { + /* We can process the setup data as soon as SETUP done + * word is popped of the RxFIFO. + */ + + priv->ep0state = EP0STATE_SETUP_READY; + } + } + break; + + default: + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_INVALIDPARMS), + (regval & OTGFS_GRXSTSD_PKTSTS_MASK) >> + OTGFS_GRXSTSD_PKTSTS_SHIFT); + } + break; + } + } + } +} + +/**************************************************************************** + * Name: at32_enuminterrupt + * + * Description: + * Enumeration done interrupt + * + ****************************************************************************/ + +static inline void at32_enuminterrupt(struct at32_usbdev_s *priv) +{ + uint32_t regval; + + /* Activate EP0 */ + + at32_ep0in_activate(); + + /* Set USB turn-around time for the full speed device with internal PHY + * interface. + */ + + regval = at32_getreg(AT32_OTGFS_GUSBCFG); + regval &= ~OTGFS_GUSBCFG_TRDT_MASK; + regval |= OTGFS_GUSBCFG_TRDT(6); + at32_putreg(regval, AT32_OTGFS_GUSBCFG); +} + +/**************************************************************************** + * Name: at32_isocininterrupt + * + * Description: + * Incomplete isochronous IN transfer interrupt. Assertion of the + * incomplete isochronous IN transfer interrupt indicates an incomplete + * isochronous IN transfer on at least one of the isochronous IN endpoints. + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_ISOCHRONOUS +static inline void at32_isocininterrupt(struct at32_usbdev_s *priv) +{ + int i; + + /* The application must read the endpoint control register for all + * isochronous IN endpoints to detect endpoints with incomplete IN data + * transfers. + */ + + for (i = 0; i < AT32_NENDPOINTS; i++) + { + /* Is this an isochronous IN endpoint? */ + + privep = &priv->epin[i]; + if (privep->eptype != USB_EP_ATTR_XFER_ISOC) + { + /* No... keep looking */ + + continue; + } + + /* Is there an active read request on the isochronous OUT endpoint? */ + + if (!privep->active) + { + /* No.. the endpoint is not actively transmitting data */ + + continue; + } + + /* Check if this is the endpoint that had the incomplete transfer */ + + regaddr = AT32_OTGFS_DIEPCTL(privep->epphy); + doepctl = at32_getreg(regaddr); + dsts = at32_getreg(AT32_OTGFS_DSTS); + + /* EONUM = 0:even frame, 1:odd frame + * SOFFN = Frame number of the received SOF + */ + + eonum = ((doepctl & OTGFS_DIEPCTL_EONUM) != 0); + soffn = ((dsts & OTGFS_DSTS_SOFFN0) != 0); + + if (eonum != soffn) + { + /* Not this endpoint */ + + continue; + } + + /* For isochronous IN endpoints with incomplete transfers, + * the application must discard the data in the memory and + * disable the endpoint. + */ + + at32_req_complete(privep, -EIO); +#warning "Will clear OTGFS_DIEPCTL_USBAEP too" + at32_epin_disable(privep); + break; + } +} +#endif + +/**************************************************************************** + * Name: at32_isocoutinterrupt + * + * Description: + * Incomplete periodic transfer interrupt + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_ISOCHRONOUS +static inline void at32_isocoutinterrupt(struct at32_usbdev_s *priv) +{ + struct at32_ep_s *privep; + struct at32_req_s *privreq; + uint32_t regaddr; + uint32_t doepctl; + uint32_t dsts; + bool eonum; + bool soffn; + + /* When it receives an IISOOXFR interrupt, the application must read the + * control registers of all isochronous OUT endpoints to determine which + * endpoints had an incomplete transfer in the current microframe. An + * endpoint transfer is incomplete if both the following conditions are + * true: + * + * DOEPCTLx:EONUM = DSTS:SOFFN[0], and + * DOEPCTLx:EPENA = 1 + */ + + for (i = 0; i < AT32_NENDPOINTS; i++) + { + /* Is this an isochronous OUT endpoint? */ + + privep = &priv->epout[i]; + if (privep->eptype != USB_EP_ATTR_XFER_ISOC) + { + /* No... keep looking */ + + continue; + } + + /* Is there an active read request on the isochronous OUT endpoint? */ + + if (!privep->active) + { + /* No.. the endpoint is not actively transmitting data */ + + continue; + } + + /* Check if this is the endpoint that had the incomplete transfer */ + + regaddr = AT32_OTGFS_DOEPCTL(privep->epphy); + doepctl = at32_getreg(regaddr); + dsts = at32_getreg(AT32_OTGFS_DSTS); + + /* EONUM = 0:even frame, 1:odd frame + * SOFFN = Frame number of the received SOF + */ + + eonum = ((doepctl & OTGFS_DOEPCTL_EONUM) != 0); + soffn = ((dsts & OTGFS_DSTS_SOFFN0) != 0); + + if (eonum != soffn) + { + /* Not this endpoint */ + + continue; + } + + /* For isochronous OUT endpoints with incomplete transfers, + * the application must discard the data in the memory and + * disable the endpoint. + */ + + at32_req_complete(privep, -EIO); +#warning "Will clear OTGFS_DOEPCTL_USBAEP too" + at32_epout_disable(privep); + break; + } +} +#endif + +/**************************************************************************** + * Name: at32_sessioninterrupt + * + * Description: + * Session request/new session detected interrupt + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_VBUSSENSING +static inline void at32_sessioninterrupt(struct at32_usbdev_s *priv) +{ +#warning "Missing logic" +} +#endif + +/**************************************************************************** + * Name: at32_otginterrupt + * + * Description: + * OTG interrupt + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_VBUSSENSING +static inline void at32_otginterrupt(struct at32_usbdev_s *priv) +{ + uint32_t regval; + + /* Check for session end detected */ + + regval = at32_getreg(AT32_OTGFS_GOTGINT); + if ((regval & OTGFS_GOTGINT_SEDET) != 0) + { +#warning "Missing logic" + } + + /* Clear OTG interrupt */ + + at32_putreg(regval, AT32_OTGFS_GOTGINT); +} +#endif + +/**************************************************************************** + * Name: at32_usbinterrupt + * + * Description: + * USB interrupt handler + * + ****************************************************************************/ + +static int at32_usbinterrupt(int irq, void *context, void *arg) +{ + /* At present, there is only a single OTG FS device support. Hence it is + * pre-allocated as g_otgfsdev. However, in most code, the private data + * structure will be referenced using the 'priv' pointer (rather than the + * global data) in order to simplify any future support for multiple + * devices. + */ + + struct at32_usbdev_s *priv = &g_otgfsdev; + uint32_t regval; + uint32_t reserved; + + usbtrace(TRACE_INTENTRY(AT32_TRACEINTID_USB), 0); + + /* Assure that we are in device mode */ + + DEBUGASSERT((at32_getreg(AT32_OTGFS_GINTSTS) & OTGFS_GINTSTS_CMOD) == + OTGFS_GINTSTS_DEVMODE); + + /* Get the state of all enabled interrupts. We will do this repeatedly + * some interrupts (like RXFLVL) will generate additional interrupting + * events. + */ + + for (; ; ) + { + /* Get the set of pending, un-masked interrupts */ + + regval = at32_getreg(AT32_OTGFS_GINTSTS); + reserved = (regval & OTGFS_GINT_RESERVED); + regval &= at32_getreg(AT32_OTGFS_GINTMSK); + + /* With out modifying the reserved bits, acknowledge all + * **Writable** pending irqs we will service below + */ + + at32_putreg(((regval | reserved) & OTGFS_GINT_RC_W1), + AT32_OTGFS_GINTSTS); + + /* Break out of the loop when there are no further pending (and + * unmasked) interrupts to be processes. + */ + + if (regval == 0) + { + break; + } + + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_INTPENDING), + (uint16_t)regval); + + /* OUT endpoint interrupt. The core sets this bit to indicate that an + * interrupt is pending on one of the OUT endpoints of the core. + */ + + if ((regval & OTGFS_GINT_OEP) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPOUT), + (uint16_t)regval); + at32_epout_interrupt(priv); + } + + /* IN endpoint interrupt. The core sets this bit to indicate that + * an interrupt is pending on one of the IN endpoints of the core. + */ + + if ((regval & OTGFS_GINT_IEP) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_EPIN), (uint16_t)regval); + at32_epin_interrupt(priv); + } + + /* Host/device mode mismatch error interrupt */ + +#ifdef CONFIG_DEBUG_USB + if ((regval & OTGFS_GINT_MMIS) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_MISMATCH), + (uint16_t)regval); + } +#endif + + /* Resume/remote wakeup detected interrupt */ + + if ((regval & OTGFS_GINT_WKUP) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_WAKEUP), + (uint16_t)regval); + at32_resumeinterrupt(priv); + } + + /* USB suspend interrupt */ + + if ((regval & OTGFS_GINT_USBSUSP) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_SUSPEND), + (uint16_t)regval); + at32_suspendinterrupt(priv); + } + + /* Start of frame interrupt */ + +#ifdef CONFIG_USBDEV_SOFINTERRUPT + if ((regval & OTGFS_GINT_SOF) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_SOF), (uint16_t)regval); + } +#endif + + /* RxFIFO non-empty interrupt. Indicates that there is at least one + * packet pending to be read from the RxFIFO. + */ + + if ((regval & OTGFS_GINT_RXFLVL) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_RXFIFO), + (uint16_t)regval); + at32_rxinterrupt(priv); + } + + /* USB reset interrupt */ + + if ((regval & OTGFS_GINT_RESETS) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_DEVRESET), + (uint16_t)regval); + + /* Perform the device reset */ + + at32_usbreset(priv); + usbtrace(TRACE_INTEXIT(AT32_TRACEINTID_USB), 0); + return OK; + } + + /* Enumeration done interrupt */ + + if ((regval & OTGFS_GINT_ENUMDNE) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_ENUMDNE), + (uint16_t)regval); + at32_enuminterrupt(priv); + } + + /* Incomplete isochronous IN transfer interrupt. When the core finds + * non-empty any of the isochronous IN endpoint FIFOs scheduled for + * the current frame non-empty, the core generates an IISOIXFR + * interrupt. + */ + +#ifdef CONFIG_USBDEV_ISOCHRONOUS + if ((regval & OTGFS_GINT_IISOIXFR) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_IISOIXFR), + (uint16_t)regval); + at32_isocininterrupt(priv); + } + + /* Incomplete isochronous OUT transfer. For isochronous OUT + * endpoints, the XFRC interrupt may not always be asserted. If the + * core drops isochronous OUT data packets, the application could fail + * to detect the XFRC interrupt. The incomplete Isochronous OUT data + * interrupt indicates that an XFRC interrupt was not asserted on at + * least one of the isochronous OUT endpoints. At this point, the + * endpoint with the incomplete transfer remains enabled, but no active + * transfers remain in progress on this endpoint on the USB. + */ + + if ((regval & OTGFS_GINT_IISOOXFR) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_IISOOXFR), + (uint16_t)regval); + at32_isocoutinterrupt(priv); + } +#endif + + /* Session request/new session detected interrupt */ + +#ifdef CONFIG_USBDEV_VBUSSENSING + if ((regval & OTGFS_GINT_SRQ) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_SRQ), (uint16_t)regval); + at32_sessioninterrupt(priv); + } + + /* OTG interrupt */ + + if ((regval & OTGFS_GINT_OTG) != 0) + { + usbtrace(TRACE_INTDECODE(AT32_TRACEINTID_OTG), (uint16_t)regval); + at32_otginterrupt(priv); + } +#endif + } + + usbtrace(TRACE_INTEXIT(AT32_TRACEINTID_USB), 0); + return OK; +} + +/**************************************************************************** + * Endpoint operations + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_enablegonak + * + * Description: + * Enable global OUT NAK mode + * + ****************************************************************************/ + +static void at32_enablegonak(struct at32_ep_s *privep) +{ + uint32_t regval; + + /* First, make sure that there is no GNOAKEFF interrupt pending. */ + +#if 0 + at32_putreg(OTGFS_GINT_GONAKEFF, AT32_OTGFS_GINTSTS); +#endif + + /* Enable Global OUT NAK mode in the core. */ + + regval = at32_getreg(AT32_OTGFS_DCTL); + regval |= OTGFS_DCTL_SGONAK; + at32_putreg(regval, AT32_OTGFS_DCTL); + +#if 0 + /* Wait for the GONAKEFF interrupt that indicates that the OUT NAK + * mode is in effect. When the interrupt handler pops the OUTNAK word + * from the RxFIFO, the core sets the GONAKEFF interrupt. + */ + + while ((at32_getreg(AT32_OTGFS_GINTSTS) & OTGFS_GINT_GONAKEFF) == 0); + at32_putreg(OTGFS_GINT_GONAKEFF, AT32_OTGFS_GINTSTS); + +#else + /* Since we are in the interrupt handler, we cannot wait inline for the + * GONAKEFF because it cannot occur until service the RXFLVL global + * interrupt and pop the OUTNAK word from the RxFIFO. + * + * Perhaps it is sufficient to wait for Global OUT NAK status to be + * reported in OTGFS DCTL register? + */ + + while ((at32_getreg(AT32_OTGFS_DCTL) & OTGFS_DCTL_GONSTS) == 0); +#endif +} + +/**************************************************************************** + * Name: at32_disablegonak + * + * Description: + * Disable global OUT NAK mode + * + ****************************************************************************/ + +static void at32_disablegonak(struct at32_ep_s *privep) +{ + uint32_t regval; + + /* Set the "Clear the Global OUT NAK bit" to disable global OUT NAK mode */ + + regval = at32_getreg(AT32_OTGFS_DCTL); + regval |= OTGFS_DCTL_CGONAK; + at32_putreg(regval, AT32_OTGFS_DCTL); +} + +/**************************************************************************** + * Name: at32_epout_configure + * + * Description: + * Configure an OUT endpoint, making it usable + * + * Input Parameters: + * privep - a pointer to an internal endpoint structure + * eptype - The type of the endpoint + * maxpacket - The max packet size of the endpoint + * + ****************************************************************************/ + +static int at32_epout_configure(struct at32_ep_s *privep, + uint8_t eptype, + uint16_t maxpacket) +{ + uint32_t mpsiz; + uint32_t regaddr; + uint32_t regval; + + usbtrace(TRACE_EPCONFIGURE, privep->epphy); + + /* For EP0, the packet size is encoded */ + + if (privep->epphy == EP0) + { + DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL); + + /* Map the size in bytes to the encoded value in the register */ + + switch (maxpacket) + { + case 8: + mpsiz = OTGFS_DOEPCTL0_MPSIZ_8; + break; + + case 16: + mpsiz = OTGFS_DOEPCTL0_MPSIZ_16; + break; + + case 32: + mpsiz = OTGFS_DOEPCTL0_MPSIZ_32; + break; + + case 64: + mpsiz = OTGFS_DOEPCTL0_MPSIZ_64; + break; + + default: + uerr("ERROR: Unsupported maxpacket: %d\n", maxpacket); + return -EINVAL; + } + } + + /* For other endpoints, the packet size is in bytes */ + + else + { + mpsiz = (maxpacket << OTGFS_DOEPCTL_MPSIZ_SHIFT); + } + + /* If the endpoint is already active don't change the endpoint control + * register. + */ + + regaddr = AT32_OTGFS_DOEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + if ((regval & OTGFS_DOEPCTL_USBAEP) == 0) + { + if (regval & OTGFS_DOEPCTL_NAKSTS) + { + regval |= OTGFS_DOEPCTL_CNAK; + } + + regval &= ~(OTGFS_DOEPCTL_MPSIZ_MASK | OTGFS_DOEPCTL_EPTYP_MASK); + regval |= mpsiz; + regval |= (eptype << OTGFS_DOEPCTL_EPTYP_SHIFT); + regval |= (OTGFS_DOEPCTL_SD0PID | OTGFS_DOEPCTL_USBAEP); + at32_putreg(regval, regaddr); + + /* Save the endpoint configuration */ + + privep->ep.maxpacket = maxpacket; + privep->eptype = eptype; + privep->stalled = false; + privep->active = false; + privep->zlp = false; + } + + /* Enable the interrupt for this endpoint */ + + regval = at32_getreg(AT32_OTGFS_DAINTMSK); + regval |= OTGFS_DAINT_OEP(privep->epphy); + at32_putreg(regval, AT32_OTGFS_DAINTMSK); + return OK; +} + +/**************************************************************************** + * Name: at32_epin_configure + * + * Description: + * Configure an IN endpoint, making it usable + * + * Input Parameters: + * privep - a pointer to an internal endpoint structure + * eptype - The type of the endpoint + * maxpacket - The max packet size of the endpoint + * + ****************************************************************************/ + +static int at32_epin_configure(struct at32_ep_s *privep, + uint8_t eptype, + uint16_t maxpacket) +{ + uint32_t mpsiz; + uint32_t regaddr; + uint32_t regval; + + usbtrace(TRACE_EPCONFIGURE, privep->epphy); + + /* For EP0, the packet size is encoded */ + + if (privep->epphy == EP0) + { + DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL); + + /* Map the size in bytes to the encoded value in the register */ + + switch (maxpacket) + { + case 8: + mpsiz = OTGFS_DIEPCTL0_MPSIZ_8; + break; + + case 16: + mpsiz = OTGFS_DIEPCTL0_MPSIZ_16; + break; + + case 32: + mpsiz = OTGFS_DIEPCTL0_MPSIZ_32; + break; + + case 64: + mpsiz = OTGFS_DIEPCTL0_MPSIZ_64; + break; + + default: + uerr("ERROR: Unsupported maxpacket: %d\n", maxpacket); + return -EINVAL; + } + } + + /* For other endpoints, the packet size is in bytes */ + + else + { + mpsiz = (maxpacket << OTGFS_DIEPCTL_MPSIZ_SHIFT); + } + + /* If the endpoint is already active don't change the endpoint control + * register. + */ + + regaddr = AT32_OTGFS_DIEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + if ((regval & OTGFS_DIEPCTL_USBAEP) == 0) + { + if (regval & OTGFS_DIEPCTL_NAKSTS) + { + regval |= OTGFS_DIEPCTL_CNAK; + } + + regval &= ~(OTGFS_DIEPCTL_MPSIZ_MASK | OTGFS_DIEPCTL_EPTYP_MASK | + OTGFS_DIEPCTL_TXFNUM_MASK); + regval |= mpsiz; + regval |= (eptype << OTGFS_DIEPCTL_EPTYP_SHIFT); + regval |= (privep->epphy << OTGFS_DIEPCTL_TXFNUM_SHIFT); + regval |= (OTGFS_DIEPCTL_SD0PID | OTGFS_DIEPCTL_USBAEP); + at32_putreg(regval, regaddr); + + /* Save the endpoint configuration */ + + privep->ep.maxpacket = maxpacket; + privep->eptype = eptype; + privep->stalled = false; + privep->active = false; + privep->zlp = false; + } + + /* Enable the interrupt for this endpoint */ + + regval = at32_getreg(AT32_OTGFS_DAINTMSK); + regval |= OTGFS_DAINT_IEP(privep->epphy); + at32_putreg(regval, AT32_OTGFS_DAINTMSK); + + return OK; +} + +/**************************************************************************** + * Name: at32_ep_configure + * + * Description: + * Configure endpoint, making it usable + * + * Input Parameters: + * ep - the struct usbdev_ep_s instance obtained from allocep() + * desc - A struct usb_epdesc_s instance describing the endpoint + * last - true if this this last endpoint to be configured. Some hardware + * needs to take special action when all of the endpoints have been + * configured. + * + ****************************************************************************/ + +static int at32_ep_configure(struct usbdev_ep_s *ep, + const struct usb_epdesc_s *desc, + bool last) +{ + struct at32_ep_s *privep = (struct at32_ep_s *)ep; + uint16_t maxpacket; + uint8_t eptype; + int ret; + + usbtrace(TRACE_EPCONFIGURE, privep->epphy); + DEBUGASSERT(desc->addr == ep->eplog); + + /* Initialize EP capabilities */ + + maxpacket = GETUINT16(desc->mxpacketsize); + eptype = desc->attr & USB_EP_ATTR_XFERTYPE_MASK; + + /* Setup Endpoint Control Register */ + + if (privep->isin) + { + ret = at32_epin_configure(privep, eptype, maxpacket); + } + else + { + ret = at32_epout_configure(privep, eptype, maxpacket); + } + + return ret; +} + +/**************************************************************************** + * Name: at32_ep0_configure + * + * Description: + * Reset Usb engine + * + ****************************************************************************/ + +static void at32_ep0_configure(struct at32_usbdev_s *priv) +{ + /* Enable EP0 IN and OUT */ + + at32_epin_configure(&priv->epin[EP0], USB_EP_ATTR_XFER_CONTROL, + CONFIG_USBDEV_EP0_MAXSIZE); + at32_epout_configure(&priv->epout[EP0], USB_EP_ATTR_XFER_CONTROL, + CONFIG_USBDEV_EP0_MAXSIZE); +} + +/**************************************************************************** + * Name: at32_epout_disable + * + * Description: + * Disable an OUT endpoint will no longer be used + * + ****************************************************************************/ + +static void at32_epout_disable(struct at32_ep_s *privep) +{ + uint32_t regaddr; + uint32_t regval; + irqstate_t flags; + + usbtrace(TRACE_EPDISABLE, privep->epphy); + + /* Is this an IN or an OUT endpoint */ + + /* Before disabling any OUT endpoint, the application must enable + * Global OUT NAK mode in the core. + */ + + flags = enter_critical_section(); + at32_enablegonak(privep); + + /* Disable the required OUT endpoint by setting the EPDIS and SNAK bits + * int DOECPTL register. + */ + + regaddr = AT32_OTGFS_DOEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + regval &= ~OTGFS_DOEPCTL_USBAEP; + regval |= (OTGFS_DOEPCTL_EPDIS | OTGFS_DOEPCTL_SNAK); + at32_putreg(regval, regaddr); + + /* Wait for the EPDISD interrupt which indicates that the OUT + * endpoint is completely disabled. + */ + +#if 0 /* Doesn't happen */ + regaddr = AT32_OTGFS_DOEPINT(privep->epphy); + while ((at32_getreg(regaddr) & OTGFS_DOEPINT_EPDISD) == 0); +#else + /* REVISIT: */ + + up_udelay(10); +#endif + + /* Clear the EPDISD interrupt indication */ + + at32_putreg(OTGFS_DOEPINT_EPDISD, AT32_OTGFS_DOEPINT(privep->epphy)); + + /* Then disable the Global OUT NAK mode to continue receiving data + * from other non-disabled OUT endpoints. + */ + + at32_disablegonak(privep); + + /* Disable endpoint interrupts */ + + regval = at32_getreg(AT32_OTGFS_DAINTMSK); + regval &= ~OTGFS_DAINT_OEP(privep->epphy); + at32_putreg(regval, AT32_OTGFS_DAINTMSK); + + /* Cancel any queued read requests */ + + at32_req_cancel(privep, -ESHUTDOWN); + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: at32_epin_disable + * + * Description: + * Disable an IN endpoint when it will no longer be used + * + ****************************************************************************/ + +static void at32_epin_disable(struct at32_ep_s *privep) +{ + uint32_t regaddr; + uint32_t regval; + irqstate_t flags; + + usbtrace(TRACE_EPDISABLE, privep->epphy); + + /* After USB reset, the endpoint will already be deactivated by the + * hardware. Trying to disable again will just hang in the wait. + */ + + regaddr = AT32_OTGFS_DIEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + if ((regval & OTGFS_DIEPCTL_USBAEP) == 0) + { + return; + } + + /* This INEPNE wait logic is suggested by reference manual, but seems + * to get stuck to infinite loop. + */ + +#if 0 + /* Make sure that there is no pending IPEPNE interrupt (because we are + * to poll this bit below). + */ + + at32_putreg(OTGFS_DIEPINT_INEPNE, AT32_OTGFS_DIEPINT(privep->epphy)); + + /* Set the endpoint in NAK mode */ + + regaddr = AT32_OTGFS_DIEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + regval &= ~OTGFS_DIEPCTL_USBAEP; + regval |= (OTGFS_DIEPCTL_EPDIS | OTGFS_DIEPCTL_SNAK); + at32_putreg(regval, regaddr); + + /* Wait for the INEPNE interrupt that indicates that we are now in NAK + * mode + */ + + regaddr = AT32_OTGFS_DIEPINT(privep->epphy); + while ((at32_getreg(regaddr) & OTGFS_DIEPINT_INEPNE) == 0); + + /* Clear the INEPNE interrupt indication */ + + at32_putreg(OTGFS_DIEPINT_INEPNE, regaddr); +#endif + + /* Deactivate and disable the endpoint by setting the EPDIS and SNAK bits + * the DIEPCTLx register. + */ + + flags = enter_critical_section(); + regaddr = AT32_OTGFS_DIEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + regval &= ~OTGFS_DIEPCTL_USBAEP; + regval |= (OTGFS_DIEPCTL_EPDIS | OTGFS_DIEPCTL_SNAK); + at32_putreg(regval, regaddr); + + /* Wait for the EPDISD interrupt which indicates that the IN + * endpoint is completely disabled. + */ + + regaddr = AT32_OTGFS_DIEPINT(privep->epphy); + while ((at32_getreg(regaddr) & OTGFS_DIEPINT_EPDISD) == 0); + + /* Clear the EPDISD interrupt indication */ + + at32_putreg(OTGFS_DIEPINT_EPDISD, at32_getreg(regaddr)); + + /* Flush any data remaining in the TxFIFO */ + + at32_txfifo_flush(OTGFS_GRSTCTL_TXFNUM_D(privep->epphy)); + + /* Disable endpoint interrupts */ + + regval = at32_getreg(AT32_OTGFS_DAINTMSK); + regval &= ~OTGFS_DAINT_IEP(privep->epphy); + at32_putreg(regval, AT32_OTGFS_DAINTMSK); + + /* Cancel any queued write requests */ + + at32_req_cancel(privep, -ESHUTDOWN); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: at32_ep_disable + * + * Description: + * The endpoint will no longer be used + * + ****************************************************************************/ + +static int at32_ep_disable(struct usbdev_ep_s *ep) +{ + struct at32_ep_s *privep = (struct at32_ep_s *)ep; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + usbtrace(TRACE_EPDISABLE, privep->epphy); + + /* Is this an IN or an OUT endpoint */ + + if (privep->isin) + { + /* Disable the IN endpoint */ + + at32_epin_disable(privep); + } + else + { + /* Disable the OUT endpoint */ + + at32_epout_disable(privep); + } + + return OK; +} + +/**************************************************************************** + * Name: at32_ep_allocreq + * + * Description: + * Allocate an I/O request + * + ****************************************************************************/ + +static struct usbdev_req_s *at32_ep_allocreq(struct usbdev_ep_s *ep) +{ + struct at32_req_s *privreq; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_INVALIDPARMS), 0); + return NULL; + } +#endif + + usbtrace(TRACE_EPALLOCREQ, ((struct at32_ep_s *)ep)->epphy); + + privreq = (struct at32_req_s *)kmm_malloc(sizeof(struct at32_req_s)); + if (!privreq) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_ALLOCFAIL), 0); + return NULL; + } + + memset(privreq, 0, sizeof(struct at32_req_s)); + return &privreq->req; +} + +/**************************************************************************** + * Name: at32_ep_freereq + * + * Description: + * Free an I/O request + * + ****************************************************************************/ + +static void at32_ep_freereq(struct usbdev_ep_s *ep, + struct usbdev_req_s *req) +{ + struct at32_req_s *privreq = (struct at32_req_s *)req; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep || !req) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_INVALIDPARMS), 0); + return; + } +#endif + + usbtrace(TRACE_EPFREEREQ, ((struct at32_ep_s *)ep)->epphy); + kmm_free(privreq); +} + +/**************************************************************************** + * Name: at32_ep_allocbuffer + * + * Description: + * Allocate an I/O buffer + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_DMA +static void *at32_ep_allocbuffer(struct usbdev_ep_s *ep, uint16_t bytes) +{ + usbtrace(TRACE_EPALLOCBUFFER, ((struct at32_ep_s *)ep)->epphy); + +#ifdef CONFIG_USBDEV_DMAMEMORY + return usbdev_dma_alloc(bytes); +#else + return kmm_malloc(bytes); +#endif +} +#endif + +/**************************************************************************** + * Name: at32_ep_freebuffer + * + * Description: + * Free an I/O buffer + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_DMA +static void at32_ep_freebuffer(struct usbdev_ep_s *ep, void *buf) +{ + usbtrace(TRACE_EPALLOCBUFFER, ((struct at32_ep_s *)ep)->epphy); + +#ifdef CONFIG_USBDEV_DMAMEMORY + usbdev_dma_free(buf); +#else + kmm_free(buf); +#endif +} +#endif + +/**************************************************************************** + * Name: at32_ep_submit + * + * Description: + * Submit an I/O request to the endpoint + * + ****************************************************************************/ + +static int at32_ep_submit(struct usbdev_ep_s *ep, + struct usbdev_req_s *req) +{ + struct at32_req_s *privreq = (struct at32_req_s *)req; + struct at32_ep_s *privep = (struct at32_ep_s *)ep; + struct at32_usbdev_s *priv; + irqstate_t flags; + int ret = OK; + + /* Some sanity checking */ + +#ifdef CONFIG_DEBUG_FEATURES + if (!req || !req->callback || !req->buf || !ep) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_INVALIDPARMS), 0); + uinfo("req=%p callback=%p buf=%p ep=%p\n", req, req->callback, + req->buf, ep); + return -EINVAL; + } +#endif + + usbtrace(TRACE_EPSUBMIT, privep->epphy); + priv = privep->dev; + +#ifdef CONFIG_DEBUG_FEATURES + if (!priv->driver) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_NOTCONFIGURED), + priv->usbdev.speed); + return -ESHUTDOWN; + } +#endif + + /* Handle the request from the class driver */ + + req->result = -EINPROGRESS; + req->xfrd = 0; + + /* Disable Interrupts */ + + flags = enter_critical_section(); + + /* If we are stalled, then drop all requests on the floor */ + + if (privep->stalled) + { + ret = -EBUSY; + } + else + { + /* Add the new request to the request queue for the endpoint. */ + + if (at32_req_addlast(privep, privreq) && !privep->active) + { + /* If a request was added to an IN endpoint, then attempt to send + * the request data buffer now. + */ + + if (privep->isin) + { + usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len); + + /* If the endpoint is not busy with another write request, + * then process the newly received write request now. + */ + + if (!privep->active) + { + at32_epin_request(priv, privep); + } + } + + /* If the request was added to an OUT endpoint, then attempt to + * setup a read into the request data buffer now (this will, of + * course, fail if there is already a read in place). + */ + + else + { + usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len); + at32_epout_request(priv, privep); + } + } + } + + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Name: at32_ep_cancel + * + * Description: + * Cancel an I/O request previously sent to an endpoint + * + ****************************************************************************/ + +static int at32_ep_cancel(struct usbdev_ep_s *ep, + struct usbdev_req_s *req) +{ + struct at32_ep_s *privep = (struct at32_ep_s *)ep; + irqstate_t flags; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep || !req) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + usbtrace(TRACE_EPCANCEL, privep->epphy); + + flags = enter_critical_section(); + + /* FIXME: if the request is the first, then we need to flush the EP + * otherwise just remove it from the list + * + * but ... all other implementations cancel all requests ... + */ + + at32_req_cancel(privep, -ESHUTDOWN); + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: at32_epout_setstall + * + * Description: + * Stall an OUT endpoint + * + ****************************************************************************/ + +static int at32_epout_setstall(struct at32_ep_s *privep) +{ +#if 1 + /* This implementation follows the requirements from the AT32 F4 reference + * manual. + */ + + uint32_t regaddr; + uint32_t regval; + + /* Put the core in the Global OUT NAK mode */ + + at32_enablegonak(privep); + + /* Disable and STALL the OUT endpoint by setting the EPDIS and STALL bits + * in the DOECPTL register. + */ + + regaddr = AT32_OTGFS_DOEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + regval |= (OTGFS_DOEPCTL_EPDIS | OTGFS_DOEPCTL_STALL); + at32_putreg(regval, regaddr); + + /* Wait for the EPDISD interrupt which indicates that the OUT + * endpoint is completely disabled. + */ + +#if 0 /* Doesn't happen */ + regaddr = AT32_OTGFS_DOEPINT(privep->epphy); + while ((at32_getreg(regaddr) & OTGFS_DOEPINT_EPDISD) == 0); +#else + /* REVISIT: */ + + up_udelay(10); +#endif + + /* Disable Global OUT NAK mode */ + + at32_disablegonak(privep); + + /* The endpoint is now stalled */ + + privep->stalled = true; + return OK; +#else + /* This implementation follows the Artery code example. */ + + /* REVISIT: */ + + uint32_t regaddr; + uint32_t regval; + + /* Stall the OUT endpoint by setting the STALL bit in the DOECPTL + * register. + */ + + regaddr = AT32_OTGFS_DOEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + regval |= OTGFS_DOEPCTL_STALL; + at32_putreg(regval, regaddr); + + /* The endpoint is now stalled */ + + privep->stalled = true; + return OK; +#endif +} + +/**************************************************************************** + * Name: at32_epin_setstall + * + * Description: + * Stall an IN endpoint + * + ****************************************************************************/ + +static int at32_epin_setstall(struct at32_ep_s *privep) +{ + uint32_t regaddr; + uint32_t regval; + + /* Get the IN endpoint device control register */ + + regaddr = AT32_OTGFS_DIEPCTL(privep->epphy); + regval = at32_getreg(regaddr); + + /* Then stall the endpoint */ + + regval |= OTGFS_DIEPCTL_STALL; + at32_putreg(regval, regaddr); + + /* The endpoint is now stalled */ + + privep->stalled = true; + return OK; +} + +/**************************************************************************** + * Name: at32_ep_setstall + * + * Description: + * Stall an endpoint + * + ****************************************************************************/ + +static int at32_ep_setstall(struct at32_ep_s *privep) +{ + usbtrace(TRACE_EPSTALL, privep->epphy); + + /* Is this an IN endpoint? */ + + if (privep->isin == 1) + { + return at32_epin_setstall(privep); + } + else + { + return at32_epout_setstall(privep); + } +} + +/**************************************************************************** + * Name: at32_ep_clrstall + * + * Description: + * Resume a stalled endpoint + * + ****************************************************************************/ + +static int at32_ep_clrstall(struct at32_ep_s *privep) +{ + uint32_t regaddr; + uint32_t regval; + uint32_t stallbit; + uint32_t data0bit; + + usbtrace(TRACE_EPRESUME, privep->epphy); + + /* Is this an IN endpoint? */ + + if (privep->isin == 1) + { + /* Clear the stall bit in the IN endpoint device control register */ + + regaddr = AT32_OTGFS_DIEPCTL(privep->epphy); + stallbit = OTGFS_DIEPCTL_STALL; + data0bit = OTGFS_DIEPCTL_SD0PID; + } + else + { + /* Clear the stall bit in the IN endpoint device control register */ + + regaddr = AT32_OTGFS_DOEPCTL(privep->epphy); + stallbit = OTGFS_DOEPCTL_STALL; + data0bit = OTGFS_DOEPCTL_SD0PID; + } + + /* Clear the stall bit */ + + regval = at32_getreg(regaddr); + regval &= ~stallbit; + + /* Set the DATA0 pid for interrupt and bulk endpoints */ + + if (privep->eptype == USB_EP_ATTR_XFER_INT || + privep->eptype == USB_EP_ATTR_XFER_BULK) + { + /* Writing this bit sets the DATA0 PID */ + + regval |= data0bit; + } + + at32_putreg(regval, regaddr); + + /* The endpoint is no longer stalled */ + + privep->stalled = false; + return OK; +} + +/**************************************************************************** + * Name: at32_ep_stall + * + * Description: + * Stall or resume an endpoint + * + ****************************************************************************/ + +static int at32_ep_stall(struct usbdev_ep_s *ep, bool resume) +{ + struct at32_ep_s *privep = (struct at32_ep_s *)ep; + irqstate_t flags; + int ret; + + /* Set or clear the stall condition as requested */ + + flags = enter_critical_section(); + if (resume) + { + ret = at32_ep_clrstall(privep); + } + else + { + ret = at32_ep_setstall(privep); + } + + leave_critical_section(flags); + + return ret; +} + +/**************************************************************************** + * Name: at32_ep0_stall + * + * Description: + * Stall endpoint 0 + * + ****************************************************************************/ + +static void at32_ep0_stall(struct at32_usbdev_s *priv) +{ + at32_epin_setstall(&priv->epin[EP0]); + at32_epout_setstall(&priv->epout[EP0]); + priv->stalled = true; + at32_ep0out_ctrlsetup(priv); +} + +/**************************************************************************** + * Device operations + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_ep_alloc + * + * Description: + * Allocate an endpoint matching the parameters. + * + * Input Parameters: + * eplog - 7-bit logical endpoint number (direction bit ignored). + * Zero means that any endpoint matching the other requirements + * will suffice. The assigned endpoint can be found in the eplog + * field. + * in - true: IN (device-to-host) endpoint requested + * eptype - Endpoint type. One of {USB_EP_ATTR_XFER_ISOC, + * USB_EP_ATTR_XFER_BULK, USB_EP_ATTR_XFER_INT} + * + ****************************************************************************/ + +static struct usbdev_ep_s *at32_ep_alloc(struct usbdev_s *dev, + uint8_t eplog, bool in, + uint8_t eptype) +{ + struct at32_usbdev_s *priv = (struct at32_usbdev_s *)dev; + uint8_t epavail; + irqstate_t flags; + int epphy; + int epno = 0; + + usbtrace(TRACE_DEVALLOCEP, (uint16_t)eplog); + + /* Ignore any direction bits in the logical address */ + + epphy = USB_EPNO(eplog); + + /* Get the set of available endpoints depending on the direction */ + + flags = enter_critical_section(); + epavail = priv->epavail[in]; + + /* A physical address of 0 means that any endpoint will do */ + + if (epphy > 0) + { + /* Otherwise, we will return the endpoint structure only for the + * requested 'logical' endpoint. All of the other checks will still + * be performed. + * + * First, verify that the logical endpoint is in the range supported by + * by the hardware. + */ + + if (epphy >= AT32_NENDPOINTS) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BADEPNO), (uint16_t)epphy); + return NULL; + } + + /* Remove all of the candidate endpoints from the bitset except for the + * this physical endpoint number. + */ + + epavail &= (1 << epphy); + } + + /* Is there an available endpoint? */ + + if (epavail) + { + /* Yes.. Select the lowest numbered endpoint in the set of available + * endpoints. + */ + + for (epno = 1; epno < AT32_NENDPOINTS; epno++) + { + uint8_t bit = 1 << epno; + if ((epavail & bit) != 0) + { + /* Mark the endpoint no longer available */ + + priv->epavail[in] &= ~(1 << epno); + + /* And return the pointer to the standard endpoint structure */ + + leave_critical_section(flags); + return in ? &priv->epin[epno].ep : &priv->epout[epno].ep; + } + } + + /* We should not get here */ + } + + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_NOEP), (uint16_t)eplog); + leave_critical_section(flags); + return NULL; +} + +/**************************************************************************** + * Name: at32_ep_free + * + * Description: + * Free the previously allocated endpoint + * + ****************************************************************************/ + +static void at32_ep_free(struct usbdev_s *dev, + struct usbdev_ep_s *ep) +{ + struct at32_usbdev_s *priv = (struct at32_usbdev_s *)dev; + struct at32_ep_s *privep = (struct at32_ep_s *)ep; + irqstate_t flags; + + usbtrace(TRACE_DEVFREEEP, (uint16_t)privep->epphy); + + if (priv && privep) + { + /* Mark the endpoint as available */ + + flags = enter_critical_section(); + priv->epavail[privep->isin] |= (1 << privep->epphy); + leave_critical_section(flags); + } +} + +/**************************************************************************** + * Name: at32_getframe + * + * Description: + * Returns the current frame number + * + ****************************************************************************/ + +static int at32_getframe(struct usbdev_s *dev) +{ + uint32_t regval; + + usbtrace(TRACE_DEVGETFRAME, 0); + + /* Return the last frame number of the last SOF detected by the hardware */ + + regval = at32_getreg(AT32_OTGFS_DSTS); + return (int)((regval & OTGFS_DSTS_SOFFN_MASK) >> OTGFS_DSTS_SOFFN_SHIFT); +} + +/**************************************************************************** + * Name: at32_wakeup + * + * Description: + * Exit suspend mode. + * + ****************************************************************************/ + +static int at32_wakeup(struct usbdev_s *dev) +{ + struct at32_usbdev_s *priv = (struct at32_usbdev_s *)dev; + uint32_t regval; + irqstate_t flags; + + usbtrace(TRACE_DEVWAKEUP, 0); + + /* Is wakeup enabled? */ + + flags = enter_critical_section(); + if (priv->wakeup) + { + /* Yes... is the core suspended? */ + + regval = at32_getreg(AT32_OTGFS_DSTS); + if ((regval & OTGFS_DSTS_SUSPSTS) != 0) + { + /* Re-start the PHY clock and un-gate USB core clock (HCLK) */ + + /* Activate Remote wakeup signaling */ + + regval = at32_getreg(AT32_OTGFS_DCTL); + regval |= OTGFS_DCTL_RWUSIG; + at32_putreg(regval, AT32_OTGFS_DCTL); + up_mdelay(5); + regval &= ~OTGFS_DCTL_RWUSIG; + at32_putreg(regval, AT32_OTGFS_DCTL); + } + } + + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: at32_selfpowered + * + * Description: + * Sets/clears the device self-powered feature + * + ****************************************************************************/ + +static int at32_selfpowered(struct usbdev_s *dev, bool selfpowered) +{ + struct at32_usbdev_s *priv = (struct at32_usbdev_s *)dev; + + usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered); + +#ifdef CONFIG_DEBUG_FEATURES + if (!dev) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_INVALIDPARMS), 0); + return -ENODEV; + } +#endif + + priv->selfpowered = selfpowered; + return OK; +} + +/**************************************************************************** + * Name: at32_pullup + * + * Description: + * Software-controlled connect to/disconnect from USB host + * + ****************************************************************************/ + +static int at32_pullup(struct usbdev_s *dev, bool enable) +{ + uint32_t regval; + + usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); + + irqstate_t flags = enter_critical_section(); + regval = at32_getreg(AT32_OTGFS_DCTL); + if (enable) + { + /* Connect the device by clearing the soft disconnect bit in the DCTL + * register + */ + + regval &= ~OTGFS_DCTL_SDIS; + } + else + { + /* Connect the device by setting the soft disconnect bit in the DCTL + * register + */ + + regval |= OTGFS_DCTL_SDIS; + } + + at32_putreg(regval, AT32_OTGFS_DCTL); + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: at32_setaddress + * + * Description: + * Set the devices USB address + * + ****************************************************************************/ + +static void at32_setaddress(struct at32_usbdev_s *priv, uint16_t address) +{ + uint32_t regval; + + /* Set the device address in the DCFG register */ + + regval = at32_getreg(AT32_OTGFS_DCFG); + regval &= ~OTGFS_DCFG_DAD_MASK; + regval |= ((uint32_t)address << OTGFS_DCFG_DAD_SHIFT); + at32_putreg(regval, AT32_OTGFS_DCFG); + + /* Are we now addressed? (i.e., do we have a non-NULL device + * address?) + */ + + if (address != 0) + { + priv->devstate = DEVSTATE_ADDRESSED; + priv->addressed = true; + } + else + { + priv->devstate = DEVSTATE_DEFAULT; + priv->addressed = false; + } +} + +/**************************************************************************** + * Name: at32_txfifo_flush + * + * Description: + * Flush the specific TX fifo. + * + ****************************************************************************/ + +static int at32_txfifo_flush(uint32_t txfnum) +{ + uint32_t regval; + uint32_t timeout; + + /* Initiate the TX FIFO flush operation */ + + regval = OTGFS_GRSTCTL_TXFFLSH | txfnum; + at32_putreg(regval, AT32_OTGFS_GRSTCTL); + + /* Wait for the FLUSH to complete */ + + for (timeout = 0; timeout < AT32_FLUSH_DELAY; timeout++) + { + regval = at32_getreg(AT32_OTGFS_GRSTCTL); + if ((regval & OTGFS_GRSTCTL_TXFFLSH) == 0) + { + break; + } + } + + /* Wait for 3 PHY Clocks */ + + up_udelay(3); + return OK; +} + +/**************************************************************************** + * Name: at32_rxfifo_flush + * + * Description: + * Flush the RX fifo. + * + ****************************************************************************/ + +static int at32_rxfifo_flush(void) +{ + uint32_t regval; + uint32_t timeout; + + /* Initiate the RX FIFO flush operation */ + + at32_putreg(OTGFS_GRSTCTL_RXFFLSH, AT32_OTGFS_GRSTCTL); + + /* Wait for the FLUSH to complete */ + + for (timeout = 0; timeout < AT32_FLUSH_DELAY; timeout++) + { + regval = at32_getreg(AT32_OTGFS_GRSTCTL); + if ((regval & OTGFS_GRSTCTL_RXFFLSH) == 0) + { + break; + } + } + + /* Wait for 3 PHY Clocks */ + + up_udelay(3); + return OK; +} + +/**************************************************************************** + * Name: at32_swinitialize + * + * Description: + * Initialize all driver data structures. + * + ****************************************************************************/ + +static void at32_swinitialize(struct at32_usbdev_s *priv) +{ + struct at32_ep_s *privep; + int i; + + /* Initialize the device state structure */ + + memset(priv, 0, sizeof(struct at32_usbdev_s)); + + priv->usbdev.ops = &g_devops; + priv->usbdev.ep0 = &priv->epin[EP0].ep; + + priv->epavail[0] = AT32_EP_AVAILABLE; + priv->epavail[1] = AT32_EP_AVAILABLE; + + priv->epin[EP0].ep.priv = priv; + priv->epout[EP0].ep.priv = priv; + + /* Initialize the endpoint lists */ + + for (i = 0; i < AT32_NENDPOINTS; i++) + { + /* Set endpoint operations, reference to driver structure (not + * really necessary because there is only one controller), and + * the physical endpoint number (which is just the index to the + * endpoint). + */ + + privep = &priv->epin[i]; + privep->ep.ops = &g_epops; + privep->dev = priv; + privep->isin = 1; + + /* The index, i, is the physical endpoint address; Map this + * to a logical endpoint address usable by the class driver. + */ + + privep->epphy = i; + privep->ep.eplog = AT32_EPPHYIN2LOG(i); + + /* Control until endpoint is activated */ + + privep->eptype = USB_EP_ATTR_XFER_CONTROL; + privep->ep.maxpacket = CONFIG_USBDEV_EP0_MAXSIZE; + } + + /* Initialize the endpoint lists */ + + for (i = 0; i < AT32_NENDPOINTS; i++) + { + /* Set endpoint operations, reference to driver structure (not + * really necessary because there is only one controller), and + * the physical endpoint number (which is just the index to the + * endpoint). + */ + + privep = &priv->epout[i]; + privep->ep.ops = &g_epops; + privep->dev = priv; + + /* The index, i, is the physical endpoint address; Map this + * to a logical endpoint address usable by the class driver. + */ + + privep->epphy = i; + privep->ep.eplog = AT32_EPPHYOUT2LOG(i); + + /* Control until endpoint is activated */ + + privep->eptype = USB_EP_ATTR_XFER_CONTROL; + privep->ep.maxpacket = CONFIG_USBDEV_EP0_MAXSIZE; + } +} + +/**************************************************************************** + * Name: at32_hwinitialize + * + * Description: + * Configure the OTG FS core for operation. + * + ****************************************************************************/ + +static void at32_hwinitialize(struct at32_usbdev_s *priv) +{ + uint32_t regval; + uint32_t timeout; + uint32_t address; + int i; + + /* At start-up the core is in FS mode. */ + + /* Disable global interrupts by clearing the GINTMASK bit in the GAHBCFG + * register; Set the TXFELVL bit in the GAHBCFG register so that TxFIFO + * interrupts will occur when the TxFIFO is truly empty (not just half + * full). + */ + + at32_putreg(OTGFS_GAHBCFG_TXFELVL, AT32_OTGFS_GAHBCFG); + + /* Common USB OTG core initialization */ + + /* Reset after a PHY select and set Host mode. First, wait for AHB master + * IDLE state. + */ + + for (timeout = 0; timeout < AT32_READY_DELAY; timeout++) + { + up_udelay(3); + regval = at32_getreg(AT32_OTGFS_GRSTCTL); + if ((regval & OTGFS_GRSTCTL_AHBIDL) != 0) + { + break; + } + } + + /* Then perform the core soft reset. */ + + at32_putreg(OTGFS_GRSTCTL_CSRST, AT32_OTGFS_GRSTCTL); + for (timeout = 0; timeout < AT32_READY_DELAY; timeout++) + { + regval = at32_getreg(AT32_OTGFS_GRSTCTL); + if ((regval & OTGFS_GRSTCTL_CSRST) == 0) + { + break; + } + } + + /* Wait for 3 PHY Clocks */ + + up_udelay(3); + + /* Deactivate the power down */ + + /* In the case of the all others the meaning of the bit is No VBUS + * Sense when Set + */ + + regval = (OTGFS_GCCFG_PWRDWN | OTGFS_GCCFG_VBUSASEN | \ + OTGFS_GCCFG_VBUSBSEN); + +# ifndef CONFIG_USBDEV_VBUSSENSING + regval |= OTGFS_GCCFG_NOVBUSSENS; +# endif +# ifdef CONFIG_AT32_OTGFS_SOFOUTPUT + regval |= OTGFS_GCCFG_SOFOUTEN; +# endif + + at32_putreg(regval, AT32_OTGFS_GCCFG); + up_mdelay(20); + + /* Force Device Mode */ + + regval = at32_getreg(AT32_OTGFS_GUSBCFG); + regval &= ~OTGFS_GUSBCFG_FHMOD; + regval |= OTGFS_GUSBCFG_FDMOD; + at32_putreg(regval, AT32_OTGFS_GUSBCFG); + up_mdelay(50); + + /* Initialize device mode */ + + /* Restart the PHY Clock */ + + regval = at32_getreg(AT32_OTGFS_PCGCCTL); + regval &= ~(1 << 0); + at32_putreg(0, AT32_OTGFS_PCGCCTL); + + /* Device configuration register */ + + regval = at32_getreg(AT32_OTGFS_DCFG); + regval &= ~OTGFS_DCFG_PFIVL_MASK; + regval |= OTGFS_DCFG_PFIVL_80PCT; + at32_putreg(regval, AT32_OTGFS_DCFG); + + /* Set full speed PHY */ + + regval = at32_getreg(AT32_OTGFS_DCFG); + regval &= ~OTGFS_DCFG_DSPD_MASK; + regval |= OTGFS_DCFG_DSPD_FS; + at32_putreg(regval, AT32_OTGFS_DCFG); + + /* Set Rx FIFO size */ + + at32_putreg(AT32_RXFIFO_WORDS, AT32_OTGFS_GRXFSIZ); + + /* EP0 TX */ + + address = AT32_RXFIFO_WORDS; + regval = (address << OTGFS_DIEPTXF0_TX0FD_SHIFT) | + (AT32_EP0_TXFIFO_WORDS << OTGFS_DIEPTXF0_TX0FSA_SHIFT); + at32_putreg(regval, AT32_OTGFS_DIEPTXF0); + + /* EP1 TX */ + + address += AT32_EP0_TXFIFO_WORDS; + regval = (address << OTGFS_DIEPTXF_INEPTXSA_SHIFT) | + (AT32_EP1_TXFIFO_WORDS << OTGFS_DIEPTXF_INEPTXFD_SHIFT); + at32_putreg(regval, AT32_OTGFS_DIEPTXF1); + + /* EP2 TX */ + + address += AT32_EP1_TXFIFO_WORDS; + regval = (address << OTGFS_DIEPTXF_INEPTXSA_SHIFT) | + (AT32_EP2_TXFIFO_WORDS << OTGFS_DIEPTXF_INEPTXFD_SHIFT); + at32_putreg(regval, AT32_OTGFS_DIEPTXF2); + + /* EP3 TX */ + + address += AT32_EP2_TXFIFO_WORDS; + regval = (address << OTGFS_DIEPTXF_INEPTXSA_SHIFT) | + (AT32_EP3_TXFIFO_WORDS << OTGFS_DIEPTXF_INEPTXFD_SHIFT); + at32_putreg(regval, AT32_OTGFS_DIEPTXF3); + + /* EP4 TX */ + + address += AT32_EP3_TXFIFO_WORDS; + regval = (address << OTGFS_DIEPTXF_INEPTXSA_SHIFT) | + (AT32_EP4_TXFIFO_WORDS << OTGFS_DIEPTXF_INEPTXFD_SHIFT); + at32_putreg(regval, AT32_OTGFS_DIEPTXF4); + + /* EP5 TX */ + + address += AT32_EP4_TXFIFO_WORDS; + regval = (address << OTGFS_DIEPTXF_INEPTXSA_SHIFT) | + (AT32_EP5_TXFIFO_WORDS << OTGFS_DIEPTXF_INEPTXFD_SHIFT); + at32_putreg(regval, AT32_OTGFS_DIEPTXF5); + + /* EP6 TX */ + + address += AT32_EP5_TXFIFO_WORDS; + regval = (address << OTGFS_DIEPTXF_INEPTXSA_SHIFT) | + (AT32_EP6_TXFIFO_WORDS << OTGFS_DIEPTXF_INEPTXFD_SHIFT); + at32_putreg(regval, AT32_OTGFS_DIEPTXF6); + + /* EP7 TX */ + + address += AT32_EP6_TXFIFO_WORDS; + regval = (address << OTGFS_DIEPTXF_INEPTXSA_SHIFT) | + (AT32_EP7_TXFIFO_WORDS << OTGFS_DIEPTXF_INEPTXFD_SHIFT); + at32_putreg(regval, AT32_OTGFS_DIEPTXF7); + + /* Flush the FIFOs */ + + at32_txfifo_flush(OTGFS_GRSTCTL_TXFNUM_DALL); + at32_rxfifo_flush(); + + /* Clear all pending Device Interrupts */ + + at32_putreg(0, AT32_OTGFS_DIEPMSK); + at32_putreg(0, AT32_OTGFS_DOEPMSK); + at32_putreg(0, AT32_OTGFS_DIEPEMPMSK); + at32_putreg(0xffffffff, AT32_OTGFS_DAINT); + at32_putreg(0, AT32_OTGFS_DAINTMSK); + + /* Configure all IN endpoints */ + + for (i = 0; i < AT32_NENDPOINTS; i++) + { + regval = at32_getreg(AT32_OTGFS_DIEPCTL(i)); + if ((regval & OTGFS_DIEPCTL_EPENA) != 0) + { + /* The endpoint is already enabled */ + + regval = OTGFS_DIEPCTL_EPENA | OTGFS_DIEPCTL_SNAK; + } + else + { + regval = 0; + } + + at32_putreg(regval, AT32_OTGFS_DIEPCTL(i)); + at32_putreg(0, AT32_OTGFS_DIEPTSIZ(i)); + at32_putreg(0xff, AT32_OTGFS_DIEPINT(i)); + } + + /* Configure all OUT endpoints */ + + for (i = 0; i < AT32_NENDPOINTS; i++) + { + regval = at32_getreg(AT32_OTGFS_DOEPCTL(i)); + if ((regval & OTGFS_DOEPCTL_EPENA) != 0) + { + /* The endpoint is already enabled */ + + regval = OTGFS_DOEPCTL_EPENA | OTGFS_DOEPCTL_SNAK; + } + else + { + regval = 0; + } + + at32_putreg(regval, AT32_OTGFS_DOEPCTL(i)); + at32_putreg(0, AT32_OTGFS_DOEPTSIZ(i)); + at32_putreg(0xff, AT32_OTGFS_DOEPINT(i)); + } + + /* Disable all interrupts. */ + + at32_putreg(0, AT32_OTGFS_GINTMSK); + + /* Clear any pending USB_OTG Interrupts */ + + at32_putreg(0xffffffff, AT32_OTGFS_GOTGINT); + + /* Clear any pending interrupts */ + + regval = at32_getreg(AT32_OTGFS_GINTSTS); + regval &= OTGFS_GINT_RESERVED; + at32_putreg(regval | OTGFS_GINT_RC_W1, AT32_OTGFS_GINTSTS); + + /* Enable the interrupts in the INTMSK */ + + regval = (OTGFS_GINT_RXFLVL | OTGFS_GINT_USBSUSP | OTGFS_GINT_ENUMDNE | + OTGFS_GINT_IEP | OTGFS_GINT_OEP | OTGFS_GINT_USBRST); + +#ifdef CONFIG_USBDEV_ISOCHRONOUS + regval |= (OTGFS_GINT_IISOIXFR | OTGFS_GINT_IISOOXFR); +#endif + +#ifdef CONFIG_USBDEV_SOFINTERRUPT + regval |= OTGFS_GINT_SOF; +#endif + +#ifdef CONFIG_USBDEV_VBUSSENSING + regval |= (OTGFS_GINT_OTG | OTGFS_GINT_SRQ); +#endif + +#ifdef CONFIG_DEBUG_USB + regval |= OTGFS_GINT_MMIS; +#endif + + at32_putreg(regval, AT32_OTGFS_GINTMSK); + + /* Enable the USB global interrupt by setting GINTMSK in the global OTG + * FS AHB configuration register; Set the TXFELVL bit in the GAHBCFG + * register so that TxFIFO interrupts will occur when the TxFIFO is truly + * empty (not just half full). + */ + + at32_putreg(OTGFS_GAHBCFG_GINTMSK | OTGFS_GAHBCFG_TXFELVL, + AT32_OTGFS_GAHBCFG); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_usbinitialize + * + * Description: + * Initialize USB hardware. + * + * Assumptions: + * - This function is called very early in the initialization sequence + * - PLL and GIO pin initialization is not performed here but should been in + * the low-level boot logic: PLL1 must be configured for operation at + * 48MHz and P0.23 and PO.31 in PINSEL1 must be configured for Vbus and + * USB connect LED. + * + ****************************************************************************/ + +void arm_usbinitialize(void) +{ + /* At present, there is only a single OTG FS device support. Hence it is + * pre-allocated as g_otgfsdev. However, in most code, the private data + * structure will be referenced using the 'priv' pointer (rather than the + * global data) in order to simplify any future support for multiple + * devices. + */ + + struct at32_usbdev_s *priv = &g_otgfsdev; + int ret; + + usbtrace(TRACE_DEVINIT, 0); + + /* Here we assume that: + * + * 1. GPIOA and OTG FS peripheral clocking has already been enabled as part + * of the boot sequence. + * 2. Board-specific logic has already enabled other board specific GPIOs + * for things like soft pull-up, VBUS sensing, power controls, and over- + * current detection. + */ + + /* Configure OTG FS alternate function pins + * + * PIN* SIGNAL DIRECTION + * ---- ----------- ---------- + * PA8 OTG_FS_SOF SOF clock output + * PA9 OTG_FS_VBUS VBUS input for device, Driven by external regulator by + * host (not an alternate function) + * PA10 OTG_FS_ID OTG ID pin (only needed in Dual mode) + * PA11 OTG_FS_DM D- I/O + * PA12 OTG_FS_DP D+ I/O + * + * *Pins may vary from device-to-device. + */ + + at32_configgpio(GPIO_OTGFS_DM); + at32_configgpio(GPIO_OTGFS_DP); + + /* Only needed for OTG */ +#ifndef CONFIG_OTG_ID_GPIO_DISABLE + at32_configgpio(GPIO_OTGFS_ID); +#endif + + /* SOF output pin configuration is configurable. */ + +#ifdef CONFIG_AT32_OTGFS_SOFOUTPUT + at32_configgpio(GPIO_OTGFS_SOF); +#endif + + /* Uninitialize the hardware so th`at we know that we are starting from a + * known state. + */ + + arm_usbuninitialize(); + + /* Initialie the driver data structure */ + + at32_swinitialize(priv); + + /* Attach the OTG FS interrupt handler */ + + ret = irq_attach(AT32_IRQ_OTGFS, at32_usbinterrupt, NULL); + if (ret < 0) + { + uerr("ERROR: irq_attach failed: %d\n", ret); + goto errout; + } + + /* Initialize the USB OTG core */ + + at32_hwinitialize(priv); + + /* Disconnect device */ + + at32_pullup(&priv->usbdev, false); + + /* Reset/Re-initialize the USB hardware */ + + at32_usbreset(priv); + + /* Enable USB controller interrupts at the NVIC */ + + up_enable_irq(AT32_IRQ_OTGFS); + return; + +errout: + arm_usbuninitialize(); +} + +/**************************************************************************** + * Name: arm_usbuninitialize + ****************************************************************************/ + +void arm_usbuninitialize(void) +{ + /* At present, there is only a single OTG FS device support. Hence it is + * pre-allocated as g_otgfsdev. However, in most code, the private data + * structure will be referenced using the 'priv' pointer (rather than the + * global data) in order to simplify any future support for multiple + * devices. + */ + + struct at32_usbdev_s *priv = &g_otgfsdev; + irqstate_t flags; + int i; + + usbtrace(TRACE_DEVUNINIT, 0); + + if (priv->driver) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_DRIVERREGISTERED), 0); + usbdev_unregister(priv->driver); + } + + /* Disconnect device */ + + flags = enter_critical_section(); + at32_pullup(&priv->usbdev, false); + priv->usbdev.speed = USB_SPEED_UNKNOWN; + + /* Disable and detach IRQs */ + + up_disable_irq(AT32_IRQ_OTGFS); + irq_detach(AT32_IRQ_OTGFS); + + /* Disable all endpoint interrupts */ + + for (i = 0; i < AT32_NENDPOINTS; i++) + { + at32_putreg(0xff, AT32_OTGFS_DIEPINT(i)); + at32_putreg(0xff, AT32_OTGFS_DOEPINT(i)); + } + + at32_putreg(0, AT32_OTGFS_DIEPMSK); + at32_putreg(0, AT32_OTGFS_DOEPMSK); + at32_putreg(0, AT32_OTGFS_DIEPEMPMSK); + at32_putreg(0, AT32_OTGFS_DAINTMSK); + at32_putreg(0xffffffff, AT32_OTGFS_DAINT); + + /* Flush the FIFOs */ + + at32_txfifo_flush(OTGFS_GRSTCTL_TXFNUM_DALL); + at32_rxfifo_flush(); + + /* TODO: Turn off USB power and clocking */ + + priv->devstate = DEVSTATE_DEFAULT; + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: usbdev_register + * + * Description: + * Register a USB device class driver. The class driver's bind() method + * will be called to bind it to a USB device driver. + * + ****************************************************************************/ + +int usbdev_register(struct usbdevclass_driver_s *driver) +{ + /* At present, there is only a single OTG FS device support. Hence it is + * pre-allocated as g_otgfsdev. However, in most code, the private data + * structure will be referenced using the 'priv' pointer (rather than the + * global data) in order to simplify any future support for multiple + * devices. + */ + + struct at32_usbdev_s *priv = &g_otgfsdev; + int ret; + + usbtrace(TRACE_DEVREGISTER, 0); + +#ifdef CONFIG_DEBUG_FEATURES + if (!driver || !driver->ops->bind || !driver->ops->unbind || + !driver->ops->disconnect || !driver->ops->setup) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } + + if (priv->driver) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_DRIVER), 0); + return -EBUSY; + } +#endif + + /* First hook up the driver */ + + priv->driver = driver; + + /* Then bind the class driver */ + + ret = CLASS_BIND(driver, &priv->usbdev); + if (ret) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_BINDFAILED), (uint16_t)-ret); + priv->driver = NULL; + } + else + { + /* Enable USB controller interrupts */ + + up_enable_irq(AT32_IRQ_OTGFS); + + /* FIXME: nothing seems to call DEV_CONNECT(), but we need to set + * the RS bit to enable the controller. It kind of makes sense + * to do this after the class has bound to us... + * GEN: This bug is really in the class driver. It should make the + * soft connect when it is ready to be enumerated. I have added + * that logic to the class drivers but left this logic here. + */ + + at32_pullup(&priv->usbdev, true); + priv->usbdev.speed = USB_SPEED_FULL; + } + + return ret; +} + +/**************************************************************************** + * Name: usbdev_unregister + * + * Description: + * Un-register usbdev class driver.If the USB device is connected to a USB + * host, it will first disconnect(). The driver is also requested to + * unbind() and clean up any device state, before this procedure finally + * returns. + * + ****************************************************************************/ + +int usbdev_unregister(struct usbdevclass_driver_s *driver) +{ + /* At present, there is only a single OTG FS device support. Hence it is + * pre-allocated as g_otgfsdev. However, in most code, the private data + * structure will be referenced using the 'priv' pointer (rather than the + * global data) in order to simplify any future support for multiple + * devices. + */ + + struct at32_usbdev_s *priv = &g_otgfsdev; + irqstate_t flags; + + usbtrace(TRACE_DEVUNREGISTER, 0); + +#ifdef CONFIG_DEBUG_FEATURES + if (driver != priv->driver) + { + usbtrace(TRACE_DEVERROR(AT32_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + /* Reset the hardware and cancel all requests. All requests must be + * canceled while the class driver is still bound. + */ + + flags = enter_critical_section(); + at32_usbreset(priv); + leave_critical_section(flags); + + /* Unbind the class driver */ + + CLASS_UNBIND(driver, &priv->usbdev); + + /* Disable USB controller interrupts */ + + flags = enter_critical_section(); + up_disable_irq(AT32_IRQ_OTGFS); + + /* Disconnect device */ + + at32_pullup(&priv->usbdev, false); + + /* Unhook the driver */ + + priv->driver = NULL; + leave_critical_section(flags); + + return OK; +} + +#endif /* CONFIG_USBDEV && CONFIG_AT32_OTGFSDEV */ diff --git a/arch/arm/src/at32/at32_otgfshost.c b/arch/arm/src/at32/at32_otgfshost.c new file mode 100644 index 0000000000..1e4d27bb4d --- /dev/null +++ b/arch/arm/src/at32/at32_otgfshost.c @@ -0,0 +1,5467 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_otgfshost.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "chip.h" /* Includes default GPIO settings */ +#include /* May redefine GPIO settings */ + +#include "arm_internal.h" +#include "at32_gpio.h" +#include "at32_usbhost.h" + +#if defined(CONFIG_AT32_USBHOST) && defined(CONFIG_AT32_OTGFS) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* AT32 USB OTG FS Host Driver Support + * + * Pre-requisites + * + * CONFIG_AT32_USBHOST - Enable AT32 USB host support + * CONFIG_USBHOST - Enable general USB host support + * CONFIG_AT32_OTGFS - Enable the AT32 USB OTG FS block + * CONFIG_AT32_SYSCFG - Needed + * + * Options: + * + * CONFIG_AT32_OTGFS_RXFIFO_SIZE - Size of the RX FIFO in 32-bit words. + * Default 128 (512 bytes) + * CONFIG_AT32_OTGFS_NPTXFIFO_SIZE - Size of the non-periodic Tx FIFO + * in 32-bit words. Default 96 (384 bytes) + * CONFIG_AT32_OTGFS_PTXFIFO_SIZE - Size of the periodic Tx FIFO in 32-bit + * words. Default 96 (384 bytes) + * CONFIG_AT32_OTGFS_DESCSIZE - Maximum size of a descriptor. Default: 128 + * CONFIG_AT32_OTGFS_SOFINTR - Enable SOF interrupts. Why would you ever + * want to do that? + * CONFIG_AT32_USBHOST_REGDEBUG - Enable very low-level register access + * debug. Depends on CONFIG_DEBUG_FEATURES. + * CONFIG_AT32_USBHOST_PKTDUMP - Dump all incoming and outgoing USB + * packets. Depends on CONFIG_DEBUG_FEATURES. + */ + +/* Pre-requisites (partial) */ + +#ifndef CONFIG_AT32_SYSCFG +# error "CONFIG_AT32_SYSCFG is required" +#endif + +/* Default RxFIFO size */ + +#ifndef CONFIG_AT32_OTGFS_RXFIFO_SIZE +# define CONFIG_AT32_OTGFS_RXFIFO_SIZE 128 +#endif + +/* Default host non-periodic Tx FIFO size */ + +#ifndef CONFIG_AT32_OTGFS_NPTXFIFO_SIZE +# define CONFIG_AT32_OTGFS_NPTXFIFO_SIZE 96 +#endif + +/* Default host periodic Tx fifo size register */ + +#ifndef CONFIG_AT32_OTGFS_PTXFIFO_SIZE +# define CONFIG_AT32_OTGFS_PTXFIFO_SIZE 96 +#endif + +/* Maximum size of a descriptor */ + +#ifndef CONFIG_AT32_OTGFS_DESCSIZE +# define CONFIG_AT32_OTGFS_DESCSIZE 128 +#endif + +/* Register/packet debug depends on CONFIG_DEBUG_FEATURES */ + +#ifndef CONFIG_DEBUG_USB_INFO +# undef CONFIG_AT32_USBHOST_REGDEBUG +# undef CONFIG_AT32_USBHOST_PKTDUMP +#endif + +/* HCD Setup ****************************************************************/ + +/* Hardware capabilities */ + +#define AT32_NHOST_CHANNELS 16 /* Number of host channels */ +#define AT32_MAX_PACKET_SIZE 64 /* Full speed max packet size */ +#define AT32_EP0_DEF_PACKET_SIZE 8 /* EP0 default packet size */ +#define AT32_EP0_MAX_PACKET_SIZE 64 /* EP0 FS max packet size */ +#define AT32_MAX_TX_FIFOS 15 /* Max number of TX FIFOs */ +#define AT32_MAX_PKTCOUNT 256 /* Max packet count */ +#define AT32_RETRY_COUNT 3 /* Number of ctrl transfer retries */ + +/* Delays *******************************************************************/ + +#define AT32_READY_DELAY 200000 /* In loop counts */ +#define AT32_FLUSH_DELAY 200000 /* In loop counts */ +#define AT32_SETUP_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ +#define AT32_DATANAK_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The following enumeration represents the various states of the USB host + * state machine (for debug purposes only) + */ + +enum at32_smstate_e +{ + SMSTATE_DETACHED = 0, /* Not attached to a device */ + SMSTATE_ATTACHED, /* Attached to a device */ + SMSTATE_ENUM, /* Attached, enumerating */ + SMSTATE_CLASS_BOUND, /* Enumeration complete, class bound */ +}; + +/* This enumeration provides the reason for the channel halt. */ + +enum at32_chreason_e +{ + CHREASON_IDLE = 0, /* Inactive (initial state) */ + CHREASON_FREED, /* Channel is no longer in use */ + CHREASON_XFRC, /* Transfer complete */ + CHREASON_NAK, /* NAK received */ + CHREASON_NYET, /* NotYet received */ + CHREASON_STALL, /* Endpoint stalled */ + CHREASON_TXERR, /* Transfer error received */ + CHREASON_DTERR, /* Data toggle error received */ + CHREASON_FRMOR, /* Frame overrun */ + CHREASON_CANCELLED /* Transfer cancelled */ +}; + +/* This structure retains the state of one host channel. NOTE: Since there + * is only one channel operation active at a time, some of the fields in + * in the structure could be moved in struct at32_ubhost_s to achieve + * some memory savings. + */ + +struct at32_chan_s +{ + sem_t waitsem; /* Channel wait semaphore */ + volatile uint8_t result; /* The result of the transfer */ + volatile uint8_t chreason; /* Channel halt reason. See enum at32_chreason_e */ + uint8_t chidx; /* Channel index */ + uint8_t epno; /* Device endpoint number (0-127) */ + uint8_t eptype; /* See OTGFS_EPTYPE_* definitions */ + uint8_t funcaddr; /* Device function address */ + uint8_t speed; /* Device speed */ + uint8_t interval; /* Interrupt/isochronous EP polling interval */ + uint8_t pid; /* Data PID */ + uint8_t npackets; /* Number of packets (for data toggle) */ + bool inuse; /* True: This channel is "in use" */ + volatile bool indata1; /* IN data toggle. True: DATA01 (Bulk and INTR only) */ + volatile bool outdata1; /* OUT data toggle. True: DATA01 */ + bool in; /* True: IN endpoint */ + volatile bool waiter; /* True: Thread is waiting for a channel event */ + uint16_t maxpacket; /* Max packet size */ + uint16_t buflen; /* Buffer length (at start of transfer) */ + volatile uint16_t xfrd; /* Bytes transferred (at end of transfer) */ + volatile uint16_t inflight; /* Number of Tx bytes "in-flight" */ + uint8_t *buffer; /* Transfer buffer pointer */ +#ifdef CONFIG_USBHOST_ASYNCH + usbhost_asynch_t callback; /* Transfer complete callback */ + void *arg; /* Argument that accompanies the callback */ +#endif +}; + +/* A channel represents on uni-directional endpoint. So, in the case of the + * bi-directional, control endpoint, there must be two channels to represent + * the endpoint. + */ + +struct at32_ctrlinfo_s +{ + uint8_t inndx; /* EP0 IN control channel index */ + uint8_t outndx; /* EP0 OUT control channel index */ +}; + +/* This structure retains the state of the USB host controller */ + +struct at32_usbhost_s +{ + /* Common device fields. This must be the first thing defined in the + * structure so that it is possible to simply cast from struct usbhost_s + * to structat32_usbhost_s. + */ + + struct usbhost_driver_s drvr; + + /* This is the hub port description understood by class drivers */ + + struct usbhost_roothubport_s rhport; + + /* Overall driver status */ + + volatile uint8_t smstate; /* The state of the USB host state machine */ + uint8_t chidx; /* ID of channel waiting for space in Tx FIFO */ + volatile bool connected; /* Connected to device */ + volatile bool change; /* Connection change */ + volatile bool pscwait; /* True: Thread is waiting for a port event */ + mutex_t lock; /* Support mutually exclusive access */ + sem_t pscsem; /* Semaphore to wait for a port event */ + struct at32_ctrlinfo_s ep0; /* Root hub port EP0 description */ + +#ifdef CONFIG_USBHOST_HUB + /* Used to pass external hub port events */ + + volatile struct usbhost_hubport_s *hport; +#endif + + struct usbhost_devaddr_s devgen; /* Address generation data */ + + /* The state of each host channel */ + + struct at32_chan_s chan[AT32_MAX_TX_FIFOS]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register operations ******************************************************/ + +#ifdef CONFIG_AT32_USBHOST_REGDEBUG +static void at32_printreg(uint32_t addr, uint32_t val, bool iswrite); +static void at32_checkreg(uint32_t addr, uint32_t val, bool iswrite); +static uint32_t at32_getreg(uint32_t addr); +static void at32_putreg(uint32_t addr, uint32_t value); +#else +# define at32_getreg(addr) getreg32(addr) +# define at32_putreg(addr,val) putreg32(val,addr) +#endif + +static inline void at32_modifyreg(uint32_t addr, uint32_t clrbits, + uint32_t setbits); + +#ifdef CONFIG_AT32_USBHOST_PKTDUMP +# define at32_pktdump(m,b,n) lib_dumpbuffer(m,b,n) +#else +# define at32_pktdump(m,b,n) +#endif + +/* Byte stream access helper functions **************************************/ + +static inline uint16_t at32_getle16(const uint8_t *val); + +/* Channel management *******************************************************/ + +static int at32_chan_alloc(struct at32_usbhost_s *priv); +static inline void at32_chan_free(struct at32_usbhost_s *priv, + int chidx); +static inline void at32_chan_freeall(struct at32_usbhost_s *priv); +static void at32_chan_configure(struct at32_usbhost_s *priv, + int chidx); +static void at32_chan_halt(struct at32_usbhost_s *priv, int chidx, + enum at32_chreason_e chreason); +static int at32_chan_waitsetup(struct at32_usbhost_s *priv, + struct at32_chan_s *chan); +#ifdef CONFIG_USBHOST_ASYNCH +static int at32_chan_asynchsetup(struct at32_usbhost_s *priv, + struct at32_chan_s *chan, + usbhost_asynch_t callback, void *arg); +#endif +static int at32_chan_wait(struct at32_usbhost_s *priv, + struct at32_chan_s *chan); +static void at32_chan_wakeup(struct at32_usbhost_s *priv, + struct at32_chan_s *chan); +static int at32_ctrlchan_alloc(struct at32_usbhost_s *priv, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, + struct at32_ctrlinfo_s *ctrlep); +static int at32_ctrlep_alloc(struct at32_usbhost_s *priv, + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep); +static int at32_xfrep_alloc(struct at32_usbhost_s *priv, + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep); + +/* Control/data transfer logic **********************************************/ + +static void at32_transfer_start(struct at32_usbhost_s *priv, + int chidx); +#if 0 /* Not used */ +static inline uint16_t at32_getframe(void); +#endif +static int at32_ctrl_sendsetup(struct at32_usbhost_s *priv, + struct at32_ctrlinfo_s *ep0, + const struct usb_ctrlreq_s *req); +static int at32_ctrl_senddata(struct at32_usbhost_s *priv, + struct at32_ctrlinfo_s *ep0, + uint8_t *buffer, unsigned int buflen); +static int at32_ctrl_recvdata(struct at32_usbhost_s *priv, + struct at32_ctrlinfo_s *ep0, + uint8_t *buffer, unsigned int buflen); +static int at32_in_setup(struct at32_usbhost_s *priv, int chidx); +static ssize_t at32_in_transfer(struct at32_usbhost_s *priv, int chidx, + uint8_t *buffer, size_t buflen); +#ifdef CONFIG_USBHOST_ASYNCH +static void at32_in_next(struct at32_usbhost_s *priv, + struct at32_chan_s *chan); +static int at32_in_asynch(struct at32_usbhost_s *priv, int chidx, + uint8_t *buffer, size_t buflen, + usbhost_asynch_t callback, void *arg); +#endif +static int at32_out_setup(struct at32_usbhost_s *priv, int chidx); +static ssize_t at32_out_transfer(struct at32_usbhost_s *priv, + int chidx, uint8_t *buffer, + size_t buflen); +#ifdef CONFIG_USBHOST_ASYNCH +static void at32_out_next(struct at32_usbhost_s *priv, + struct at32_chan_s *chan); +static int at32_out_asynch(struct at32_usbhost_s *priv, int chidx, + uint8_t *buffer, size_t buflen, + usbhost_asynch_t callback, void *arg); +#endif + +/* Interrupt handling *******************************************************/ + +/* Lower level interrupt handlers */ + +static void at32_gint_wrpacket(struct at32_usbhost_s *priv, + uint8_t *buffer, int chidx, int buflen); +static inline void at32_gint_hcinisr(struct at32_usbhost_s *priv, + int chidx); +static inline void at32_gint_hcoutisr(struct at32_usbhost_s *priv, + int chidx); +static void at32_gint_connected(struct at32_usbhost_s *priv); +static void at32_gint_disconnected(struct at32_usbhost_s *priv); + +/* Second level interrupt handlers */ + +#ifdef CONFIG_AT32_OTGFS_SOFINTR +static inline void at32_gint_sofisr(struct at32_usbhost_s *priv); +#endif +static inline void at32_gint_rxflvlisr(struct at32_usbhost_s *priv); +static inline void at32_gint_nptxfeisr(struct at32_usbhost_s *priv); +static inline void at32_gint_ptxfeisr(struct at32_usbhost_s *priv); +static inline void at32_gint_hcisr(struct at32_usbhost_s *priv); +static inline void at32_gint_hprtisr(struct at32_usbhost_s *priv); +static inline void at32_gint_discisr(struct at32_usbhost_s *priv); +static inline void at32_gint_ipxfrisr(struct at32_usbhost_s *priv); + +/* First level, global interrupt handler */ + +static int at32_gint_isr(int irq, void *context, void *arg); + +/* Interrupt controls */ + +static void at32_gint_enable(void); +static void at32_gint_disable(void); +static inline void at32_hostinit_enable(void); +static void at32_txfe_enable(struct at32_usbhost_s *priv, int chidx); + +/* USB host controller operations *******************************************/ + +static int at32_wait(struct usbhost_connection_s *conn, + struct usbhost_hubport_s **hport); +static int at32_rh_enumerate(struct at32_usbhost_s *priv, + struct usbhost_connection_s *conn, + struct usbhost_hubport_s *hport); +static int at32_enumerate(struct usbhost_connection_s *conn, + struct usbhost_hubport_s *hport); + +static int at32_ep0configure(struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize); +static int at32_epalloc(struct usbhost_driver_s *drvr, + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep); +static int at32_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep); +static int at32_alloc(struct usbhost_driver_s *drvr, + uint8_t **buffer, size_t *maxlen); +static int at32_free(struct usbhost_driver_s *drvr, + uint8_t *buffer); +static int at32_ioalloc(struct usbhost_driver_s *drvr, + uint8_t **buffer, size_t buflen); +static int at32_iofree(struct usbhost_driver_s *drvr, + uint8_t *buffer); +static int at32_ctrlin(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, + const struct usb_ctrlreq_s *req, + uint8_t *buffer); +static int at32_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, + const struct usb_ctrlreq_s *req, + const uint8_t *buffer); +static ssize_t at32_transfer(struct usbhost_driver_s *drvr, + usbhost_ep_t ep, uint8_t *buffer, + size_t buflen); +#ifdef CONFIG_USBHOST_ASYNCH +static int at32_asynch(struct usbhost_driver_s *drvr, usbhost_ep_t ep, + uint8_t *buffer, size_t buflen, + usbhost_asynch_t callback, void *arg); +#endif +static int at32_cancel(struct usbhost_driver_s *drvr, usbhost_ep_t ep); +#ifdef CONFIG_USBHOST_HUB +static int at32_connect(struct usbhost_driver_s *drvr, + struct usbhost_hubport_s *hport, + bool connected); +#endif +static void at32_disconnect(struct usbhost_driver_s *drvr, + struct usbhost_hubport_s *hport); + +/* Initialization ***********************************************************/ + +static void at32_portreset(struct at32_usbhost_s *priv); +static void at32_flush_txfifos(uint32_t txfnum); +static void at32_flush_rxfifo(void); +static void at32_vbusdrive(struct at32_usbhost_s *priv, bool state); +static void at32_host_initialize(struct at32_usbhost_s *priv); + +static inline void at32_sw_initialize(struct at32_usbhost_s *priv); +static inline int at32_hw_initialize(struct at32_usbhost_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* In this driver implementation, support is provided for only a single a + * single USB device. All status information can be simply retained in a + * single global instance. + */ + +static struct at32_usbhost_s g_usbhost = +{ + .lock = NXMUTEX_INITIALIZER, + .pscsem = SEM_INITIALIZER(0), +}; + +/* This is the connection/enumeration interface */ + +static struct usbhost_connection_s g_usbconn = +{ + .wait = at32_wait, + .enumerate = at32_enumerate, +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_printreg + * + * Description: + * Print the contents of an AT32xx register operation + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_USBHOST_REGDEBUG +static void at32_printreg(uint32_t addr, uint32_t val, bool iswrite) +{ + uinfo("%08x%s%08x\n", addr, iswrite ? "<-" : "->", val); +} +#endif + +/**************************************************************************** + * Name: at32_checkreg + * + * Description: + * Get the contents of an AT32 register + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_USBHOST_REGDEBUG +static void at32_checkreg(uint32_t addr, uint32_t val, bool iswrite) +{ + static uint32_t prevaddr = 0; + static uint32_t preval = 0; + static uint32_t count = 0; + static bool prevwrite = false; + + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. + */ + + if (addr == prevaddr && val == preval && prevwrite == iswrite) + { + /* Yes.. Just increment the count */ + + count++; + } + else + { + /* No this is a new address or value or operation. Were there any + * duplicate accesses before this one? + */ + + if (count > 0) + { + /* Yes.. Just one? */ + + if (count == 1) + { + /* Yes.. Just one */ + + at32_printreg(prevaddr, preval, prevwrite); + } + else + { + /* No.. More than one. */ + + uinfo("[repeats %d more times]\n", count); + } + } + + /* Save the new address, value, count, and operation for next time */ + + prevaddr = addr; + preval = val; + count = 0; + prevwrite = iswrite; + + /* Show the new regisgter access */ + + at32_printreg(addr, val, iswrite); + } +} +#endif + +/**************************************************************************** + * Name: at32_getreg + * + * Description: + * Get the contents of an AT32 register + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_USBHOST_REGDEBUG +static uint32_t at32_getreg(uint32_t addr) +{ + /* Read the value from the register */ + + uint32_t val = getreg32(addr); + + /* Check if we need to print this value */ + + at32_checkreg(addr, val, false); + return val; +} +#endif + +/**************************************************************************** + * Name: at32_putreg + * + * Description: + * Set the contents of an AT32 register to a value + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_USBHOST_REGDEBUG +static void at32_putreg(uint32_t addr, uint32_t val) +{ + /* Check if we need to print this value */ + + at32_checkreg(addr, val, true); + + /* Write the value */ + + putreg32(val, addr); +} +#endif + +/**************************************************************************** + * Name: at32_modifyreg + * + * Description: + * Modify selected bits of an AT32 register. + * + ****************************************************************************/ + +static inline void at32_modifyreg(uint32_t addr, uint32_t clrbits, + uint32_t setbits) +{ + at32_putreg(addr, (((at32_getreg(addr)) & ~clrbits) | setbits)); +} + +/**************************************************************************** + * Name: at32_getle16 + * + * Description: + * Get a (possibly unaligned) 16-bit little endian value. + * + ****************************************************************************/ + +static inline uint16_t at32_getle16(const uint8_t *val) +{ + return (uint16_t)val[1] << 8 | (uint16_t)val[0]; +} + +/**************************************************************************** + * Name: at32_chan_alloc + * + * Description: + * Allocate a channel. + * + ****************************************************************************/ + +static int at32_chan_alloc(struct at32_usbhost_s *priv) +{ + int chidx; + + /* Search the table of channels */ + + for (chidx = 0; chidx < AT32_NHOST_CHANNELS; chidx++) + { + /* Is this channel available? */ + + if (!priv->chan[chidx].inuse) + { + /* Yes... make it "in use" and return the index */ + + priv->chan[chidx].inuse = true; + return chidx; + } + } + + /* All of the channels are "in-use" */ + + return -EBUSY; +} + +/**************************************************************************** + * Name: at32_chan_free + * + * Description: + * Free a previoiusly allocated channel. + * + ****************************************************************************/ + +static void at32_chan_free(struct at32_usbhost_s *priv, int chidx) +{ + DEBUGASSERT((unsigned)chidx < AT32_NHOST_CHANNELS); + + /* Halt the channel */ + + at32_chan_halt(priv, chidx, CHREASON_FREED); + + /* Mark the channel available */ + + priv->chan[chidx].inuse = false; +} + +/**************************************************************************** + * Name: at32_chan_freeall + * + * Description: + * Free all channels. + * + ****************************************************************************/ + +static inline void at32_chan_freeall(struct at32_usbhost_s *priv) +{ + uint8_t chidx; + + /* Free all host channels */ + + for (chidx = 2; chidx < AT32_NHOST_CHANNELS; chidx++) + { + at32_chan_free(priv, chidx); + } +} + +/**************************************************************************** + * Name: at32_chan_configure + * + * Description: + * Configure or re-configure a host channel. Host channels are configured + * when endpoint is allocated and EP0 (only) is re-configured with the + * max packet size or device address changes. + * + ****************************************************************************/ + +static void at32_chan_configure(struct at32_usbhost_s *priv, int chidx) +{ + struct at32_chan_s *chan = &priv->chan[chidx]; + uint32_t regval; + + /* Clear any old pending interrupts for this host channel. */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), 0xffffffff); + + /* Enable channel interrupts required for transfers on this channel. */ + + regval = 0; + + switch (chan->eptype) + { + case OTGFS_EPTYPE_CTRL: + case OTGFS_EPTYPE_BULK: + { +#ifdef HAVE_USBHOST_TRACE_VERBOSE + uint16_t intrace; + uint16_t outtrace; + + /* Determine the definitive trace ID to use below */ + + if (chan->eptype == OTGFS_EPTYPE_CTRL) + { + intrace = OTGFS_VTRACE2_CHANCONF_CTRL_IN; + outtrace = OTGFS_VTRACE2_CHANCONF_CTRL_OUT; + } + else + { + intrace = OTGFS_VTRACE2_CHANCONF_BULK_IN; + outtrace = OTGFS_VTRACE2_CHANCONF_BULK_OUT; + } +#endif + + /* Interrupts required for CTRL and BULK endpoints */ + + regval |= (OTGFS_HCINT_XFRC | OTGFS_HCINT_STALL | OTGFS_HCINT_NAK | + OTGFS_HCINT_TXERR | OTGFS_HCINT_DTERR); + + /* Additional setting for IN/OUT endpoints */ + + if (chan->in) + { + usbhost_vtrace2(intrace, chidx, chan->epno); + regval |= OTGFS_HCINT_BBERR; + } + else + { + usbhost_vtrace2(outtrace, chidx, chan->epno); + regval |= OTGFS_HCINT_NYET; + } + } + break; + + case OTGFS_EPTYPE_INTR: + { + /* Interrupts required for INTR endpoints */ + + regval |= (OTGFS_HCINT_XFRC | OTGFS_HCINT_STALL | + OTGFS_HCINT_NAK | OTGFS_HCINT_TXERR | + OTGFS_HCINT_FRMOR | OTGFS_HCINT_DTERR); + + /* Additional setting for IN endpoints */ + + if (chan->in) + { + usbhost_vtrace2(OTGFS_VTRACE2_CHANCONF_INTR_IN, chidx, + chan->epno); + regval |= OTGFS_HCINT_BBERR; + } +#ifdef HAVE_USBHOST_TRACE_VERBOSE + else + { + usbhost_vtrace2(OTGFS_VTRACE2_CHANCONF_INTR_OUT, chidx, + chan->epno); + } +#endif + } + break; + + case OTGFS_EPTYPE_ISOC: + { + /* Interrupts required for ISOC endpoints */ + + regval |= OTGFS_HCINT_XFRC | OTGFS_HCINT_ACK | OTGFS_HCINT_FRMOR; + + /* Additional setting for IN endpoints */ + + if (chan->in) + { + usbhost_vtrace2(OTGFS_VTRACE2_CHANCONF_ISOC_IN, chidx, + chan->epno); + regval |= (OTGFS_HCINT_TXERR | OTGFS_HCINT_BBERR); + } +#ifdef HAVE_USBHOST_TRACE_VERBOSE + else + { + usbhost_vtrace2(OTGFS_VTRACE2_CHANCONF_ISOC_OUT, chidx, + chan->epno); + } +#endif + } + break; + } + + at32_putreg(AT32_OTGFS_HCINTMSK(chidx), regval); + + /* Enable the top level host channel interrupt. */ + + at32_modifyreg(AT32_OTGFS_HAINTMSK, 0, OTGFS_HAINT(chidx)); + + /* Make sure host channel interrupts are enabled. */ + + at32_modifyreg(AT32_OTGFS_GINTMSK, 0, OTGFS_GINT_HC); + + /* Program the HCCHAR register */ + + regval = ((uint32_t)chan->maxpacket << OTGFS_HCCHAR_MPSIZ_SHIFT) | + ((uint32_t)chan->epno << OTGFS_HCCHAR_EPNUM_SHIFT) | + ((uint32_t)chan->eptype << OTGFS_HCCHAR_EPTYP_SHIFT) | + ((uint32_t)chan->funcaddr << OTGFS_HCCHAR_DAD_SHIFT); + + /* Special case settings for low speed devices */ + + if (chan->speed == USB_SPEED_LOW) + { + regval |= OTGFS_HCCHAR_LSDEV; + } + + /* Special case settings for IN endpoints */ + + if (chan->in) + { + regval |= OTGFS_HCCHAR_EPDIR_IN; + } + + /* Special case settings for INTR endpoints */ + + if (chan->eptype == OTGFS_EPTYPE_INTR) + { + regval |= OTGFS_HCCHAR_ODDFRM; + } + + /* Write the channel configuration */ + + at32_putreg(AT32_OTGFS_HCCHAR(chidx), regval); +} + +/**************************************************************************** + * Name: at32_chan_halt + * + * Description: + * Halt the channel associated with 'chidx' by setting the CHannel DISable + * (CHDIS) bit in in the HCCHAR register. + * + ****************************************************************************/ + +static void at32_chan_halt(struct at32_usbhost_s *priv, int chidx, + enum at32_chreason_e chreason) +{ + uint32_t hcchar; + uint32_t intmsk; + uint32_t eptype; + unsigned int avail; + + /* Save the reason for the halt. We need this in the channel halt + * interrupt handling logic to know what to do next. + */ + + usbhost_vtrace2(OTGFS_VTRACE2_CHANHALT, chidx, chreason); + + priv->chan[chidx].chreason = (uint8_t)chreason; + + /* "The application can disable any channel by programming the + * OTG_FS_HCCHARx register with the CHDIS and CHENA bits set to 1. This + * enables the OTG_FS host to flush the posted requests (if any) and + * generates a channel halted interrupt. The application must wait for + * the CHH interrupt in OTG_FS_HCINTx before reallocating the channel for + * other transactions. The OTG_FS host does not interrupt the + * transaction that has already been started on the USB." + */ + + hcchar = at32_getreg(AT32_OTGFS_HCCHAR(chidx)); + hcchar |= (OTGFS_HCCHAR_CHDIS | OTGFS_HCCHAR_CHENA); + + /* Get the endpoint type from the HCCHAR register */ + + eptype = hcchar & OTGFS_HCCHAR_EPTYP_MASK; + + /* Check for space in the Tx FIFO to issue the halt. + * + * "Before disabling a channel, the application must ensure that there is + * at least one free space available in the non-periodic request queue + * (when disabling a non-periodic channel) or the periodic request queue + * (when disabling a periodic channel). The application can simply flush + * the posted requests when the Request queue is full (before disabling + * the channel), by programming the OTG_FS_HCCHARx register with the + * CHDIS bit set to 1, and the CHENA bit cleared to 0." + */ + + if (eptype == OTGFS_HCCHAR_EPTYP_CTRL || + eptype == OTGFS_HCCHAR_EPTYP_BULK) + { + /* Get the number of words available in the non-periodic Tx FIFO. */ + + avail = at32_getreg(AT32_OTGFS_HNPTXSTS) & + OTGFS_HNPTXSTS_NPTXFSAV_MASK; + } + else + { + /* Get the number of words available in the non-periodic Tx FIFO. */ + + avail = at32_getreg(AT32_OTGFS_HPTXSTS) & + OTGFS_HPTXSTS_PTXFSAVL_MASK; + } + + /* Check if there is any space available in the Tx FIFO. */ + + if (avail == 0) + { + /* The Tx FIFO is full... disable the channel to flush the requests */ + + hcchar &= ~OTGFS_HCCHAR_CHENA; + } + + /* Unmask the CHannel Halted (CHH) interrupt */ + + intmsk = at32_getreg(AT32_OTGFS_HCINTMSK(chidx)); + intmsk |= OTGFS_HCINT_CHH; + at32_putreg(AT32_OTGFS_HCINTMSK(chidx), intmsk); + + /* Halt the channel by setting CHDIS (and maybe CHENA) in the HCCHAR */ + + at32_putreg(AT32_OTGFS_HCCHAR(chidx), hcchar); +} + +/**************************************************************************** + * Name: at32_chan_waitsetup + * + * Description: + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the transfer). + * We do this to minimize race conditions. This logic would have to be + * expanded if we want to have more than one packet in flight at a time! + * + * Assumptions: + * Called from a normal thread context BEFORE the transfer has been + * started. + * + ****************************************************************************/ + +static int at32_chan_waitsetup(struct at32_usbhost_s *priv, + struct at32_chan_s *chan) +{ + irqstate_t flags = enter_critical_section(); + int ret = -ENODEV; + + /* Is the device still connected? */ + + if (priv->connected) + { + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. + */ + + chan->waiter = true; +#ifdef CONFIG_USBHOST_ASYNCH + chan->callback = NULL; + chan->arg = NULL; +#endif + ret = OK; + } + + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Name: at32_chan_asynchsetup + * + * Description: + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the to avoid + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! + * + * Assumptions: + * Might be called from the level of an interrupt handler + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST_ASYNCH +static int at32_chan_asynchsetup(struct at32_usbhost_s *priv, + struct at32_chan_s *chan, + usbhost_asynch_t callback, void *arg) +{ + irqstate_t flags = enter_critical_section(); + int ret = -ENODEV; + + /* Is the device still connected? */ + + if (priv->connected) + { + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. + */ + + chan->waiter = false; + chan->callback = callback; + chan->arg = arg; + ret = OK; + } + + leave_critical_section(flags); + return ret; +} +#endif + +/**************************************************************************** + * Name: at32_chan_wait + * + * Description: + * Wait for a transfer on a channel to complete. + * + * Assumptions: + * Called from a normal thread context + * + ****************************************************************************/ + +static int at32_chan_wait(struct at32_usbhost_s *priv, + struct at32_chan_s *chan) +{ + irqstate_t flags; + int ret; + + /* Disable interrupts so that the following operations will be atomic. On + * the OTG FS global interrupt needs to be disabled. However, here we + * disable all interrupts to exploit that fact that interrupts will be re- + * enabled while we wait. + */ + + flags = enter_critical_section(); + + /* Loop, testing for an end of transfer condition. The channel 'result' + * was set to EBUSY and 'waiter' was set to true before the transfer; + * 'waiter' will be set to false and 'result' will be set appropriately + * when the transfer is completed. + */ + + do + { + /* Wait for the transfer to complete. NOTE the transfer may already + * completed before we get here or the transfer may complete while we + * wait here. + */ + + ret = nxsem_wait_uninterruptible(&chan->waitsem); + } + while (chan->waiter && ret >= 0); + + /* The transfer is complete re-enable interrupts and return the result */ + + if (ret >= 0) + { + ret = -(int)chan->result; + } + + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Name: at32_chan_wakeup + * + * Description: + * A channel transfer has completed... wakeup any threads waiting for the + * transfer to complete. + * + * Assumptions: + * This function is called from the transfer complete interrupt handler for + * the channel. Interrupts are disabled. + * + ****************************************************************************/ + +static void at32_chan_wakeup(struct at32_usbhost_s *priv, + struct at32_chan_s *chan) +{ + /* Is the transfer complete? */ + + if (chan->result != EBUSY) + { + /* Is there a thread waiting for this transfer to complete? */ + + if (chan->waiter) + { +#ifdef CONFIG_USBHOST_ASYNCH + /* Yes.. there should not also be a callback scheduled */ + + DEBUGASSERT(chan->callback == NULL); +#endif + /* Wake'em up! */ + + usbhost_vtrace2(chan->in ? OTGFS_VTRACE2_CHANWAKEUP_IN : + OTGFS_VTRACE2_CHANWAKEUP_OUT, + chan->epno, chan->result); + + nxsem_post(&chan->waitsem); + chan->waiter = false; + } + +#ifdef CONFIG_USBHOST_ASYNCH + /* No.. is an asynchronous callback expected when the transfer + * completes? + */ + + else if (chan->callback) + { + /* Handle continuation of IN/OUT pipes */ + + if (chan->in) + { + at32_in_next(priv, chan); + } + else + { + at32_out_next(priv, chan); + } + } +#endif + } +} + +/**************************************************************************** + * Name: at32_ctrlchan_alloc + * + * Description: + * Allocate and configured channels for a control pipe. + * + ****************************************************************************/ + +static int at32_ctrlchan_alloc(struct at32_usbhost_s *priv, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, + struct at32_ctrlinfo_s *ctrlep) +{ + struct at32_chan_s *chan; + int inndx; + int outndx; + + outndx = at32_chan_alloc(priv); + if (outndx < 0) + { + return -ENOMEM; + } + + ctrlep->outndx = outndx; + chan = &priv->chan[outndx]; + chan->epno = epno; + chan->in = false; + chan->eptype = OTGFS_EPTYPE_CTRL; + chan->funcaddr = funcaddr; + chan->speed = speed; + chan->interval = 0; + chan->maxpacket = AT32_EP0_DEF_PACKET_SIZE; + chan->indata1 = false; + chan->outdata1 = false; + + /* Configure control OUT channels */ + + at32_chan_configure(priv, outndx); + + /* Allocate and initialize the control IN channel */ + + inndx = at32_chan_alloc(priv); + if (inndx < 0) + { + at32_chan_free(priv, outndx); + return -ENOMEM; + } + + ctrlep->inndx = inndx; + chan = &priv->chan[inndx]; + chan->epno = epno; + chan->in = true; + chan->eptype = OTGFS_EPTYPE_CTRL; + chan->funcaddr = funcaddr; + chan->speed = speed; + chan->interval = 0; + chan->maxpacket = AT32_EP0_DEF_PACKET_SIZE; + chan->indata1 = false; + chan->outdata1 = false; + + /* Configure control IN channels */ + + at32_chan_configure(priv, inndx); + return OK; +} + +/**************************************************************************** + * Name: at32_ctrlep_alloc + * + * Description: + * Allocate a container and channels for control pipe. + * + * Input Parameters: + * priv - The private USB host driver state. + * epdesc - Describes the endpoint to be allocated. + * ep - A memory location provided by the caller in which to receive the + * allocated endpoint descriptor. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_ctrlep_alloc(struct at32_usbhost_s *priv, + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep) +{ + struct usbhost_hubport_s *hport; + struct at32_ctrlinfo_s *ctrlep; + int ret; + + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). + */ + + DEBUGASSERT(epdesc->hport != NULL); + hport = epdesc->hport; + + /* Allocate a container for the control endpoint */ + + ctrlep = (struct at32_ctrlinfo_s *) + kmm_malloc(sizeof(struct at32_ctrlinfo_s)); + if (ctrlep == NULL) + { + uerr("ERROR: Failed to allocate control endpoint container\n"); + return -ENOMEM; + } + + /* Then allocate and configure the IN/OUT channels */ + + ret = at32_ctrlchan_alloc(priv, epdesc->addr & USB_EPNO_MASK, + hport->funcaddr, hport->speed, ctrlep); + if (ret < 0) + { + uerr("ERROR: at32_ctrlchan_alloc failed: %d\n", ret); + kmm_free(ctrlep); + return ret; + } + + /* Return a pointer to the control pipe container as the pipe "handle" */ + + *ep = (usbhost_ep_t)ctrlep; + return OK; +} + +/**************************************************************************** + * Name: at32_xfrep_alloc + * + * Description: + * Allocate and configure one unidirectional endpoint. + * + * Input Parameters: + * priv - The private USB host driver state. + * epdesc - Describes the endpoint to be allocated. + * ep - A memory location provided by the caller in which to receive the + * allocated endpoint descriptor. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_xfrep_alloc(struct at32_usbhost_s *priv, + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep) +{ + struct usbhost_hubport_s *hport; + struct at32_chan_s *chan; + int chidx; + + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). + */ + + DEBUGASSERT(epdesc->hport != NULL); + hport = epdesc->hport; + + /* Allocate a host channel for the endpoint */ + + chidx = at32_chan_alloc(priv); + if (chidx < 0) + { + uerr("ERROR: Failed to allocate a host channel\n"); + return -ENOMEM; + } + + /* Decode the endpoint descriptor to initialize the channel data + * structures. Note: Here we depend on the fact that the endpoint + * point type is encoded in the same way in the endpoint descriptor as it + * is in the OTG HS hardware. + */ + + chan = &priv->chan[chidx]; + chan->epno = epdesc->addr & USB_EPNO_MASK; + chan->in = epdesc->in; + chan->eptype = epdesc->xfrtype; + chan->funcaddr = hport->funcaddr; + chan->speed = hport->speed; + chan->interval = epdesc->interval; + chan->maxpacket = epdesc->mxpacketsize; + chan->indata1 = false; + chan->outdata1 = false; + + /* Then configure the endpoint */ + + at32_chan_configure(priv, chidx); + + /* Return the index to the allocated channel as the endpoint "handle" */ + + *ep = (usbhost_ep_t)chidx; + return OK; +} + +/**************************************************************************** + * Name: at32_transfer_start + * + * Description: + * Start at transfer on the select IN or OUT channel. + * + ****************************************************************************/ + +static void at32_transfer_start(struct at32_usbhost_s *priv, int chidx) +{ + struct at32_chan_s *chan; + uint32_t regval; + unsigned int npackets; + unsigned int maxpacket; + unsigned int avail; + unsigned int wrsize; + unsigned int minsize; + + /* Set up the initial state of the transfer */ + + chan = &priv->chan[chidx]; + + usbhost_vtrace2(OTGFS_VTRACE2_STARTTRANSFER, chidx, chan->buflen); + + chan->result = EBUSY; + chan->inflight = 0; + chan->xfrd = 0; + priv->chidx = chidx; + + /* Compute the expected number of packets associated to the transfer. + * If the transfer length is zero (or less than the size of one maximum + * size packet), then one packet is expected. + */ + + /* If the transfer size is greater than one packet, then calculate the + * number of packets that will be received/sent, including any partial + * final packet. + */ + + maxpacket = chan->maxpacket; + + if (chan->buflen > maxpacket) + { + npackets = (chan->buflen + maxpacket - 1) / maxpacket; + + /* Clip if the buffer length if it exceeds the maximum number of + * packets that can be transferred (this should not happen). + */ + + if (npackets > AT32_MAX_PKTCOUNT) + { + npackets = AT32_MAX_PKTCOUNT; + chan->buflen = AT32_MAX_PKTCOUNT * maxpacket; + usbhost_trace2(OTGFS_TRACE2_CLIP, chidx, chan->buflen); + } + } + else + { + /* One packet will be sent/received (might be a zero length packet) */ + + npackets = 1; + } + + /* If it is an IN transfer, then adjust the size of the buffer UP to + * a full number of packets. Hmmm... couldn't this cause an overrun + * into unallocated memory? + */ + +#if 0 /* Think about this */ + if (chan->in) + { + /* Force the buffer length to an even multiple of maxpacket */ + + chan->buflen = npackets * maxpacket; + } +#endif + + /* Save the number of packets in the transfer. We will need this in + * order to set the next data toggle correctly when the transfer + * completes. + */ + + chan->npackets = (uint8_t)npackets; + + /* Setup the HCTSIZn register */ + + regval = ((uint32_t)chan->buflen << OTGFS_HCTSIZ_XFRSIZ_SHIFT) | + ((uint32_t)npackets << OTGFS_HCTSIZ_PKTCNT_SHIFT) | + ((uint32_t)chan->pid << OTGFS_HCTSIZ_DPID_SHIFT); + at32_putreg(AT32_OTGFS_HCTSIZ(chidx), regval); + + /* Setup the HCCHAR register: Frame oddness and host channel enable */ + + regval = at32_getreg(AT32_OTGFS_HCCHAR(chidx)); + + /* Set/clear the Odd Frame bit. Check for an even frame; if so set Odd + * Frame. This field is applicable for only periodic (isochronous and + * interrupt) channels. + */ + + if ((at32_getreg(AT32_OTGFS_HFNUM) & 1) == 0) + { + regval |= OTGFS_HCCHAR_ODDFRM; + } + else + { + regval &= ~OTGFS_HCCHAR_ODDFRM; + } + + regval &= ~OTGFS_HCCHAR_CHDIS; + regval |= OTGFS_HCCHAR_CHENA; + at32_putreg(AT32_OTGFS_HCCHAR(chidx), regval); + + /* If this is an out transfer, then we need to do more.. we need to copy + * the outgoing data into the correct TxFIFO. + */ + + if (!chan->in && chan->buflen > 0) + { + /* Handle non-periodic (CTRL and BULK) OUT transfers differently than + * periodic (INTR and ISOC) OUT transfers. + */ + + minsize = MIN(chan->buflen, chan->maxpacket); + + switch (chan->eptype) + { + case OTGFS_EPTYPE_CTRL: /* Non periodic transfer */ + case OTGFS_EPTYPE_BULK: + { + /* Read the Non-periodic Tx FIFO status register */ + + regval = at32_getreg(AT32_OTGFS_HNPTXSTS); + avail = ((regval & OTGFS_HNPTXSTS_NPTXFSAV_MASK) >> + OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) << 2; + } + break; + + /* Periodic transfer */ + + case OTGFS_EPTYPE_INTR: + case OTGFS_EPTYPE_ISOC: + { + /* Read the Non-periodic Tx FIFO status register */ + + regval = at32_getreg(AT32_OTGFS_HPTXSTS); + avail = ((regval & OTGFS_HPTXSTS_PTXFSAVL_MASK) >> + OTGFS_HPTXSTS_PTXFSAVL_SHIFT) << 2; + } + break; + + default: + DEBUGPANIC(); + return; + } + + /* Is there space in the TxFIFO to hold the minimum size packet? */ + + if (minsize <= avail) + { + /* Yes.. Get the size of the biggest thing that we can put + * in the Tx FIFO now + */ + + wrsize = chan->buflen; + if (wrsize > avail) + { + /* Clip the write size to the number of full, max sized packets + * that will fit in the Tx FIFO. + */ + + unsigned int wrpackets = avail / chan->maxpacket; + wrsize = wrpackets * chan->maxpacket; + } + + /* Write packet into the Tx FIFO. */ + + at32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); + } + + /* Did we put the entire buffer into the Tx FIFO? */ + + if (chan->buflen > avail) + { + /* No, there was insufficient space to hold the entire transfer ... + * Enable the Tx FIFO interrupt to handle the transfer when the Tx + * FIFO becomes empty. + */ + + at32_txfe_enable(priv, chidx); + } + } +} + +/**************************************************************************** + * Name: at32_getframe + * + * Description: + * Get the current frame number. The frame number (FRNUM) field increments + * when a new SOF is transmitted on the USB, and is cleared to 0 when it + * reaches 0x3fff. + * + ****************************************************************************/ + +#if 0 /* Not used */ +static inline uint16_t at32_getframe(void) +{ + return (uint16_t) + (at32_getreg(AT32_OTGFS_HFNUM) & OTGFS_HFNUM_FRNUM_MASK); +} +#endif + +/**************************************************************************** + * Name: at32_ctrl_sendsetup + * + * Description: + * Send an IN/OUT SETUP packet. + * + ****************************************************************************/ + +static int at32_ctrl_sendsetup(struct at32_usbhost_s *priv, + struct at32_ctrlinfo_s *ep0, + const struct usb_ctrlreq_s *req) +{ + struct at32_chan_s *chan; + clock_t start; + clock_t elapsed; + int ret; + + /* Loop while the device reports NAK (and a timeout is not exceeded */ + + chan = &priv->chan[ep0->outndx]; + start = clock_systime_ticks(); + + do + { + /* Send the SETUP packet */ + + chan->pid = OTGFS_PID_SETUP; + chan->buffer = (uint8_t *)req; + chan->buflen = USB_SIZEOF_CTRLREQ; + chan->xfrd = 0; + + /* Set up for the wait BEFORE starting the transfer */ + + ret = at32_chan_waitsetup(priv, chan); + if (ret < 0) + { + usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0); + return ret; + } + + /* Start the transfer */ + + at32_transfer_start(priv, ep0->outndx); + + /* Wait for the transfer to complete */ + + ret = at32_chan_wait(priv, chan); + + /* Return on success and for all failures other than EAGAIN. EAGAIN + * means that the device NAKed the SETUP command and that we should + * try a few more times. + */ + + if (ret != -EAGAIN) + { + /* Output some debug information if the transfer failed */ + + if (ret < 0) + { + usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret); + } + + /* Return the result in any event */ + + return ret; + } + + /* Get the elapsed time (in frames) */ + + elapsed = clock_systime_ticks() - start; + } + while (elapsed < AT32_SETUP_DELAY); + + return -ETIMEDOUT; +} + +/**************************************************************************** + * Name: at32_ctrl_senddata + * + * Description: + * Send data in the data phase of an OUT control transfer. Or send status + * in the status phase of an IN control transfer + * + ****************************************************************************/ + +static int at32_ctrl_senddata(struct at32_usbhost_s *priv, + struct at32_ctrlinfo_s *ep0, + uint8_t *buffer, unsigned int buflen) +{ + struct at32_chan_s *chan = &priv->chan[ep0->outndx]; + int ret; + + /* Save buffer information */ + + chan->buffer = buffer; + chan->buflen = buflen; + chan->xfrd = 0; + + /* Set the DATA PID */ + + if (buflen == 0) + { + /* For status OUT stage with buflen == 0, set PID DATA1 */ + + chan->outdata1 = true; + } + + /* Set the Data PID as per the outdata1 boolean */ + + chan->pid = chan->outdata1 ? OTGFS_PID_DATA1 : OTGFS_PID_DATA0; + + /* Set up for the wait BEFORE starting the transfer */ + + ret = at32_chan_waitsetup(priv, chan); + if (ret < 0) + { + usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0); + return ret; + } + + /* Start the transfer */ + + at32_transfer_start(priv, ep0->outndx); + + /* Wait for the transfer to complete and return the result */ + + return at32_chan_wait(priv, chan); +} + +/**************************************************************************** + * Name: at32_ctrl_recvdata + * + * Description: + * Receive data in the data phase of an IN control transfer. Or receive + * status in the status phase of an OUT control transfer + * + ****************************************************************************/ + +static int at32_ctrl_recvdata(struct at32_usbhost_s *priv, + struct at32_ctrlinfo_s *ep0, + uint8_t *buffer, unsigned int buflen) +{ + struct at32_chan_s *chan = &priv->chan[ep0->inndx]; + int ret; + + /* Save buffer information */ + + chan->pid = OTGFS_PID_DATA1; + chan->buffer = buffer; + chan->buflen = buflen; + chan->xfrd = 0; + + /* Set up for the wait BEFORE starting the transfer */ + + ret = at32_chan_waitsetup(priv, chan); + if (ret < 0) + { + usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0); + return ret; + } + + /* Start the transfer */ + + at32_transfer_start(priv, ep0->inndx); + + /* Wait for the transfer to complete and return the result */ + + return at32_chan_wait(priv, chan); +} + +/**************************************************************************** + * Name: at32_in_setup + * + * Description: + * Initiate an IN transfer on an bulk, interrupt, or isochronous pipe. + * + ****************************************************************************/ + +static int at32_in_setup(struct at32_usbhost_s *priv, int chidx) +{ + struct at32_chan_s *chan; + + /* Set up for the transfer based on the direction and the endpoint type */ + + chan = &priv->chan[chidx]; + switch (chan->eptype) + { + default: + case OTGFS_EPTYPE_CTRL: /* Control */ + { + /* This kind of transfer on control endpoints other than EP0 are not + * currently supported + */ + + return -ENOSYS; + } + + case OTGFS_EPTYPE_ISOC: /* Isochronous */ + { + /* Set up the IN data PID */ + + usbhost_vtrace2(OTGFS_VTRACE2_ISOCIN, chidx, chan->buflen); + chan->pid = OTGFS_PID_DATA0; + } + break; + + case OTGFS_EPTYPE_BULK: /* Bulk */ + { + /* Setup the IN data PID */ + + usbhost_vtrace2(OTGFS_VTRACE2_BULKIN, chidx, chan->buflen); + chan->pid = chan->indata1 ? OTGFS_PID_DATA1 : OTGFS_PID_DATA0; + } + break; + + case OTGFS_EPTYPE_INTR: /* Interrupt */ + { + /* Setup the IN data PID */ + + usbhost_vtrace2(OTGFS_VTRACE2_INTRIN, chidx, chan->buflen); + chan->pid = chan->indata1 ? OTGFS_PID_DATA1 : OTGFS_PID_DATA0; + } + break; + } + + /* Start the transfer */ + + at32_transfer_start(priv, chidx); + return OK; +} + +/**************************************************************************** + * Name: at32_in_transfer + * + * Description: + * Transfer 'buflen' bytes into 'buffer' from an IN channel. + * + ****************************************************************************/ + +static ssize_t at32_in_transfer(struct at32_usbhost_s *priv, int chidx, + uint8_t *buffer, size_t buflen) +{ + struct at32_chan_s *chan; + clock_t start; + ssize_t xfrd; + int ret; + + /* Loop until the transfer completes (i.e., buflen is decremented to zero) + * or a fatal error occurs any error other than a simple NAK. NAK would + * simply indicate the end of the transfer (short-transfer). + */ + + chan = &priv->chan[chidx]; + chan->buffer = buffer; + chan->buflen = buflen; + chan->xfrd = 0; + xfrd = 0; + + start = clock_systime_ticks(); + while (chan->xfrd < chan->buflen) + { + /* Set up for the wait BEFORE starting the transfer */ + + ret = at32_chan_waitsetup(priv, chan); + if (ret < 0) + { + usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0); + return (ssize_t)ret; + } + + /* Set up for the transfer based on the direction and the endpoint */ + + ret = at32_in_setup(priv, chidx); + if (ret < 0) + { + uerr("ERROR: at32_in_setup failed: %d\n", ret); + return (ssize_t)ret; + } + + /* Wait for the transfer to complete and get the result */ + + ret = at32_chan_wait(priv, chan); + + /* EAGAIN indicates that the device NAKed the transfer. */ + + if (ret < 0) + { + /* The transfer failed. If we received a NAK, return all data + * buffered so far (if any). + */ + + if (ret == -EAGAIN) + { + /* Was data buffered prior to the NAK? */ + + if (xfrd > 0) + { + /* Yes, return the amount of data received. + * + * REVISIT: This behavior is clearly correct for CDC/ACM + * bulk transfers and HID interrupt transfers. But I am + * not so certain for MSC bulk transfers which, I think, + * could have NAKed packets in the middle of a transfer. + */ + + return xfrd; + } + else + { + useconds_t delay; + + /* Get the elapsed time. Has the timeout elapsed? + * if not then try again. + */ + + clock_t elapsed = clock_systime_ticks() - start; + if (elapsed >= AT32_DATANAK_DELAY) + { + /* Timeout out... break out returning the NAK as + * as a failure. + */ + + return (ssize_t)ret; + } + + /* Wait a bit before retrying after a NAK. */ + + if (chan->eptype == OTGFS_EPTYPE_INTR) + { + /* For interrupt (and isochronous) endpoints, the + * polling rate is determined by the bInterval field + * of the endpoint descriptor (in units of frames + * which we treat as milliseconds here). + */ + + if (chan->interval > 0) + { + /* Convert the delay to units of microseconds */ + + delay = (useconds_t)chan->interval * 1000; + } + else + { + /* Out of range! For interrupt endpoints, the valid + * range is 1-255 frames. Assume one frame. + */ + + delay = 1000; + } + } + else + { + /* For Isochronous endpoints, bInterval must be 1. + * Bulk endpoints do not have a polling interval. + * Rather, the should wait until data is received. + * + * REVISIT: For bulk endpoints this 1 msec delay is + * only intended to give the CPU a break from the bulk + * EP tight polling loop. But are there performance + * issues? + */ + + delay = 1000; + } + + /* Wait for the next polling interval. For interrupt and + * isochronous endpoints, this is necessary to assure the + * polling interval. It is used in other cases only to + * prevent the polling from consuming too much CPU + * bandwidth. + * + * Small delays could require more resolution than is + * provided by the system timer. For example, if the + * system timer resolution is 10MS, then + * nxsig_usleep(1000) will actually request a delay 20MS + * (due to both quantization and rounding). + * + * REVISIT: So which is better? To ignore tiny delays and + * hog the system bandwidth? Or to wait for an excessive + * amount and destroy system throughput? + */ + + if (delay > CONFIG_USEC_PER_TICK) + { + nxsig_usleep(delay - CONFIG_USEC_PER_TICK); + } + } + } + else + { + /* Some unexpected, fatal error occurred. */ + + usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret); + + /* Break out and return the error */ + + uerr("ERROR: at32_chan_wait failed: %d\n", ret); + return (ssize_t)ret; + } + } + else + { + /* Successfully received another chunk of data... add that to the + * running total. Then continue reading until we read 'buflen' + * bytes of data or until the devices NAKs (implying a short + * packet). + */ + + xfrd += chan->xfrd; + } + } + + return xfrd; +} + +/**************************************************************************** + * Name: at32_in_next + * + * Description: + * Initiate the next of a sequence of asynchronous transfers. + * + * Assumptions: + * This function is always called from an interrupt handler + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST_ASYNCH +static void at32_in_next(struct at32_usbhost_s *priv, + struct at32_chan_s *chan) +{ + usbhost_asynch_t callback; + void *arg; + ssize_t nbytes; + int result; + int ret; + + /* Is the full transfer complete? Did the last chunk transfer OK? */ + + result = -(int)chan->result; + if (chan->xfrd < chan->buflen && result == OK) + { + /* Yes.. Set up for the next transfer based on the direction and the + * endpoint type + */ + + ret = at32_in_setup(priv, chan->chidx); + if (ret >= 0) + { + return; + } + + uerr("ERROR: at32_in_setup failed: %d\n", ret); + result = ret; + } + + /* The transfer is complete, with or without an error */ + + uinfo("Transfer complete: %d\n", result); + + /* Extract the callback information */ + + callback = chan->callback; + arg = chan->arg; + nbytes = chan->xfrd; + + chan->callback = NULL; + chan->arg = NULL; + chan->xfrd = 0; + + /* Then perform the callback */ + + if (result < 0) + { + nbytes = (ssize_t)result; + } + + callback(arg, nbytes); +} +#endif + +/**************************************************************************** + * Name: at32_in_asynch + * + * Description: + * Initiate the first of a sequence of asynchronous transfers. + * + * Assumptions: + * This function is never called from an interrupt handler + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST_ASYNCH +static int at32_in_asynch(struct at32_usbhost_s *priv, int chidx, + uint8_t *buffer, size_t buflen, + usbhost_asynch_t callback, void *arg) +{ + struct at32_chan_s *chan; + int ret; + + /* Set up for the transfer BEFORE starting the first transfer */ + + chan = &priv->chan[chidx]; + chan->buffer = buffer; + chan->buflen = buflen; + chan->xfrd = 0; + + ret = at32_chan_asynchsetup(priv, chan, callback, arg); + if (ret < 0) + { + uerr("ERROR: at32_chan_asynchsetup failed: %d\n", ret); + return ret; + } + + /* Set up for the transfer based on the direction and the endpoint type */ + + ret = at32_in_setup(priv, chidx); + if (ret < 0) + { + uerr("ERROR: at32_in_setup failed: %d\n", ret); + } + + /* And return with the transfer pending */ + + return ret; +} +#endif + +/**************************************************************************** + * Name: at32_out_setup + * + * Description: + * Initiate an OUT transfer on an bulk, interrupt, or isochronous pipe. + * + ****************************************************************************/ + +static int at32_out_setup(struct at32_usbhost_s *priv, int chidx) +{ + struct at32_chan_s *chan; + + /* Set up for the transfer based on the direction and the endpoint type */ + + chan = &priv->chan[chidx]; + switch (chan->eptype) + { + default: + case OTGFS_EPTYPE_CTRL: /* Control */ + { + /* This kind of transfer on control endpoints other than EP0 are not + * currently supported + */ + + return -ENOSYS; + } + + case OTGFS_EPTYPE_ISOC: /* Isochronous */ + { + /* Set up the OUT data PID */ + + usbhost_vtrace2(OTGFS_VTRACE2_ISOCOUT, chidx, chan->buflen); + chan->pid = OTGFS_PID_DATA0; + } + break; + + case OTGFS_EPTYPE_BULK: /* Bulk */ + { + /* Setup the OUT data PID */ + + usbhost_vtrace2(OTGFS_VTRACE2_BULKOUT, chidx, chan->buflen); + chan->pid = chan->outdata1 ? OTGFS_PID_DATA1 : OTGFS_PID_DATA0; + } + break; + + case OTGFS_EPTYPE_INTR: /* Interrupt */ + { + /* Setup the OUT data PID */ + + usbhost_vtrace2(OTGFS_VTRACE2_INTROUT, chidx, chan->buflen); + chan->pid = chan->outdata1 ? OTGFS_PID_DATA1 : OTGFS_PID_DATA0; + + /* Toggle the OUT data PID for the next transfer */ + + chan->outdata1 ^= true; + } + break; + } + + /* Start the transfer */ + + at32_transfer_start(priv, chidx); + return OK; +} + +/**************************************************************************** + * Name: at32_out_transfer + * + * Description: + * Transfer the 'buflen' bytes in 'buffer' through an OUT channel. + * + ****************************************************************************/ + +static ssize_t at32_out_transfer(struct at32_usbhost_s *priv, + int chidx, uint8_t *buffer, + size_t buflen) +{ + struct at32_chan_s *chan; + clock_t start; + clock_t elapsed; + size_t xfrlen; + ssize_t xfrd; + int ret; + bool zlp; + + /* Loop until the transfer completes (i.e., buflen is decremented to zero) + * or a fatal error occurs (any error other than a simple NAK) + */ + + chan = &priv->chan[chidx]; + start = clock_systime_ticks(); + xfrd = 0; + zlp = (buflen == 0); + + while (buflen > 0 || zlp) + { + /* Transfer one packet at a time. The hardware is capable of queueing + * multiple OUT packets, but I just haven't figured out how to handle + * the case where a single OUT packet in the group is NAKed. + */ + + xfrlen = MIN(chan->maxpacket, buflen); + chan->buffer = buffer; + chan->buflen = xfrlen; + chan->xfrd = 0; + + /* Set up for the wait BEFORE starting the transfer */ + + ret = at32_chan_waitsetup(priv, chan); + if (ret < 0) + { + usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0); + return (ssize_t)ret; + } + + /* Set up for the transfer based on the direction and the endpoint */ + + ret = at32_out_setup(priv, chidx); + if (ret < 0) + { + uerr("ERROR: at32_out_setup failed: %d\n", ret); + return (ssize_t)ret; + } + + /* Wait for the transfer to complete and get the result */ + + ret = at32_chan_wait(priv, chan); + + /* Handle transfer failures */ + + if (ret < 0) + { + usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret); + + /* Check for a special case: If (1) the transfer was NAKed and (2) + * no Tx FIFO empty or Rx FIFO not-empty event occurred, then we + * should be able to just flush the Rx and Tx FIFOs and try again. + * We can detect this latter case because then the transfer buffer + * pointer and buffer size will be unaltered. + */ + + elapsed = clock_systime_ticks() - start; + if (ret != -EAGAIN || /* Not a NAK condition OR */ + elapsed >= AT32_DATANAK_DELAY || /* Timeout has elapsed OR */ + chan->xfrd > 0) /* Data has been partially transferred */ + { + /* Break out and return the error */ + + uerr("ERROR: at32_chan_wait failed: %d\n", ret); + return (ssize_t)ret; + } + + /* Is this flush really necessary? What does the hardware do with + * the data in the FIFO when the NAK occurs? Does it discard it? + */ + + at32_flush_txfifos(OTGFS_GRSTCTL_TXFNUM_HALL); + + /* Get the device a little time to catch up. Then retry the + * transfer using the same buffer pointer and length. + */ + + nxsig_usleep(5 * 1000); + } + else + { + /* Successfully transferred. Update the buffer pointer/length */ + + buffer += xfrlen; + buflen -= xfrlen; + xfrd += chan->xfrd; + zlp = false; + } + } + + return xfrd; +} + +/**************************************************************************** + * Name: at32_out_next + * + * Description: + * Initiate the next of a sequence of asynchronous transfers. + * + * Assumptions: + * This function is always called from an interrupt handler + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST_ASYNCH +static void at32_out_next(struct at32_usbhost_s *priv, + struct at32_chan_s *chan) +{ + usbhost_asynch_t callback; + void *arg; + ssize_t nbytes; + int result; + int ret; + + /* Is the full transfer complete? Did the last chunk transfer OK? */ + + result = -(int)chan->result; + if (chan->xfrd < chan->buflen && result == OK) + { + /* Yes.. Set up for the next transfer based on the direction and the + * endpoint type + */ + + ret = at32_out_setup(priv, chan->chidx); + if (ret >= 0) + { + return; + } + + uerr("ERROR: at32_out_setup failed: %d\n", ret); + result = ret; + } + + /* The transfer is complete, with or without an error */ + + uinfo("Transfer complete: %d\n", result); + + /* Extract the callback information */ + + callback = chan->callback; + arg = chan->arg; + nbytes = chan->xfrd; + + chan->callback = NULL; + chan->arg = NULL; + chan->xfrd = 0; + + /* Then perform the callback */ + + if (result < 0) + { + nbytes = (ssize_t)result; + } + + callback(arg, nbytes); +} +#endif + +/**************************************************************************** + * Name: at32_out_asynch + * + * Description: + * Initiate the first of a sequence of asynchronous transfers. + * + * Assumptions: + * This function is never called from an interrupt handler + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST_ASYNCH +static int at32_out_asynch(struct at32_usbhost_s *priv, int chidx, + uint8_t *buffer, size_t buflen, + usbhost_asynch_t callback, void *arg) +{ + struct at32_chan_s *chan; + int ret; + + /* Set up for the transfer BEFORE starting the first transfer */ + + chan = &priv->chan[chidx]; + chan->buffer = buffer; + chan->buflen = buflen; + chan->xfrd = 0; + + ret = at32_chan_asynchsetup(priv, chan, callback, arg); + if (ret < 0) + { + uerr("ERROR: at32_chan_asynchsetup failed: %d\n", ret); + return ret; + } + + /* Set up for the transfer based on the direction and the endpoint type */ + + ret = at32_out_setup(priv, chidx); + if (ret < 0) + { + uerr("ERROR: at32_out_setup failed: %d\n", ret); + } + + /* And return with the transfer pending */ + + return ret; +} +#endif + +/**************************************************************************** + * Name: at32_gint_wrpacket + * + * Description: + * Transfer the 'buflen' bytes in 'buffer' to the Tx FIFO associated with + * 'chidx' (non-DMA). + * + ****************************************************************************/ + +static void at32_gint_wrpacket(struct at32_usbhost_s *priv, + uint8_t *buffer, int chidx, int buflen) +{ + uint32_t *src; + uint32_t fifo; + int buflen32; + + at32_pktdump("Sending", buffer, buflen); + + /* Get the number of 32-byte words associated with this byte size */ + + buflen32 = (buflen + 3) >> 2; + + /* Get the address of the Tx FIFO associated with this channel */ + + fifo = AT32_OTGFS_DFIFO_HCH(chidx); + + /* Transfer all of the data into the Tx FIFO */ + + src = (uint32_t *)buffer; + for (; buflen32 > 0; buflen32--) + { + uint32_t data = *src++; + at32_putreg(fifo, data); + } + + /* Increment the count of bytes "in-flight" in the Tx FIFO */ + + priv->chan[chidx].inflight += buflen; +} + +/**************************************************************************** + * Name: at32_gint_hcinisr + * + * Description: + * USB OTG FS host IN channels interrupt handler + * + * One the completion of the transfer, the channel result byte may be set + * as follows: + * + * OK - Transfer completed successfully + * EAGAIN - If devices NAKs the transfer or NYET occurs + * EPERM - If the endpoint stalls + * EIO - On a TX or data toggle error + * EPIPE - Frame overrun + * + * EBUSY in the result field indicates that the transfer has not completed. + * + ****************************************************************************/ + +static inline void at32_gint_hcinisr(struct at32_usbhost_s *priv, + int chidx) +{ + struct at32_chan_s *chan = &priv->chan[chidx]; + uint32_t regval; + uint32_t pending; + + /* Read the HCINT register to get the pending HC interrupts. Read the + * HCINTMSK register to get the set of enabled HC interrupts. + */ + + pending = at32_getreg(AT32_OTGFS_HCINT(chidx)); + regval = at32_getreg(AT32_OTGFS_HCINTMSK(chidx)); + + /* AND the two to get the set of enabled, pending HC interrupts */ + + pending &= regval; + uinfo("HCINTMSK%d: %08" PRIx32 " pending: %08" PRIx32 "\n", + chidx, regval, pending); + + /* Check for a pending ACK response received/transmitted interrupt */ + + if ((pending & OTGFS_HCINT_ACK) != 0) + { + /* Clear the pending the ACK response received/transmitted interrupt */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_ACK); + } + + /* Check for a pending STALL response receive (STALL) interrupt */ + + else if ((pending & OTGFS_HCINT_STALL) != 0) + { + /* Clear the NAK and STALL Conditions. */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), + OTGFS_HCINT_NAK | OTGFS_HCINT_STALL); + + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ + + at32_chan_halt(priv, chidx, CHREASON_STALL); + + /* When there is a STALL, clear any pending NAK so that it is not + * processed below. + */ + + pending &= ~OTGFS_HCINT_NAK; + } + + /* Check for a pending Data Toggle ERRor (DTERR) interrupt */ + + else if ((pending & OTGFS_HCINT_DTERR) != 0) + { + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ + + at32_chan_halt(priv, chidx, CHREASON_DTERR); + + /* Clear the NAK and data toggle error conditions */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), + OTGFS_HCINT_NAK | OTGFS_HCINT_DTERR); + } + + /* Check for a pending FRaMe OverRun (FRMOR) interrupt */ + + if ((pending & OTGFS_HCINT_FRMOR) != 0) + { + /* Halt the channel -- the CHH interrupt is expected next */ + + at32_chan_halt(priv, chidx, CHREASON_FRMOR); + + /* Clear the FRaMe OverRun (FRMOR) condition */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_FRMOR); + } + + /* Check for a pending TransFeR Completed (XFRC) interrupt */ + + else if ((pending & OTGFS_HCINT_XFRC) != 0) + { + /* Clear the TransFeR Completed (XFRC) condition */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_XFRC); + + /* Then handle the transfer completion event based on the endpoint */ + + if (chan->eptype == OTGFS_EPTYPE_CTRL || + chan->eptype == OTGFS_EPTYPE_BULK) + { + /* Halt the channel -- the CHH interrupt is expected next */ + + at32_chan_halt(priv, chidx, CHREASON_XFRC); + + /* Clear any pending NAK condition. The 'indata1' data toggle + * should have been appropriately updated by the RxFIFO + * logic as each packet was received. + */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_NAK); + } + else if (chan->eptype == OTGFS_EPTYPE_INTR) + { + /* Force the next transfer on an ODD frame */ + + regval = at32_getreg(AT32_OTGFS_HCCHAR(chidx)); + regval |= OTGFS_HCCHAR_ODDFRM; + at32_putreg(AT32_OTGFS_HCCHAR(chidx), regval); + + /* Set the request done state */ + + chan->result = OK; + } + } + + /* Check for a pending CHannel Halted (CHH) interrupt */ + + else if ((pending & OTGFS_HCINT_CHH) != 0) + { + /* Mask the CHannel Halted (CHH) interrupt */ + + regval = at32_getreg(AT32_OTGFS_HCINTMSK(chidx)); + regval &= ~OTGFS_HCINT_CHH; + at32_putreg(AT32_OTGFS_HCINTMSK(chidx), regval); + + /* Update the request state based on the host state machine state */ + + if (chan->chreason == CHREASON_XFRC) + { + /* Set the request done result */ + + chan->result = OK; + } + else if (chan->chreason == CHREASON_STALL) + { + /* Set the request stall result */ + + chan->result = EPERM; + } + else if ((chan->chreason == CHREASON_TXERR) || + (chan->chreason == CHREASON_DTERR)) + { + /* Set the request I/O error result */ + + chan->result = EIO; + } + else if (chan->chreason == CHREASON_NAK) + { + /* Set the NAK error result */ + + chan->result = EAGAIN; + } + else /* if (chan->chreason == CHREASON_FRMOR) */ + { + /* Set the frame overrun error result */ + + chan->result = EPIPE; + } + + /* Clear the CHannel Halted (CHH) condition */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_CHH); + } + + /* Check for a pending Transaction ERror (TXERR) interrupt */ + + else if ((pending & OTGFS_HCINT_TXERR) != 0) + { + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ + + at32_chan_halt(priv, chidx, CHREASON_TXERR); + + /* Clear the Transaction ERror (TXERR) condition */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_TXERR); + } + + /* Check for a pending NAK response received (NAK) interrupt */ + + else if ((pending & OTGFS_HCINT_NAK) != 0) + { + /* For a BULK transfer, the hardware is capable of retrying + * automatically on a NAK. However, this is not always + * what we need to do. So we always halt the transfer and + * return control to high level logic in the event of a NAK. + */ + +#if 1 + /* Halt the interrupt channel */ + + if (chan->eptype == OTGFS_EPTYPE_INTR || + chan->eptype == OTGFS_EPTYPE_BULK) + { + /* Halt the channel -- the CHH interrupt is expected next */ + + at32_chan_halt(priv, chidx, CHREASON_NAK); + } + + /* Re-activate CTRL and BULK channels. + * + * REVISIT: This can cause a lot of interrupts! + * REVISIT: BULK endpoints are not re-activated. + */ + + else if (chan->eptype == OTGFS_EPTYPE_CTRL) + { + /* Re-activate the channel by clearing CHDIS and assuring that + * CHENA is set + * + * TODO: set channel reason to NACK? + */ + + regval = at32_getreg(AT32_OTGFS_HCCHAR(chidx)); + regval |= OTGFS_HCCHAR_CHENA; + regval &= ~OTGFS_HCCHAR_CHDIS; + at32_putreg(AT32_OTGFS_HCCHAR(chidx), regval); + } + +#else + /* Halt all transfers on the NAK -- CHH interrupt is expected next */ + + at32_chan_halt(priv, chidx, CHREASON_NAK); +#endif + + /* Clear the NAK condition */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_NAK); + } + + /* Check for a transfer complete event */ + + at32_chan_wakeup(priv, chan); +} + +/**************************************************************************** + * Name: at32_gint_hcoutisr + * + * Description: + * USB OTG FS host OUT channels interrupt handler + * + * One the completion of the transfer, the channel result byte may be set + * as follows: + * + * OK - Transfer completed successfully + * EAGAIN - If devices NAKs the transfer or NYET occurs + * EPERM - If the endpoint stalls + * EIO - On a TX or data toggle error + * EPIPE - Frame overrun + * + * EBUSY in the result field indicates that the transfer has not completed. + * + ****************************************************************************/ + +static inline void at32_gint_hcoutisr(struct at32_usbhost_s *priv, + int chidx) +{ + struct at32_chan_s *chan = &priv->chan[chidx]; + uint32_t regval; + uint32_t pending; + + /* Read the HCINT register to get the pending HC interrupts. Read the + * HCINTMSK register to get the set of enabled HC interrupts. + */ + + pending = at32_getreg(AT32_OTGFS_HCINT(chidx)); + regval = at32_getreg(AT32_OTGFS_HCINTMSK(chidx)); + + /* AND the two to get the set of enabled, pending HC interrupts */ + + pending &= regval; + uinfo("HCINTMSK%d: %08" PRIx32 " pending: %08" PRIx32 "\n", + chidx, regval, pending); + + /* Check for a pending ACK response received/transmitted interrupt */ + + if ((pending & OTGFS_HCINT_ACK) != 0) + { + /* Clear the pending the ACK response received/transmitted interrupt */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_ACK); + } + + /* Check for a pending FRaMe OverRun (FRMOR) interrupt */ + + else if ((pending & OTGFS_HCINT_FRMOR) != 0) + { + /* Halt the channel (probably not necessary for FRMOR) */ + + at32_chan_halt(priv, chidx, CHREASON_FRMOR); + + /* Clear the pending the FRaMe OverRun (FRMOR) interrupt */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_FRMOR); + } + + /* Check for a pending TransFeR Completed (XFRC) interrupt */ + + else if ((pending & OTGFS_HCINT_XFRC) != 0) + { + /* Decrement the number of bytes remaining by the number of + * bytes that were "in-flight". + */ + + priv->chan[chidx].buffer += priv->chan[chidx].inflight; + priv->chan[chidx].xfrd += priv->chan[chidx].inflight; + priv->chan[chidx].inflight = 0; + + /* Halt the channel -- the CHH interrupt is expected next */ + + at32_chan_halt(priv, chidx, CHREASON_XFRC); + + /* Clear the pending the TransFeR Completed (XFRC) interrupt */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_XFRC); + } + + /* Check for a pending STALL response receive (STALL) interrupt */ + + else if ((pending & OTGFS_HCINT_STALL) != 0) + { + /* Clear the pending the STALL response receiv (STALL) interrupt */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_STALL); + + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ + + at32_chan_halt(priv, chidx, CHREASON_STALL); + } + + /* Check for a pending NAK response received (NAK) interrupt */ + + else if ((pending & OTGFS_HCINT_NAK) != 0) + { + /* Halt the channel -- the CHH interrupt is expected next */ + + at32_chan_halt(priv, chidx, CHREASON_NAK); + + /* Clear the pending the NAK response received (NAK) interrupt */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_NAK); + } + + /* Check for a pending Transaction ERror (TXERR) interrupt */ + + else if ((pending & OTGFS_HCINT_TXERR) != 0) + { + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ + + at32_chan_halt(priv, chidx, CHREASON_TXERR); + + /* Clear the pending the Transaction ERror (TXERR) interrupt */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_TXERR); + } + + /* Check for a NYET interrupt */ + +#if 0 /* NYET is a reserved bit in the HCINT register */ + else if ((pending & OTGFS_HCINT_NYET) != 0) + { + /* Halt the channel */ + + at32_chan_halt(priv, chidx, CHREASON_NYET); + + /* Clear the pending the NYET interrupt */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_NYET); + } +#endif + + /* Check for a pending Data Toggle ERRor (DTERR) interrupt */ + + else if (pending & OTGFS_HCINT_DTERR) + { + /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is + * received on the channel. + */ + + at32_chan_halt(priv, chidx, CHREASON_DTERR); + + /* Clear the pending the Data Toggle ERRor (DTERR) and NAK interrupts */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), + OTGFS_HCINT_DTERR | OTGFS_HCINT_NAK); + } + + /* Check for a pending CHannel Halted (CHH) interrupt */ + + else if ((pending & OTGFS_HCINT_CHH) != 0) + { + /* Mask the CHannel Halted (CHH) interrupt */ + + regval = at32_getreg(AT32_OTGFS_HCINTMSK(chidx)); + regval &= ~OTGFS_HCINT_CHH; + at32_putreg(AT32_OTGFS_HCINTMSK(chidx), regval); + + if (chan->chreason == CHREASON_XFRC) + { + /* Set the request done result */ + + chan->result = OK; + + /* Read the HCCHAR register to get the HCCHAR register to get + * the endpoint type. + */ + + regval = at32_getreg(AT32_OTGFS_HCCHAR(chidx)); + + /* Is it a bulk endpoint? Were an odd number of packets + * transferred? + */ + + if ((regval & OTGFS_HCCHAR_EPTYP_MASK) == + OTGFS_HCCHAR_EPTYP_BULK && + (chan->npackets & 1) != 0) + { + /* Yes to both... toggle the data out PID */ + + chan->outdata1 ^= true; + } + } + else if (chan->chreason == CHREASON_NAK || + chan->chreason == CHREASON_NYET) + { + /* Set the try again later result */ + + chan->result = EAGAIN; + } + else if (chan->chreason == CHREASON_STALL) + { + /* Set the request stall result */ + + chan->result = EPERM; + } + else if ((chan->chreason == CHREASON_TXERR) || + (chan->chreason == CHREASON_DTERR)) + { + /* Set the I/O failure result */ + + chan->result = EIO; + } + else /* if (chan->chreason == CHREASON_FRMOR) */ + { + /* Set the frame error result */ + + chan->result = EPIPE; + } + + /* Clear the pending the CHannel Halted (CHH) interrupt */ + + at32_putreg(AT32_OTGFS_HCINT(chidx), OTGFS_HCINT_CHH); + } + + /* Check for a transfer complete event */ + + at32_chan_wakeup(priv, chan); +} + +/**************************************************************************** + * Name: at32_gint_connected + * + * Description: + * Handle a connection event. + * + ****************************************************************************/ + +static void at32_gint_connected(struct at32_usbhost_s *priv) +{ + /* We we previously disconnected? */ + + if (!priv->connected) + { + /* Yes.. then now we are connected */ + + usbhost_vtrace1(OTGFS_VTRACE1_CONNECTED, 0); + priv->connected = true; + priv->change = true; + DEBUGASSERT(priv->smstate == SMSTATE_DETACHED); + + /* Notify any waiters */ + + priv->smstate = SMSTATE_ATTACHED; + if (priv->pscwait) + { + nxsem_post(&priv->pscsem); + priv->pscwait = false; + } + } +} + +/**************************************************************************** + * Name: at32_gint_disconnected + * + * Description: + * Handle a disconnection event. + * + ****************************************************************************/ + +static void at32_gint_disconnected(struct at32_usbhost_s *priv) +{ + /* Were we previously connected? */ + + if (priv->connected) + { + /* Yes.. then we no longer connected */ + + usbhost_vtrace1(OTGFS_VTRACE1_DISCONNECTED, 0); + + /* Are we bound to a class driver? */ + + if (priv->rhport.hport.devclass) + { + /* Yes.. Disconnect the class driver */ + + CLASS_DISCONNECTED(priv->rhport.hport.devclass); + priv->rhport.hport.devclass = NULL; + } + + /* Re-Initialize Host for new Enumeration */ + + priv->smstate = SMSTATE_DETACHED; + priv->connected = false; + priv->change = true; + at32_chan_freeall(priv); + + priv->rhport.hport.speed = USB_SPEED_FULL; + priv->rhport.hport.funcaddr = 0; + + /* Notify any waiters that there is a change in the connection state */ + + if (priv->pscwait) + { + nxsem_post(&priv->pscsem); + priv->pscwait = false; + } + } +} + +/**************************************************************************** + * Name: at32_gint_sofisr + * + * Description: + * USB OTG FS start-of-frame interrupt handler + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_OTGFS_SOFINTR +static inline void at32_gint_sofisr(struct at32_usbhost_s *priv) +{ + /* Handle SOF interrupt */ + +#warning "Do what?" + + /* Clear pending SOF interrupt */ + + at32_putreg(AT32_OTGFS_GINTSTS, OTGFS_GINT_SOF); +} +#endif + +/**************************************************************************** + * Name: at32_gint_rxflvlisr + * + * Description: + * USB OTG FS RxFIFO non-empty interrupt handler + * + ****************************************************************************/ + +static inline void at32_gint_rxflvlisr(struct at32_usbhost_s *priv) +{ + uint32_t *dest; + uint32_t grxsts; + uint32_t intmsk; + uint32_t hcchar; + uint32_t hctsiz; + uint32_t fifo; + int bcnt; + int bcnt32; + int chidx; + int i; + + /* Disable the RxFIFO non-empty interrupt */ + + intmsk = at32_getreg(AT32_OTGFS_GINTMSK); + intmsk &= ~OTGFS_GINT_RXFLVL; + at32_putreg(AT32_OTGFS_GINTMSK, intmsk); + + /* Read and pop the next status from the Rx FIFO */ + + grxsts = at32_getreg(AT32_OTGFS_GRXSTSP); + uinfo("GRXSTS: %08" PRIx32 "\n", grxsts); + + /* Isolate the channel number/index in the status word */ + + chidx = (grxsts & OTGFS_GRXSTSH_CHNUM_MASK) >> OTGFS_GRXSTSH_CHNUM_SHIFT; + + /* Get the host channel characteristics register (HCCHAR) */ + + hcchar = at32_getreg(AT32_OTGFS_HCCHAR(chidx)); + + /* Then process the interrupt according to the packet status */ + + switch (grxsts & OTGFS_GRXSTSH_PKTSTS_MASK) + { + case OTGFS_GRXSTSH_PKTSTS_INRECVD: /* IN data packet received */ + { + /* Read the data into the host buffer. */ + + bcnt = (grxsts & OTGFS_GRXSTSH_BCNT_MASK) >> + OTGFS_GRXSTSH_BCNT_SHIFT; + if (bcnt > 0 && priv->chan[chidx].buffer != NULL) + { + /* Transfer the packet from the Rx FIFO into the user buffer */ + + dest = (uint32_t *)priv->chan[chidx].buffer; + fifo = AT32_OTGFS_DFIFO_HCH(0); + bcnt32 = (bcnt + 3) >> 2; + + for (i = 0; i < bcnt32; i++) + { + *dest++ = at32_getreg(fifo); + } + + at32_pktdump("Received", priv->chan[chidx].buffer, bcnt); + + /* Toggle the IN data pid (Used by Bulk and INTR only) */ + + priv->chan[chidx].indata1 ^= true; + + /* Manage multiple packet transfers */ + + priv->chan[chidx].buffer += bcnt; + priv->chan[chidx].xfrd += bcnt; + + /* Check if more packets are expected */ + + hctsiz = at32_getreg(AT32_OTGFS_HCTSIZ(chidx)); + if ((hctsiz & OTGFS_HCTSIZ_PKTCNT_MASK) != 0) + { + /* Re-activate the channel when more packets are expected */ + + hcchar |= OTGFS_HCCHAR_CHENA; + hcchar &= ~OTGFS_HCCHAR_CHDIS; + at32_putreg(AT32_OTGFS_HCCHAR(chidx), hcchar); + } + } + } + break; + + case OTGFS_GRXSTSH_PKTSTS_INDONE: /* IN transfer completed */ + case OTGFS_GRXSTSH_PKTSTS_DTOGERR: /* Data toggle error */ + case OTGFS_GRXSTSH_PKTSTS_HALTED: /* Channel halted */ + default: + break; + } + + /* Re-enable the RxFIFO non-empty interrupt */ + + intmsk |= OTGFS_GINT_RXFLVL; + at32_putreg(AT32_OTGFS_GINTMSK, intmsk); +} + +/**************************************************************************** + * Name: at32_gint_nptxfeisr + * + * Description: + * USB OTG FS non-periodic TxFIFO empty interrupt handler + * + ****************************************************************************/ + +static inline void at32_gint_nptxfeisr(struct at32_usbhost_s *priv) +{ + struct at32_chan_s *chan; + uint32_t regval; + unsigned int wrsize; + unsigned int avail; + unsigned int chidx; + + /* Recover the index of the channel that is waiting for space in the Tx + * FIFO. + */ + + chidx = priv->chidx; + chan = &priv->chan[chidx]; + + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. + */ + + chan->buffer += chan->inflight; + chan->xfrd += chan->inflight; + chan->inflight = 0; + + /* If we have now transferred the entire buffer, then this transfer is + * complete (this case really should never happen because we disable + * the NPTXFE interrupt on the final packet). + */ + + if (chan->xfrd >= chan->buflen) + { + /* Disable further Tx FIFO empty interrupts and bail. */ + + at32_modifyreg(AT32_OTGFS_GINTMSK, OTGFS_GINT_NPTXFE, 0); + return; + } + + /* Read the status from the top of the non-periodic TxFIFO */ + + regval = at32_getreg(AT32_OTGFS_HNPTXSTS); + + /* Extract the number of bytes available in the non-periodic Tx FIFO. */ + + avail = ((regval & OTGFS_HNPTXSTS_NPTXFSAV_MASK) >> + OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) << 2; + + /* Get the size to put in the Tx FIFO now */ + + wrsize = chan->buflen - chan->xfrd; + + /* Get minimal size packet that can be sent. Something is seriously + * configured wrong if one packet will not fit into the empty Tx FIFO. + */ + + DEBUGASSERT(wrsize > 0 && avail >= MIN(wrsize, chan->maxpacket)); + if (wrsize > avail) + { + /* Clip the write size to the number of full, max sized packets + * that will fit in the Tx FIFO. + */ + + unsigned int wrpackets = avail / chan->maxpacket; + wrsize = wrpackets * chan->maxpacket; + } + + /* Otherwise, this will be the last packet to be sent in this transaction. + * We now need to disable further NPTXFE interrupts. + */ + + else + { + at32_modifyreg(AT32_OTGFS_GINTMSK, OTGFS_GINT_NPTXFE, 0); + } + + /* Write the next group of packets into the Tx FIFO */ + + uinfo("HNPTXSTS: %08" PRIx32 " chidx: %d avail: %d buflen: %d xfrd: %d " + "wrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); + + at32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); +} + +/**************************************************************************** + * Name: at32_gint_ptxfeisr + * + * Description: + * USB OTG FS periodic TxFIFO empty interrupt handler + * + ****************************************************************************/ + +static inline void at32_gint_ptxfeisr(struct at32_usbhost_s *priv) +{ + struct at32_chan_s *chan; + uint32_t regval; + unsigned int wrsize; + unsigned int avail; + unsigned int chidx; + + /* Recover the index of the channel that is waiting for space in the Tx + * FIFO. + */ + + chidx = priv->chidx; + chan = &priv->chan[chidx]; + + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. + */ + + chan->buffer += chan->inflight; + chan->xfrd += chan->inflight; + chan->inflight = 0; + + /* If we have now transferred the entire buffer, then this transfer is + * complete (this case really should never happen because we disable + * the PTXFE interrupt on the final packet). + */ + + if (chan->xfrd >= chan->buflen) + { + /* Disable further Tx FIFO empty interrupts and bail. */ + + at32_modifyreg(AT32_OTGFS_GINTMSK, OTGFS_GINT_PTXFE, 0); + return; + } + + /* Read the status from the top of the periodic TxFIFO */ + + regval = at32_getreg(AT32_OTGFS_HPTXSTS); + + /* Extract the number of bytes available in the periodic Tx FIFO. */ + + avail = ((regval & OTGFS_HPTXSTS_PTXFSAVL_MASK) >> + OTGFS_HPTXSTS_PTXFSAVL_SHIFT) << 2; + + /* Get the size to put in the Tx FIFO now */ + + wrsize = chan->buflen - chan->xfrd; + + /* Get minimal size packet that can be sent. Something is seriously + * configured wrong if one packet will not fit into the empty Tx FIFO. + */ + + DEBUGASSERT(wrsize && avail >= MIN(wrsize, chan->maxpacket)); + if (wrsize > avail) + { + /* Clip the write size to the number of full, max sized packets + * that will fit in the Tx FIFO. + */ + + unsigned int wrpackets = avail / chan->maxpacket; + wrsize = wrpackets * chan->maxpacket; + } + + /* Otherwise, this will be the last packet to be sent in this transaction. + * We now need to disable further PTXFE interrupts. + */ + + else + { + at32_modifyreg(AT32_OTGFS_GINTMSK, OTGFS_GINT_PTXFE, 0); + } + + /* Write the next group of packets into the Tx FIFO */ + + uinfo("HPTXSTS: %08" PRIx32 + " chidx: %d avail: %d buflen: %d xfrd: %d wrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); + + at32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); +} + +/**************************************************************************** + * Name: at32_gint_hcisr + * + * Description: + * USB OTG FS host channels interrupt handler + * + ****************************************************************************/ + +static inline void at32_gint_hcisr(struct at32_usbhost_s *priv) +{ + uint32_t haint; + uint32_t hcchar; + int i = 0; + + /* Read the Host all channels interrupt register and test each bit in the + * register. Each bit i, i=0...(AT32_NHOST_CHANNELS-1), corresponds to + * a pending interrupt on channel i. + */ + + haint = at32_getreg(AT32_OTGFS_HAINT); + for (i = 0; i < AT32_NHOST_CHANNELS; i++) + { + /* Is an interrupt pending on this channel? */ + + if ((haint & OTGFS_HAINT(i)) != 0) + { + /* Yes... read the HCCHAR register to get the direction bit */ + + hcchar = at32_getreg(AT32_OTGFS_HCCHAR(i)); + + /* Was this an interrupt on an IN or an OUT channel? */ + + if ((hcchar & OTGFS_HCCHAR_EPDIR) != 0) + { + /* Handle the HC IN channel interrupt */ + + at32_gint_hcinisr(priv, i); + } + else + { + /* Handle the HC OUT channel interrupt */ + + at32_gint_hcoutisr(priv, i); + } + } + } +} + +/**************************************************************************** + * Name: at32_gint_hprtisr + * + * Description: + * USB OTG FS host port interrupt handler + * + ****************************************************************************/ + +static inline void at32_gint_hprtisr(struct at32_usbhost_s *priv) +{ + uint32_t hprt; + uint32_t newhprt; + uint32_t hcfg; + + usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT, 0); + + /* Read the port status and control register (HPRT) */ + + hprt = at32_getreg(AT32_OTGFS_HPRT); + + /* Setup to clear the interrupt bits in GINTSTS by setting the + * corresponding bits in the HPRT. The HCINT interrupt bit is cleared + * when the appropriate status bits in the HPRT register are cleared. + */ + + newhprt = hprt & ~(OTGFS_HPRT_PENA | OTGFS_HPRT_PCDET | + OTGFS_HPRT_PENCHNG | OTGFS_HPRT_POCCHNG); + + /* Check for Port Over-urrent CHaNGe (POCCHNG) */ + + if ((hprt & OTGFS_HPRT_POCCHNG) != 0) + { + /* Set up to clear the POCCHNG status in the new HPRT contents. */ + + usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_POCCHNG, 0); + newhprt |= OTGFS_HPRT_POCCHNG; + } + + /* Check for Port Connect DETected (PCDET). The core sets this bit when a + * device connection is detected. + */ + + if ((hprt & OTGFS_HPRT_PCDET) != 0) + { + /* Set up to clear the PCDET status in the new HPRT contents. Then + * process the new connection event. + */ + + usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_PCDET, 0); + newhprt |= OTGFS_HPRT_PCDET; + at32_portreset(priv); + at32_gint_connected(priv); + } + + /* Check for Port Enable CHaNGed (PENCHNG) */ + + if ((hprt & OTGFS_HPRT_PENCHNG) != 0) + { + /* Set up to clear the PENCHNG status in the new HPRT contents. */ + + usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_PENCHNG, 0); + newhprt |= OTGFS_HPRT_PENCHNG; + + /* Was the port enabled? */ + + if ((hprt & OTGFS_HPRT_PENA) != 0) + { + /* Yes.. handle the new connection event */ + + at32_gint_connected(priv); + + /* Check the Host ConFiGuration register (HCFG) */ + + hcfg = at32_getreg(AT32_OTGFS_HCFG); + + /* Is this a low speed or full speed connection (OTG FS does not + * support high speed) + */ + + if ((hprt & OTGFS_HPRT_PSPD_MASK) == OTGFS_HPRT_PSPD_LS) + { + /* Set the Host Frame Interval Register for the 6KHz speed */ + + usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_LSDEV, 0); + at32_putreg(AT32_OTGFS_HFIR, 6000); + + /* Are we switching from FS to LS? */ + + if ((hcfg & OTGFS_HCFG_FSLSPCS_MASK) != + OTGFS_HCFG_FSLSPCS_LS6MHz) + { + usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_FSLSSW, 0); + + /* Yes... configure for LS */ + + hcfg &= ~OTGFS_HCFG_FSLSPCS_MASK; + hcfg |= OTGFS_HCFG_FSLSPCS_LS6MHz; + at32_putreg(AT32_OTGFS_HCFG, hcfg); + + /* And reset the port */ + + at32_portreset(priv); + } + } + else /* if ((hprt & OTGFS_HPRT_PSPD_MASK) == OTGFS_HPRT_PSPD_FS) */ + { + usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_FSDEV, 0); + at32_putreg(AT32_OTGFS_HFIR, 48000); + + /* Are we switching from LS to FS? */ + + if ((hcfg & OTGFS_HCFG_FSLSPCS_MASK) != + OTGFS_HCFG_FSLSPCS_FS48MHz) + { + usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_LSFSSW, 0); + + /* Yes... configure for FS */ + + hcfg &= ~OTGFS_HCFG_FSLSPCS_MASK; + hcfg |= OTGFS_HCFG_FSLSPCS_FS48MHz; + at32_putreg(AT32_OTGFS_HCFG, hcfg); + + /* And reset the port */ + + at32_portreset(priv); + } + } + } + } + + /* Clear port interrupts by setting bits in the HPRT */ + + at32_putreg(AT32_OTGFS_HPRT, newhprt); +} + +/**************************************************************************** + * Name: at32_gint_discisr + * + * Description: + * USB OTG FS disconnect detected interrupt handler + * + ****************************************************************************/ + +static inline void at32_gint_discisr(struct at32_usbhost_s *priv) +{ + /* Handle the disconnection event */ + + at32_gint_disconnected(priv); + + /* Clear the dicsonnect interrupt */ + + at32_putreg(AT32_OTGFS_GINTSTS, OTGFS_GINT_DISC); +} + +/**************************************************************************** + * Name: at32_gint_ipxfrisr + * + * Description: + * USB OTG FS incomplete periodic interrupt handler + * + ****************************************************************************/ + +static inline void at32_gint_ipxfrisr(struct at32_usbhost_s *priv) +{ + uint32_t regval; + + /* CHENA : Set to enable the channel + * CHDIS : Set to stop transmitting/receiving data on a channel + */ + + regval = at32_getreg(AT32_OTGFS_HCCHAR(0)); + regval |= (OTGFS_HCCHAR_CHDIS | OTGFS_HCCHAR_CHENA); + at32_putreg(AT32_OTGFS_HCCHAR(0), regval); + + /* Clear the incomplete isochronous OUT interrupt */ + + at32_putreg(AT32_OTGFS_GINTSTS, OTGFS_GINT_IPXFR); +} + +/**************************************************************************** + * Name: at32_gint_isr + * + * Description: + * USB OTG FS global interrupt handler + * + ****************************************************************************/ + +static int at32_gint_isr(int irq, void *context, void *arg) +{ + /* At present, there is only support for a single OTG FS host. Hence it is + * pre-allocated as g_usbhost. However, in most code, the private data + * structure will be referenced using the 'priv' pointer (rather than the + * global data) in order to simplify any future support for multiple + * devices. + */ + + struct at32_usbhost_s *priv = &g_usbhost; + uint32_t pending; + + /* If OTG were supported, we would need to check if we are in host or + * device mode when the global interrupt occurs. Here we support only + * host mode + */ + + /* Loop while there are pending interrupts to process. This loop may save + * a little interrupt handling overhead. + */ + + for (; ; ) + { + /* Get the unmasked bits in the GINT status */ + + pending = at32_getreg(AT32_OTGFS_GINTSTS); + pending &= at32_getreg(AT32_OTGFS_GINTMSK); + + /* Return from the interrupt when there are no further pending + * interrupts. + */ + + if (pending == 0) + { + return OK; + } + + /* Otherwise, process each pending, unmasked GINT interrupts */ + + /* Handle the start of frame interrupt */ + +#ifdef CONFIG_AT32_OTGFS_SOFINTR + if ((pending & OTGFS_GINT_SOF) != 0) + { + usbhost_vtrace1(OTGFS_VTRACE1_GINT_SOF, 0); + at32_gint_sofisr(priv); + } +#endif + + /* Handle the RxFIFO non-empty interrupt */ + + if ((pending & OTGFS_GINT_RXFLVL) != 0) + { + usbhost_vtrace1(OTGFS_VTRACE1_GINT_RXFLVL, 0); + at32_gint_rxflvlisr(priv); + } + + /* Handle the non-periodic TxFIFO empty interrupt */ + + if ((pending & OTGFS_GINT_NPTXFE) != 0) + { + usbhost_vtrace1(OTGFS_VTRACE1_GINT_NPTXFE, 0); + at32_gint_nptxfeisr(priv); + } + + /* Handle the periodic TxFIFO empty interrupt */ + + if ((pending & OTGFS_GINT_PTXFE) != 0) + { + usbhost_vtrace1(OTGFS_VTRACE1_GINT_PTXFE, 0); + at32_gint_ptxfeisr(priv); + } + + /* Handle the host channels interrupt */ + + if ((pending & OTGFS_GINT_HC) != 0) + { + usbhost_vtrace1(OTGFS_VTRACE1_GINT_HC, 0); + at32_gint_hcisr(priv); + } + + /* Handle the host port interrupt */ + + if ((pending & OTGFS_GINT_HPRT) != 0) + { + at32_gint_hprtisr(priv); + } + + /* Handle the disconnect detected interrupt */ + + if ((pending & OTGFS_GINT_DISC) != 0) + { + usbhost_vtrace1(OTGFS_VTRACE1_GINT_DISC, 0); + at32_gint_discisr(priv); + } + + /* Handle the incomplete periodic transfer */ + + if ((pending & OTGFS_GINT_IPXFR) != 0) + { + usbhost_vtrace1(OTGFS_VTRACE1_GINT_IPXFR, 0); + at32_gint_ipxfrisr(priv); + } + } + + /* We won't get here */ + + return OK; +} + +/**************************************************************************** + * Name: at32_gint_enable and at32_gint_disable + * + * Description: + * Respectively enable or disable the global OTG FS interrupt. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_gint_enable(void) +{ + uint32_t regval; + + /* Set the GINTMSK bit to unmask the interrupt */ + + regval = at32_getreg(AT32_OTGFS_GAHBCFG); + regval |= OTGFS_GAHBCFG_GINTMSK; + at32_putreg(AT32_OTGFS_GAHBCFG, regval); +} + +static void at32_gint_disable(void) +{ + uint32_t regval; + + /* Clear the GINTMSK bit to mask the interrupt */ + + regval = at32_getreg(AT32_OTGFS_GAHBCFG); + regval &= ~OTGFS_GAHBCFG_GINTMSK; + at32_putreg(AT32_OTGFS_GAHBCFG, regval); +} + +/**************************************************************************** + * Name: at32_hostinit_enable + * + * Description: + * Enable host interrupts. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void at32_hostinit_enable(void) +{ + uint32_t regval; + + /* Disable all interrupts. */ + + at32_putreg(AT32_OTGFS_GINTMSK, 0); + + /* Clear any pending interrupts. */ + + at32_putreg(AT32_OTGFS_GINTSTS, 0xffffffff); + + /* Clear any pending USB OTG Interrupts */ + + at32_putreg(AT32_OTGFS_GOTGINT, 0xffffffff); + + /* Clear any pending USB OTG interrupts */ + + at32_putreg(AT32_OTGFS_GINTSTS, 0xbfffffff); + + /* Enable the host interrupts */ + + /* Common interrupts: + * + * OTGFS_GINT_WKUP : Resume/remote wakeup detected interrupt + * OTGFS_GINT_USBSUSP : USB suspend + */ + + regval = (OTGFS_GINT_WKUP | OTGFS_GINT_USBSUSP); + + /* If OTG were supported, we would need to enable the following as well: + * + * OTGFS_GINT_OTG : OTG interrupt + * OTGFS_GINT_SRQ : Session request/new session detected interrupt + * OTGFS_GINT_CIDSCHG : Connector ID status change + */ + + /* Host-specific interrupts + * + * OTGFS_GINT_SOF : Start of frame + * OTGFS_GINT_RXFLVL : RxFIFO non-empty + * OTGFS_GINT_IISOOXFR : Incomplete isochronous OUT transfer + * OTGFS_GINT_HPRT : Host port interrupt + * OTGFS_GINT_HC : Host channels interrupt + * OTGFS_GINT_DISC : Disconnect detected interrupt + */ + +#ifdef CONFIG_AT32_OTGFS_SOFINTR + regval |= (OTGFS_GINT_SOF | OTGFS_GINT_RXFLVL | OTGFS_GINT_IISOOXFR | + OTGFS_GINT_HPRT | OTGFS_GINT_HC | OTGFS_GINT_DISC); +#else + regval |= (OTGFS_GINT_RXFLVL | OTGFS_GINT_IPXFR | OTGFS_GINT_HPRT | + OTGFS_GINT_HC | OTGFS_GINT_DISC); +#endif + at32_putreg(AT32_OTGFS_GINTMSK, regval); +} + +/**************************************************************************** + * Name: at32_txfe_enable + * + * Description: + * Enable Tx FIFO empty interrupts. This is necessary when the entire + * transfer will not fit into Tx FIFO. The transfer will then be completed + * when the Tx FIFO is empty. NOTE: The Tx FIFO interrupt is disabled + * the fifo empty interrupt handler when the transfer is complete. + * + * Input Parameters: + * priv - Driver state structure reference + * chidx - The channel that requires the Tx FIFO empty interrupt + * + * Returned Value: + * None + * + * Assumptions: + * Called from user task context. Interrupts must be disabled to assure + * exclusive access to the GINTMSK register. + * + ****************************************************************************/ + +static void at32_txfe_enable(struct at32_usbhost_s *priv, int chidx) +{ + struct at32_chan_s *chan = &priv->chan[chidx]; + irqstate_t flags; + uint32_t regval; + + /* Disable all interrupts so that we have exclusive access to the GINTMSK + * (it would be sufficient just to disable the GINT interrupt). + */ + + flags = enter_critical_section(); + + /* Should we enable the periodic or non-peridic Tx FIFO empty interrupts */ + + regval = at32_getreg(AT32_OTGFS_GINTMSK); + switch (chan->eptype) + { + default: + case OTGFS_EPTYPE_CTRL: /* Non periodic transfer */ + case OTGFS_EPTYPE_BULK: + regval |= OTGFS_GINT_NPTXFE; + break; + + case OTGFS_EPTYPE_INTR: /* Periodic transfer */ + case OTGFS_EPTYPE_ISOC: + regval |= OTGFS_GINT_PTXFE; + break; + } + + /* Enable interrupts */ + + at32_putreg(AT32_OTGFS_GINTMSK, regval); + leave_critical_section(flags); +} + +/**************************************************************************** + * USB Host Controller Operations + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_wait + * + * Description: + * Wait for a device to be connected or disconnected to/from a hub port. + * + * Input Parameters: + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The location to return the hub port descriptor that detected + * the connection related event. + * + * Returned Value: + * Zero (OK) is returned on success when a device is connected or + * disconnected. This function will not return until either (1) a device is + * connected or disconnect to/from any hub port or until (2) some failure + * occurs. On a failure, a negated errno value is returned indicating the + * nature of the failure + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_wait(struct usbhost_connection_s *conn, + struct usbhost_hubport_s **hport) +{ + struct at32_usbhost_s *priv = &g_usbhost; + struct usbhost_hubport_s *connport; + irqstate_t flags; + int ret; + + /* Loop until a change in connection state is detected */ + + flags = enter_critical_section(); + for (; ; ) + { + /* Is there a change in the connection state of the single root hub + * port? + */ + + if (priv->change) + { + connport = &priv->rhport.hport; + + /* Yes. Remember the new state */ + + connport->connected = priv->connected; + priv->change = false; + + /* And return the root hub port */ + + *hport = connport; + leave_critical_section(flags); + + uinfo("RHport Connected: %s\n", + connport->connected ? "YES" : "NO"); + return OK; + } + +#ifdef CONFIG_USBHOST_HUB + /* Is a device connected to an external hub? */ + + if (priv->hport) + { + /* Yes.. return the external hub port */ + + connport = (struct usbhost_hubport_s *)priv->hport; + priv->hport = NULL; + + *hport = connport; + leave_critical_section(flags); + + uinfo("Hub port Connected: %s\n", + connport->connected ? "YES" : "NO"); + return OK; + } +#endif + + /* Wait for the next connection event */ + + priv->pscwait = true; + ret = nxsem_wait_uninterruptible(&priv->pscsem); + if (ret < 0) + { + return ret; + } + } +} + +/**************************************************************************** + * Name: at32_enumerate + * + * Description: + * Enumerate the connected device. As part of this enumeration process, + * the driver will (1) get the device's configuration descriptor, (2) + * extract the class ID info from the configuration descriptor, (3) call + * usbhost_findclass() to find the class that supports this device, (4) + * call the create() method on the struct usbhost_registry_s interface + * to get a class instance, and finally (5) call the connect() method + * of the struct usbhost_class_s interface. After that, the class is in + * charge of the sequence of operations. + * + * Input Parameters: + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The descriptor of the hub port that has the newly connected + * device. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_rh_enumerate(struct at32_usbhost_s *priv, + struct usbhost_connection_s *conn, + struct usbhost_hubport_s *hport) +{ + uint32_t regval; + int ret; + + DEBUGASSERT(conn != NULL && hport != NULL && hport->port == 0); + + /* Are we connected to a device? The caller should have called the wait() + * method first to be assured that a device is connected. + */ + + while (!priv->connected) + { + /* No, return an error */ + + usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0); + return -ENODEV; + } + + DEBUGASSERT(priv->smstate == SMSTATE_ATTACHED); + + /* USB 2.0 spec says at least 50ms delay before port reset. We wait + * 100ms. + */ + + nxsig_usleep(100 * 1000); + + /* Reset the host port */ + + at32_portreset(priv); + + /* Get the current device speed */ + + regval = at32_getreg(AT32_OTGFS_HPRT); + if ((regval & OTGFS_HPRT_PSPD_MASK) == OTGFS_HPRT_PSPD_LS) + { + priv->rhport.hport.speed = USB_SPEED_LOW; + } + else + { + priv->rhport.hport.speed = USB_SPEED_FULL; + } + + /* Allocate and initialize the root hub port EP0 channels */ + + ret = at32_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, + &priv->ep0); + if (ret < 0) + { + uerr("ERROR: Failed to allocate a control endpoint: %d\n", ret); + } + + return ret; +} + +static int at32_enumerate(struct usbhost_connection_s *conn, + struct usbhost_hubport_s *hport) +{ + struct at32_usbhost_s *priv = &g_usbhost; + int ret; + + DEBUGASSERT(hport); + + /* If this is a connection on the root hub, then we need to go to + * little more effort to get the device speed. If it is a connection + * on an external hub, then we already have that information. + */ + +#ifdef CONFIG_USBHOST_HUB + if (ROOTHUB(hport)) +#endif + { + ret = at32_rh_enumerate(priv, conn, hport); + if (ret < 0) + { + return ret; + } + } + + /* Then let the common usbhost_enumerate do the real enumeration. */ + + uinfo("Enumerate the device\n"); + priv->smstate = SMSTATE_ENUM; + ret = usbhost_enumerate(hport, &hport->devclass); + + /* The enumeration may fail either because of some HCD interfaces failure + * or because the device class is not supported. In either case, we just + * need to perform the disconnection operation and make ready for a new + * enumeration. + */ + + if (ret < 0) + { + /* Return to the disconnected state */ + + uerr("ERROR: Enumeration failed: %d\n", ret); + at32_gint_disconnected(priv); + } + + return ret; +} + +/**************************************************************************** + * Name: at32_ep0configure + * + * Description: + * Configure endpoint 0. This method is normally used internally by the + * enumerate() method but is made available at the interface to support an + * external implementation of the enumeration logic. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep0 - The (opaque) EP0 endpoint instance + * funcaddr - The USB address of the function containing the endpoint that + * EP0 controls + * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH + * maxpacketsize - The maximum number of bytes that can be sent to or + * received from the endpoint in a single data packet + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_ep0configure(struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize) +{ + struct at32_usbhost_s *priv = (struct at32_usbhost_s *)drvr; + struct at32_ctrlinfo_s *ep0info = (struct at32_ctrlinfo_s *)ep0; + struct at32_chan_s *chan; + int ret; + + DEBUGASSERT(drvr != NULL && ep0info != NULL && funcaddr < 128 && + maxpacketsize <= 64); + + /* We must have exclusive access to the USB host hardware and structures */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + /* Configure the EP0 OUT channel */ + + chan = &priv->chan[ep0info->outndx]; + chan->funcaddr = funcaddr; + chan->speed = speed; + chan->maxpacket = maxpacketsize; + + at32_chan_configure(priv, ep0info->outndx); + + /* Configure the EP0 IN channel */ + + chan = &priv->chan[ep0info->inndx]; + chan->funcaddr = funcaddr; + chan->speed = speed; + chan->maxpacket = maxpacketsize; + + at32_chan_configure(priv, ep0info->inndx); + + nxmutex_unlock(&priv->lock); + return OK; +} + +/**************************************************************************** + * Name: at32_epalloc + * + * Description: + * Allocate and configure one endpoint. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * epdesc - Describes the endpoint to be allocated. + * ep - A memory location provided by the caller in which to receive the + * allocated endpoint descriptor. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_epalloc(struct usbhost_driver_s *drvr, + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep) +{ + struct at32_usbhost_s *priv = (struct at32_usbhost_s *)drvr; + int ret; + + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). + */ + + DEBUGASSERT(drvr != 0 && epdesc != NULL && ep != NULL); + + /* We must have exclusive access to the USB host hardware and structures */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + /* Handler control pipes differently from other endpoint types. This is + * because the normal, "transfer" endpoints are unidirectional an require + * only a single channel. Control endpoints, however, are bi-diretional + * and require two channels, one for the IN and one for the OUT direction. + */ + + if (epdesc->xfrtype == OTGFS_EPTYPE_CTRL) + { + ret = at32_ctrlep_alloc(priv, epdesc, ep); + } + else + { + ret = at32_xfrep_alloc(priv, epdesc, ep); + } + + nxmutex_unlock(&priv->lock); + return ret; +} + +/**************************************************************************** + * Name: at32_epfree + * + * Description: + * Free and endpoint previously allocated by DRVR_EPALLOC. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The endpoint to be freed. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) +{ + struct at32_usbhost_s *priv = (struct at32_usbhost_s *)drvr; + int ret; + + DEBUGASSERT(priv); + + /* We must have exclusive access to the USB host hardware and structures */ + + ret = nxmutex_lock(&priv->lock); + + /* A single channel is represent by an index in the range of 0 to + * AT32_MAX_TX_FIFOS. Otherwise, the ep must be a pointer to an allocated + * control endpoint structure. + */ + + if ((uintptr_t)ep < AT32_MAX_TX_FIFOS) + { + /* Halt the channel and mark the channel available */ + + at32_chan_free(priv, (int)ep); + } + else + { + /* Halt both control channel and mark the channels available */ + + struct at32_ctrlinfo_s *ctrlep = + (struct at32_ctrlinfo_s *)ep; + + at32_chan_free(priv, ctrlep->inndx); + at32_chan_free(priv, ctrlep->outndx); + + /* And free the control endpoint container */ + + kmm_free(ctrlep); + } + + nxmutex_unlock(&priv->lock); + return ret; +} + +/**************************************************************************** + * Name: at32_alloc + * + * Description: + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc. + * + * This interface was optimized under a particular assumption. It was + * assumed that the driver maintains a pool of small, pre-allocated + * buffers for descriptor traffic. NOTE that size is not an input, but + * an output: The size of the pre-allocated buffer is returned. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_alloc(struct usbhost_driver_s *drvr, + uint8_t **buffer, size_t *maxlen) +{ + uint8_t *alloc; + + DEBUGASSERT(drvr && buffer && maxlen); + + /* There is no special memory requirement for the AT32. */ + + alloc = (uint8_t *)kmm_malloc(CONFIG_AT32_OTGFS_DESCSIZE); + if (!alloc) + { + return -ENOMEM; + } + + /* Return the allocated address and size of the descriptor buffer */ + + *buffer = alloc; + *maxlen = CONFIG_AT32_OTGFS_DESCSIZE; + return OK; +} + +/**************************************************************************** + * Name: at32_free + * + * Description: + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of the allocated buffer memory to be freed. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_free(struct usbhost_driver_s *drvr, uint8_t *buffer) +{ + /* There is no special memory requirement */ + + DEBUGASSERT(drvr && buffer); + kmm_free(buffer); + return OK; +} + +/**************************************************************************** + * Name: at32_ioalloc + * + * Description: + * Some hardware supports special memory in which larger IO buffers can + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kmm_malloc. + * + * This interface differs from DRVR_ALLOC in that the buffers are + * variable-sized. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * buflen - The size of the buffer required. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_ioalloc(struct usbhost_driver_s *drvr, + uint8_t **buffer, size_t buflen) +{ + uint8_t *alloc; + + DEBUGASSERT(drvr && buffer && buflen > 0); + + /* There is no special memory requirement */ + + alloc = (uint8_t *)kmm_malloc(buflen); + if (!alloc) + { + return -ENOMEM; + } + + /* Return the allocated buffer */ + + *buffer = alloc; + return OK; +} + +/**************************************************************************** + * Name: at32_iofree + * + * Description: + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kmm_free(). + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of the allocated buffer memory to be freed. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_iofree(struct usbhost_driver_s *drvr, + uint8_t *buffer) +{ + /* There is no special memory requirement */ + + DEBUGASSERT(drvr && buffer); + kmm_free(buffer); + return OK; +} + +/**************************************************************************** + * Name: at32_ctrlin and at32_ctrlout + * + * Description: + * Process a IN or OUT request on the control endpoint. These methods + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() + * method can be called again until the control transfer functions + * returns. + * + * These are blocking methods; these functions will not return until the + * control transfer has completed. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep0 - The control endpoint to send/receive the control request. + * req - Describes the request to be sent. This request must lie in memory + * created by DRVR_ALLOC. + * buffer - A buffer used for sending the request and for returning any + * responses. This buffer must be large enough to hold the length value + * in the request description. buffer must have been allocated using + * DRVR_ALLOC. + * + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static int at32_ctrlin(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, + const struct usb_ctrlreq_s *req, + uint8_t *buffer) +{ + struct at32_usbhost_s *priv = (struct at32_usbhost_s *)drvr; + struct at32_ctrlinfo_s *ep0info = (struct at32_ctrlinfo_s *)ep0; + uint16_t buflen; + clock_t start; + clock_t elapsed; + int retries; + int ret; + + DEBUGASSERT(priv != NULL && ep0info != NULL && req != NULL); + usbhost_vtrace2(OTGFS_VTRACE2_CTRLIN, req->type, req->req); + uinfo("type:%02x req:%02x value:%02x%02x index:%02x%02x len:%02x%02x\n", + req->type, req->req, req->value[1], req->value[0], + req->index[1], req->index[0], req->len[1], req->len[0]); + + /* Extract values from the request */ + + buflen = at32_getle16(req->len); + + /* We must have exclusive access to the USB host hardware and structures */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + /* Loop, retrying until the retry time expires */ + + for (retries = 0; retries < AT32_RETRY_COUNT; retries++) + { + /* Send the SETUP request */ + + ret = at32_ctrl_sendsetup(priv, ep0info, req); + if (ret < 0) + { + usbhost_trace1(OTGFS_TRACE1_SENDSETUP, -ret); + continue; + } + + /* Handle the IN data phase (if any) */ + + if (buflen > 0) + { + ret = at32_ctrl_recvdata(priv, ep0info, buffer, buflen); + if (ret < 0) + { + usbhost_trace1(OTGFS_TRACE1_RECVDATA, -ret); + continue; + } + } + + /* Get the start time. Loop again until the timeout expires */ + + start = clock_systime_ticks(); + do + { + /* Handle the status OUT phase */ + + priv->chan[ep0info->outndx].outdata1 ^= true; + ret = at32_ctrl_senddata(priv, ep0info, NULL, 0); + if (ret == OK) + { + /* All success transactions exit here */ + + nxmutex_unlock(&priv->lock); + return OK; + } + + usbhost_trace1(OTGFS_TRACE1_SENDDATA, ret < 0 ? -ret : ret); + + /* Get the elapsed time (in frames) */ + + elapsed = clock_systime_ticks() - start; + } + while (elapsed < AT32_DATANAK_DELAY); + } + + /* All failures exit here after all retries and timeouts are exhausted */ + + nxmutex_unlock(&priv->lock); + return -ETIMEDOUT; +} + +static int at32_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, + const struct usb_ctrlreq_s *req, + const uint8_t *buffer) +{ + struct at32_usbhost_s *priv = (struct at32_usbhost_s *)drvr; + struct at32_ctrlinfo_s *ep0info = (struct at32_ctrlinfo_s *)ep0; + uint16_t buflen; + clock_t start; + clock_t elapsed; + int retries; + int ret; + + DEBUGASSERT(priv != NULL && ep0info != NULL && req != NULL); + usbhost_vtrace2(OTGFS_VTRACE2_CTRLOUT, req->type, req->req); + uinfo("type:%02x req:%02x value:%02x%02x index:%02x%02x len:%02x%02x\n", + req->type, req->req, req->value[1], req->value[0], + req->index[1], req->index[0], req->len[1], req->len[0]); + + /* Extract values from the request */ + + buflen = at32_getle16(req->len); + + /* We must have exclusive access to the USB host hardware and structures */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + /* Loop, retrying until the retry time expires */ + + for (retries = 0; retries < AT32_RETRY_COUNT; retries++) + { + /* Send the SETUP request */ + + ret = at32_ctrl_sendsetup(priv, ep0info, req); + if (ret < 0) + { + usbhost_trace1(OTGFS_TRACE1_SENDSETUP, -ret); + continue; + } + + /* Get the start time. Loop again until the timeout expires */ + + start = clock_systime_ticks(); + do + { + /* Handle the data OUT phase (if any) */ + + if (buflen > 0) + { + /* Start DATA out transfer (only one DATA packet) */ + + priv->chan[ep0info->outndx].outdata1 = true; + ret = at32_ctrl_senddata(priv, ep0info, (uint8_t *)buffer, + buflen); + if (ret < 0) + { + usbhost_trace1(OTGFS_TRACE1_SENDDATA, -ret); + } + } + + /* Handle the status IN phase */ + + if (ret == OK) + { + ret = at32_ctrl_recvdata(priv, ep0info, NULL, 0); + if (ret == OK) + { + /* All success transactins exit here */ + + nxmutex_unlock(&priv->lock); + return OK; + } + + usbhost_trace1(OTGFS_TRACE1_RECVDATA, ret < 0 ? -ret : ret); + } + + /* Get the elapsed time (in frames) */ + + elapsed = clock_systime_ticks() - start; + } + while (elapsed < AT32_DATANAK_DELAY); + } + + /* All failures exit here after all retries and timeouts are exhausted */ + + nxmutex_unlock(&priv->lock); + return -ETIMEDOUT; +} + +/**************************************************************************** + * Name: at32_transfer + * + * Description: + * Process a request to handle a transfer descriptor. This method will + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or + * ctrlout methods can be called again until this function returns. + * + * This is a blocking method; this functions will not return until the + * transfer has completed. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC + * buflen - The length of the data to be sent or received. + * + * Returned Value: + * On success, a non-negative value is returned that indicates the number + * of bytes successfully transferred. On a failure, a negated errno value + * is returned that indicates the nature of the failure: + * + * EAGAIN - If devices NAKs the transfer (or NYET or other error where + * it may be appropriate to restart the entire transaction). + * EPERM - If the endpoint stalls + * EIO - On a TX or data toggle error + * EPIPE - Overrun errors + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static ssize_t at32_transfer(struct usbhost_driver_s *drvr, + usbhost_ep_t ep, + uint8_t *buffer, size_t buflen) +{ + struct at32_usbhost_s *priv = (struct at32_usbhost_s *)drvr; + unsigned int chidx = (unsigned int)ep; + ssize_t nbytes; + int ret; + + uinfo("chidx: %d buflen: %d\n", (unsigned int)ep, buflen); + + DEBUGASSERT(priv && buffer && chidx < AT32_MAX_TX_FIFOS && buflen > 0); + + /* We must have exclusive access to the USB host hardware and structures */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return (ssize_t)ret; + } + + /* Handle IN and OUT transfer slightly differently */ + + if (priv->chan[chidx].in) + { + nbytes = at32_in_transfer(priv, chidx, buffer, buflen); + } + else + { + nbytes = at32_out_transfer(priv, chidx, buffer, buflen); + } + + nxmutex_unlock(&priv->lock); + return nbytes; +} + +/**************************************************************************** + * Name: at32_asynch + * + * Description: + * Process a request to handle a transfer descriptor. This method will + * enqueue the transfer request and return immediately. When the transfer + * completes, the callback will be invoked with the provided transfer. + * This method is useful for receiving interrupt transfers which may come + * infrequently. + * + * Only one transfer may be queued; Neither this method nor the ctrlin or + * ctrlout methods can be called again until the transfer completes. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC + * buflen - The length of the data to be sent or received. + * callback - This function will be called when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST_ASYNCH +static int at32_asynch(struct usbhost_driver_s *drvr, usbhost_ep_t ep, + uint8_t *buffer, size_t buflen, + usbhost_asynch_t callback, void *arg) +{ + struct at32_usbhost_s *priv = (struct at32_usbhost_s *)drvr; + unsigned int chidx = (unsigned int)ep; + int ret; + + uinfo("chidx: %d buflen: %d\n", (unsigned int)ep, buflen); + + DEBUGASSERT(priv && buffer && chidx < AT32_MAX_TX_FIFOS && buflen > 0); + + /* We must have exclusive access to the USB host hardware and structures */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + /* Handle IN and OUT transfer slightly differently */ + + if (priv->chan[chidx].in) + { + ret = at32_in_asynch(priv, chidx, buffer, buflen, callback, arg); + } + else + { + ret = at32_out_asynch(priv, chidx, buffer, buflen, callback, arg); + } + + nxmutex_unlock(&priv->lock); + return ret; +} +#endif /* CONFIG_USBHOST_ASYNCH */ + +/**************************************************************************** + * Name: at32_cancel + * + * Description: + * Cancel a pending transfer on an endpoint. Cancelled synchronous or + * asynchronous transfer will complete normally with the error -ESHUTDOWN. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which an asynchronous transfer should be transferred. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + ****************************************************************************/ + +static int at32_cancel(struct usbhost_driver_s *drvr, usbhost_ep_t ep) +{ + struct at32_usbhost_s *priv = (struct at32_usbhost_s *)drvr; + struct at32_chan_s *chan; + unsigned int chidx = (unsigned int)ep; + irqstate_t flags; + + uinfo("chidx: %u\n", chidx); + + DEBUGASSERT(priv && chidx < AT32_MAX_TX_FIFOS); + chan = &priv->chan[chidx]; + + /* We need to disable interrupts to avoid race conditions with the + * asynchronous completion of the transfer being cancelled. + */ + + flags = enter_critical_section(); + + /* Halt the channel */ + + at32_chan_halt(priv, chidx, CHREASON_CANCELLED); + chan->result = -ESHUTDOWN; + + /* Is there a thread waiting for this transfer to complete? */ + + if (chan->waiter) + { +#ifdef CONFIG_USBHOST_ASYNCH + /* Yes.. there should not also be a callback scheduled */ + + DEBUGASSERT(chan->callback == NULL); +#endif + + /* Wake'em up! */ + + nxsem_post(&chan->waitsem); + chan->waiter = false; + } + +#ifdef CONFIG_USBHOST_ASYNCH + /* No.. is an asynchronous callback expected when the transfer + * completes? + */ + + else if (chan->callback) + { + usbhost_asynch_t callback; + void *arg; + + /* Extract the callback information */ + + callback = chan->callback; + arg = chan->arg; + + chan->callback = NULL; + chan->arg = NULL; + chan->xfrd = 0; + + /* Then perform the callback */ + + callback(arg, -ESHUTDOWN); + } +#endif + + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: at32_connect + * + * Description: + * New connections may be detected by an attached hub. This method is the + * mechanism that is used by the hub class to introduce a new connection + * and port description to the system. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The descriptor of the hub port that detected the connection + * related event + * connected - True: device connected; false: device disconnected + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST_HUB +static int at32_connect(struct usbhost_driver_s *drvr, + struct usbhost_hubport_s *hport, + bool connected) +{ + struct at32_usbhost_s *priv = (struct at32_usbhost_s *)drvr; + irqstate_t flags; + + DEBUGASSERT(priv != NULL && hport != NULL); + + /* Set the connected/disconnected flag */ + + hport->connected = connected; + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); + + /* Report the connection event */ + + flags = enter_critical_section(); + priv->hport = hport; + if (priv->pscwait) + { + priv->pscwait = false; + nxsem_post(&priv->pscsem); + } + + leave_critical_section(flags); + return OK; +} +#endif + +/**************************************************************************** + * Name: at32_disconnect + * + * Description: + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not call the class' + * disconnected() method. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. + * + * Returned Value: + * None + * + * Assumptions: + * - Only a single class bound to a single device is supported. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static void at32_disconnect(struct usbhost_driver_s *drvr, + struct usbhost_hubport_s *hport) +{ + DEBUGASSERT(hport != NULL); + hport->devclass = NULL; +} + +/**************************************************************************** + * Name: at32_portreset + * + * Description: + * Reset the USB host port. + * + * NOTE: "Before starting to drive a USB reset, the application waits for + * the OTG interrupt triggered by the debounce done bit (DBCDNE bit in + * OTG_FS_GOTGINT), which indicates that the bus is stable again after + * the electrical debounce caused by the attachment of a pull-up resistor + * on DP (FS) or DM (LS). + * + * Input Parameters: + * priv -- USB host driver private data structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_portreset(struct at32_usbhost_s *priv) +{ + uint32_t regval; + + regval = at32_getreg(AT32_OTGFS_HPRT); + regval &= ~(OTGFS_HPRT_PENA | OTGFS_HPRT_PCDET | OTGFS_HPRT_PENCHNG | + OTGFS_HPRT_POCCHNG); + regval |= OTGFS_HPRT_PRST; + at32_putreg(AT32_OTGFS_HPRT, regval); + + up_mdelay(20); + + regval &= ~OTGFS_HPRT_PRST; + at32_putreg(AT32_OTGFS_HPRT, regval); + + up_mdelay(20); +} + +/**************************************************************************** + * Name: at32_flush_txfifos + * + * Description: + * Flush the selected Tx FIFO. + * + * Input Parameters: + * txfnum -- USB host driver private data structure. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void at32_flush_txfifos(uint32_t txfnum) +{ + uint32_t regval; + uint32_t timeout; + + /* Initiate the TX FIFO flush operation */ + + regval = OTGFS_GRSTCTL_TXFFLSH | txfnum; + at32_putreg(AT32_OTGFS_GRSTCTL, regval); + + /* Wait for the FLUSH to complete */ + + for (timeout = 0; timeout < AT32_FLUSH_DELAY; timeout++) + { + regval = at32_getreg(AT32_OTGFS_GRSTCTL); + if ((regval & OTGFS_GRSTCTL_TXFFLSH) == 0) + { + break; + } + } + + /* Wait for 3 PHY Clocks */ + + up_udelay(3); +} + +/**************************************************************************** + * Name: at32_flush_rxfifo + * + * Description: + * Flush the Rx FIFO. + * + * Input Parameters: + * priv -- USB host driver private data structure. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void at32_flush_rxfifo(void) +{ + uint32_t regval; + uint32_t timeout; + + /* Initiate the RX FIFO flush operation */ + + at32_putreg(AT32_OTGFS_GRSTCTL, OTGFS_GRSTCTL_RXFFLSH); + + /* Wait for the FLUSH to complete */ + + for (timeout = 0; timeout < AT32_FLUSH_DELAY; timeout++) + { + regval = at32_getreg(AT32_OTGFS_GRSTCTL); + if ((regval & OTGFS_GRSTCTL_RXFFLSH) == 0) + { + break; + } + } + + /* Wait for 3 PHY Clocks */ + + up_udelay(3); +} + +/**************************************************************************** + * Name: at32_vbusdrive + * + * Description: + * Drive the Vbus +5V. + * + * Input Parameters: + * priv - USB host driver private data structure. + * state - True: Drive, False: Don't drive + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void at32_vbusdrive(struct at32_usbhost_s *priv, bool state) +{ + uint32_t regval; + +#ifdef CONFIG_AT32_OTGFS_VBUS_CONTROL + /* Enable/disable the external charge pump */ + + at32_usbhost_vbusdrive(0, state); +#endif + + /* Turn on the Host port power. */ + + regval = at32_getreg(AT32_OTGFS_HPRT); + regval &= ~(OTGFS_HPRT_PENA | OTGFS_HPRT_PCDET | OTGFS_HPRT_PENCHNG | + OTGFS_HPRT_POCCHNG); + + if (((regval & OTGFS_HPRT_PPWR) == 0) && state) + { + regval |= OTGFS_HPRT_PPWR; + at32_putreg(AT32_OTGFS_HPRT, regval); + } + + if (((regval & OTGFS_HPRT_PPWR) != 0) && !state) + { + regval &= ~OTGFS_HPRT_PPWR; + at32_putreg(AT32_OTGFS_HPRT, regval); + } + + up_mdelay(200); +} + +/**************************************************************************** + * Name: at32_host_initialize + * + * Description: + * Initialize/re-initialize hardware for host mode operation. At present, + * this function is called only from at32_hw_initialize(). But if OTG + * mode were supported, this function would also be called to switch + * between host and device modes on a connector ID change interrupt. + * + * Input Parameters: + * priv -- USB host driver private data structure. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void at32_host_initialize(struct at32_usbhost_s *priv) +{ + uint32_t regval; + uint32_t offset; + int i; + + /* Restart the PHY Clock */ + + at32_putreg(AT32_OTGFS_PCGCCTL, 0); + + /* Initialize Host Configuration (HCFG) register */ + + regval = at32_getreg(AT32_OTGFS_HCFG); + regval &= ~OTGFS_HCFG_FSLSPCS_MASK; + regval |= OTGFS_HCFG_FSLSPCS_FS48MHz; + at32_putreg(AT32_OTGFS_HCFG, regval); + + /* Reset the host port */ + + at32_portreset(priv); + + /* Clear the FS-/LS-only support bit in the HCFG register */ + + regval = at32_getreg(AT32_OTGFS_HCFG); + regval &= ~OTGFS_HCFG_FSLSS; + at32_putreg(AT32_OTGFS_HCFG, regval); + + /* Carve up FIFO memory for the Rx FIFO and the periodic + * and non-periodic Tx FIFOs + */ + + /* Configure Rx FIFO size (GRXFSIZ) */ + + at32_putreg(AT32_OTGFS_GRXFSIZ, CONFIG_AT32_OTGFS_RXFIFO_SIZE); + offset = CONFIG_AT32_OTGFS_RXFIFO_SIZE; + + /* Setup the host non-periodic Tx FIFO size (HNPTXFSIZ) */ + + regval = (offset | + (CONFIG_AT32_OTGFS_NPTXFIFO_SIZE << + OTGFS_HNPTXFSIZ_NPTXFD_SHIFT)); + at32_putreg(AT32_OTGFS_HNPTXFSIZ, regval); + offset += CONFIG_AT32_OTGFS_NPTXFIFO_SIZE; + + /* Set up the host periodic Tx fifo size register (HPTXFSIZ) */ + + regval = (offset | + (CONFIG_AT32_OTGFS_PTXFIFO_SIZE << + OTGFS_HPTXFSIZ_PTXFD_SHIFT)); + at32_putreg(AT32_OTGFS_HPTXFSIZ, regval); + + /* If OTG were supported, we should need to clear HNP enable bit in the + * USB_OTG control register about here. + */ + + /* Flush all FIFOs */ + + at32_flush_txfifos(OTGFS_GRSTCTL_TXFNUM_HALL); + at32_flush_rxfifo(); + + /* Clear all pending HC Interrupts */ + + for (i = 0; i < AT32_NHOST_CHANNELS; i++) + { + at32_putreg(AT32_OTGFS_HCINT(i), 0xffffffff); + at32_putreg(AT32_OTGFS_HCINTMSK(i), 0); + } + + /* Drive Vbus +5V (the smoke test). Should be done elsewhere in OTG + * mode. + */ + + at32_vbusdrive(priv, true); + + /* Enable host interrupts */ + + at32_hostinit_enable(); +} + +/**************************************************************************** + * Name: at32_sw_initialize + * + * Description: + * One-time setup of the host driver state structure. + * + * Input Parameters: + * priv -- USB host driver private data structure. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static inline void at32_sw_initialize(struct at32_usbhost_s *priv) +{ + struct usbhost_driver_s *drvr; + struct usbhost_hubport_s *hport; + int i; + + /* Initialize the device operations */ + + drvr = &priv->drvr; + drvr->ep0configure = at32_ep0configure; + drvr->epalloc = at32_epalloc; + drvr->epfree = at32_epfree; + drvr->alloc = at32_alloc; + drvr->free = at32_free; + drvr->ioalloc = at32_ioalloc; + drvr->iofree = at32_iofree; + drvr->ctrlin = at32_ctrlin; + drvr->ctrlout = at32_ctrlout; + drvr->transfer = at32_transfer; +#ifdef CONFIG_USBHOST_ASYNCH + drvr->asynch = at32_asynch; +#endif + drvr->cancel = at32_cancel; +#ifdef CONFIG_USBHOST_HUB + drvr->connect = at32_connect; +#endif + drvr->disconnect = at32_disconnect; + + /* Initialize the public port representation */ + + hport = &priv->rhport.hport; + hport->drvr = drvr; +#ifdef CONFIG_USBHOST_HUB + hport->parent = NULL; +#endif + hport->ep0 = (usbhost_ep_t)&priv->ep0; + hport->speed = USB_SPEED_FULL; + + /* Initialize function address generation logic */ + + usbhost_devaddr_initialize(&priv->devgen); + priv->rhport.pdevgen = &priv->devgen; + + /* Initialize the driver state data */ + + priv->smstate = SMSTATE_DETACHED; + priv->connected = false; + priv->change = false; + + /* Put all of the channels back in their initial, allocated state */ + + memset(priv->chan, 0, AT32_MAX_TX_FIFOS * sizeof(struct at32_chan_s)); + + /* Initialize each channel */ + + for (i = 0; i < AT32_MAX_TX_FIFOS; i++) + { + struct at32_chan_s *chan = &priv->chan[i]; + + chan->chidx = i; + nxsem_init(&chan->waitsem, 0, 0); + } +} + +/**************************************************************************** + * Name: at32_hw_initialize + * + * Description: + * One-time setup of the host controller hardware for normal operations. + * + * Input Parameters: + * priv -- USB host driver private data structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static inline int at32_hw_initialize(struct at32_usbhost_s *priv) +{ + uint32_t regval; + unsigned long timeout; + + /* Set the PHYSEL bit in the GUSBCFG register to select the OTG FS serial + * transceiver: "This bit is always 1 with write-only access" + */ + + regval = at32_getreg(AT32_OTGFS_GUSBCFG); + at32_putreg(AT32_OTGFS_GUSBCFG, regval); + + /* Reset after a PHY select and set Host mode. First, wait for AHB master + * IDLE state. + */ + + for (timeout = 0; timeout < AT32_READY_DELAY; timeout++) + { + up_udelay(3); + regval = at32_getreg(AT32_OTGFS_GRSTCTL); + if ((regval & OTGFS_GRSTCTL_AHBIDL) != 0) + { + break; + } + } + + /* Then perform the core soft reset. */ + + at32_putreg(AT32_OTGFS_GRSTCTL, OTGFS_GRSTCTL_CSRST); + for (timeout = 0; timeout < AT32_READY_DELAY; timeout++) + { + regval = at32_getreg(AT32_OTGFS_GRSTCTL); + if ((regval & OTGFS_GRSTCTL_CSRST) == 0) + { + break; + } + } + + /* Wait for 3 PHY Clocks */ + + up_udelay(3); + + /* Deactivate the power down */ + + regval = OTGFS_GCCFG_PWRDWN; +#if !defined(CONFIG_USBDEV_VBUSSENSING) && !defined(CONFIG_AT32_OTGFS_VBUS_CONTROL) + regval |= OTGFS_GCCFG_NOVBUSSENS; +#endif +#ifdef CONFIG_AT32_OTGFS_SOFOUTPUT + regval |= OTGFS_GCCFG_SOFOUTEN; +#endif + at32_putreg(AT32_OTGFS_GCCFG, regval); + up_mdelay(20); + + /* Initialize OTG features: In order to support OTP, the HNPCAP and SRPCAP + * bits would need to be set in the GUSBCFG register about here. + */ + + /* Force Host Mode */ + + regval = at32_getreg(AT32_OTGFS_GUSBCFG); + regval &= ~OTGFS_GUSBCFG_FDMOD; + regval |= OTGFS_GUSBCFG_FHMOD; + at32_putreg(AT32_OTGFS_GUSBCFG, regval); + up_mdelay(50); + + /* Initialize host mode and return success */ + + at32_host_initialize(priv); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_otgfshost_initialize + * + * Description: + * Initialize USB host device controller hardware. + * + * Input Parameters: + * controller -- If the device supports more than USB host controller, then + * this identifies which controller is being initialized. Normally, this + * is just zero. + * + * Returned Value: + * And instance of the USB host interface. The controlling task should + * use this interface to (1) call the wait() method to wait for a device + * to be connected, and (2) call the enumerate() method to bind the device + * to a class driver. + * + * Assumptions: + * - This function should called in the initialization sequence in order + * to initialize the USB device functionality. + * - Class drivers should be initialized prior to calling this function. + * Otherwise, there is a race condition if the device is already connected. + * + ****************************************************************************/ + +struct usbhost_connection_s *at32_otgfshost_initialize(int controller) +{ + /* At present, there is only support for a single OTG FS host. Hence it is + * pre-allocated as g_usbhost. However, in most code, the private data + * structure will be referenced using the 'priv' pointer (rather than the + * global data) in order to simplify any future support for multiple + * devices. + */ + + struct at32_usbhost_s *priv = &g_usbhost; + + /* Sanity checks */ + + DEBUGASSERT(controller == 0); + + /* Make sure that interrupts from the OTG FS core are disabled */ + + at32_gint_disable(); + + /* Reset the state of the host driver */ + + at32_sw_initialize(priv); + + /* Alternate function pin configuration. Here we assume that: + * + * 1. GPIOA, SYSCFG, and OTG FS peripheral clocking have already been\ + * enabled as part of the boot sequence. + * 2. Board-specific logic has already enabled other board specific GPIOs + * for things like soft pull-up, VBUS sensing, power controls, and over- + * current detection. + */ + + /* Configure OTG FS alternate function pins for DM, DP, ID, and SOF. + * + * PIN* SIGNAL DIRECTION + * ---- ----------- ---------- + * PA8 OTG_FS_SOF SOF clock output + * PA9 OTG_FS_VBUS VBUS input for device, Driven by external regulator by + * host (not an alternate function) + * PA10 OTG_FS_ID OTG ID pin (only needed in Dual mode) + * PA11 OTG_FS_DM D- I/O + * PA12 OTG_FS_DP D+ I/O + * + * *Pins may vary from device-to-device. + */ + + at32_configgpio(GPIO_OTGFS_DM); + at32_configgpio(GPIO_OTGFS_DP); +#ifdef CONFIG_USBDEV + at32_configgpio(GPIO_OTGFS_ID); /* Only needed for OTG */ +#endif + + /* SOF output pin configuration is configurable */ + +#ifdef CONFIG_AT32_OTGFS_SOFOUTPUT + at32_configgpio(GPIO_OTGFS_SOF); +#endif + + /* Initialize the USB OTG FS core */ + + at32_hw_initialize(priv); + + /* Attach USB host controller interrupt handler */ + + if (irq_attach(AT32_IRQ_OTGFS, at32_gint_isr, NULL) != 0) + { + usbhost_trace1(OTGFS_TRACE1_IRQATTACH, 0); + return NULL; + } + + /* Enable USB OTG FS global interrupts */ + + at32_gint_enable(); + + /* Enable interrupts at the interrupt controller */ + + up_enable_irq(AT32_IRQ_OTGFS); + return &g_usbconn; +} + +#endif /* CONFIG_AT32_USBHOST && CONFIG_AT32_OTGFS */ diff --git a/arch/arm/src/at32/at32_pm.h b/arch/arm/src/at32/at32_pm.h new file mode 100644 index 0000000000..2d69663ca8 --- /dev/null +++ b/arch/arm/src/at32/at32_pm.h @@ -0,0 +1,125 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_pm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_PM_H +#define __ARCH_ARM_SRC_AT32_AT32_PM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "chip.h" +#include "arm_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_pmstop + * + * Description: + * Enter STOP mode. + * + * Input Parameters: + * lpds - true: To further reduce power consumption in Stop mode, put the + * internal voltage regulator in low-power mode using the LPDS bit + * of the Power control register (PWR_CR). + * + * Returned Value: + * Zero means that the STOP was successfully entered and the system has + * been re-awakened. The internal voltage regulator is back to its + * original state. Otherwise, STOP mode did not occur and a negated + * errno value is returned to indicate the cause of the failure. + * + ****************************************************************************/ + +int at32_pmstop(bool lpds); + +/**************************************************************************** + * Name: at32_pmstandby + * + * Description: + * Enter STANDBY mode. + * + * Input Parameters: + * None + * + * Returned Value: + * On success, this function will not return (STANDBY mode can only be + * terminated with a reset event). Otherwise, STANDBY mode did not occur + * and a negated errno value is returned to indicate the cause of the + * failure. + * + ****************************************************************************/ + +int at32_pmstandby(void); + +/**************************************************************************** + * Name: at32_pmsleep + * + * Description: + * Enter SLEEP mode. + * + * Input Parameters: + * sleeponexit - true: SLEEPONEXIT bit is set when the WFI instruction is + * executed, the MCU enters Sleep mode as soon as it + * exits the lowest priority ISR. + * - false: SLEEPONEXIT bit is cleared, the MCU enters Sleep + * mode as soon as WFI or WFE instruction is executed. + * Returned Value: + * None + * + ****************************************************************************/ + +void at32_pmsleep(bool sleeponexit); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_ARM_SRC_AT32_AT32_PM_H */ diff --git a/arch/arm/src/at32/at32_pminitialize.c b/arch/arm/src/at32/at32_pminitialize.c new file mode 100644 index 0000000000..f3f3a76232 --- /dev/null +++ b/arch/arm/src/at32/at32_pminitialize.c @@ -0,0 +1,62 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_pminitialize.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "arm_internal.h" +#include "at32_pm.h" + +#ifdef CONFIG_PM + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_pminitialize + * + * Description: + * This function is called by MCU-specific logic at power-on reset in + * order to provide one-time initialization the power management subsystem. + * This function must be called *very* early in the initialization sequence + * *before* any other device drivers are initialized (since they may + * attempt to register with the power management subsystem). + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void arm_pminitialize(void) +{ + /* Initialize the NuttX power management subsystem proper */ + + pm_initialize(); +} + +#endif /* CONFIG_PM */ diff --git a/arch/arm/src/at32/at32_pmsleep.c b/arch/arm/src/at32/at32_pmsleep.c new file mode 100644 index 0000000000..6b51581de3 --- /dev/null +++ b/arch/arm/src/at32/at32_pmsleep.c @@ -0,0 +1,97 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_pmsleep.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "arm_internal.h" +#include "nvic.h" +#include "at32_pwr.h" +#include "at32_pm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_pmsleep + * + * Description: + * Enter SLEEP mode. + * + * Input Parameters: + * sleeponexit - true: SLEEPONEXIT bit is set when the WFI instruction is + * executed, the MCU enters Sleep mode as soon as it + * exits the lowest priority ISR. + * - false: SLEEPONEXIT bit is cleared, the MCU enters Sleep + * mode as soon as WFI or WFE instruction is executed. + * Returned Value: + * None + * + ****************************************************************************/ + +void at32_pmsleep(bool sleeponexit) +{ + uint32_t regval; + + /* Clear SLEEPDEEP bit of Cortex System Control Register */ + + regval = getreg32(NVIC_SYSCON); + regval &= ~NVIC_SYSCON_SLEEPDEEP; + if (sleeponexit) + { + regval |= NVIC_SYSCON_SLEEPONEXIT; + } + else + { + regval &= ~NVIC_SYSCON_SLEEPONEXIT; + } + + putreg32(regval, NVIC_SYSCON); + + /* Sleep until the wakeup interrupt or event occurs */ + +#ifdef CONFIG_PM_WFE + /* Mode: SLEEP + Entry with WFE */ + + asm("wfe"); +#else + /* Mode: SLEEP + Entry with WFI */ + + asm("wfi"); +#endif +} diff --git a/arch/arm/src/at32/at32_pmstandby.c b/arch/arm/src/at32/at32_pmstandby.c new file mode 100644 index 0000000000..fa17392072 --- /dev/null +++ b/arch/arm/src/at32/at32_pmstandby.c @@ -0,0 +1,96 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_pmstandby.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "arm_internal.h" +#include "nvic.h" +#include "at32_pwr.h" +#include "at32_pm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_pmstandby + * + * Description: + * Enter STANDBY mode. + * + * Input Parameters: + * None + * + * Returned Value: + * On success, this function will not return (STANDBY mode can only be + * terminated with a reset event). Otherwise, STANDBY mode did not occur + * and a negated errno value is returned to indicate the cause of the + * failure. + * + ****************************************************************************/ + +int at32_pmstandby(void) +{ + uint32_t regval; + + /* Clear the Wake-Up Flag by setting the CWUF bit in the power control + * register. + */ + + regval = getreg32(AT32_PWC_CTRL); + regval |= PWC_CTRL_CLSWEF; + putreg32(regval, AT32_PWC_CTRL); + + /* Set the Power Down Deep Sleep (PDDS) bit in the power control + * register. + */ + + regval |= PWC_CTRL_LPSEL; + putreg32(regval, AT32_PWC_CTRL); + + /* Set SLEEPDEEP bit of Cortex System Control Register */ + + regval = getreg32(NVIC_SYSCON); + regval |= NVIC_SYSCON_SLEEPDEEP; + putreg32(regval, NVIC_SYSCON); + + /* Sleep until the wakeup reset occurs */ + + asm("wfi"); + return OK; /* Won't get here */ +} diff --git a/arch/arm/src/at32/at32_pmstop.c b/arch/arm/src/at32/at32_pmstop.c new file mode 100644 index 0000000000..86d8200257 --- /dev/null +++ b/arch/arm/src/at32/at32_pmstop.c @@ -0,0 +1,107 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_pmstop.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "arm_internal.h" +#include "nvic.h" +#include "at32_pwr.h" +#include "at32_pm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_pmstop + * + * Description: + * Enter STOP mode. + * + * Input Parameters: + * lpds - true: To further reduce power consumption in Stop mode, put the + * internal voltage regulator in low-power mode using the LPDS bit + * of the Power control register (PWR_CR). + * + * Returned Value: + * Zero means that the STOP was successfully entered and the system has + * been re-awakened. The internal voltage regulator is back to its + * original state. Otherwise, STOP mode did not occur and a negated + * errno value is returned to indicate the cause of the failure. + * + ****************************************************************************/ + +int at32_pmstop(bool lpds) +{ + uint32_t regval; + + /* Clear the Power Down Deep Sleep (PDDS) and the Low Power Deep Sleep + * (LPDS)) bits in the power control register. + */ + + regval = getreg32(AT32_PWC_CTRL); + regval &= ~(PWC_CTRL_VRSEL | PWC_CTRL_LPSEL); + + /* Set the Low Power Deep Sleep (LPDS) bit if so requested */ + + if (lpds) + { + regval |= PWC_CTRL_VRSEL; + } + + putreg32(regval, AT32_PWC_CTRL); + + /* Set SLEEPDEEP bit of Cortex System Control Register */ + + regval = getreg32(NVIC_SYSCON); + regval |= NVIC_SYSCON_SLEEPDEEP; + putreg32(regval, NVIC_SYSCON); + + /* Sleep until the wakeup interrupt or event occurs */ + +#ifdef CONFIG_PM_WFE + /* Mode: SLEEP + Entry with WFE */ + + asm("wfe"); +#else + /* Mode: SLEEP + Entry with WFI */ + + asm("wfi"); +#endif + return OK; +} diff --git a/arch/arm/src/at32/at32_pwm.c b/arch/arm/src/at32/at32_pwm.c new file mode 100644 index 0000000000..0a5855c9b3 --- /dev/null +++ b/arch/arm/src/at32/at32_pwm.c @@ -0,0 +1,4505 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_pwm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32_pwm.h" +#include "at32_rcc.h" +#include "at32_gpio.h" + +/* This module then only compiles if there is at least one enabled timer + * intended for use with the PWM upper half driver. + * + * It implements support for both: + * 1. AT32 TIMER IP version 1 - F43x + */ + +#ifdef CONFIG_AT32_PWM + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* PWM/Timer Definitions ****************************************************/ + +/* The following definitions are used to identify the various time types. + * There are some differences in timer types across AT32 families: + * - TIM2 is 16-bit timer for F43x + * - TIM5 is 16-bit timer for F43x + */ + +#define TIMTYPE_BASIC 0 /* Basic timers (no outputs) */ +#define TIMTYPE_GENERAL16 1 /* General 16-bit timers (up, down, up/down)*/ +#define TIMTYPE_COUNTUP16 2 /* General 16-bit count-up timers */ +#define TIMTYPE_COUNTUP16_N 3 /* General 16-bit count-up timers with + * complementary outptus + */ +#define TIMTYPE_GENERAL32 4 /* General 32-bit timers (up, down, up/down)*/ +#define TIMTYPE_ADVANCED 5 /* Advanced timers */ + +#define TIMTYPE_TIM1 TIMTYPE_ADVANCED +#define TIMTYPE_TIM2 TIMTYPE_GENERAL32 +#define TIMTYPE_TIM3 TIMTYPE_GENERAL16 +#define TIMTYPE_TIM4 TIMTYPE_GENERAL16 +#define TIMTYPE_TIM5 TIMTYPE_GENERAL32 +#define TIMTYPE_TIM6 TIMTYPE_BASIC +#define TIMTYPE_TIM7 TIMTYPE_BASIC +#define TIMTYPE_TIM8 TIMTYPE_ADVANCED +#define TIMTYPE_TIM9 TIMTYPE_COUNTUP16 +#define TIMTYPE_TIM10 TIMTYPE_COUNTUP16 +#define TIMTYPE_TIM11 TIMTYPE_COUNTUP16 +#define TIMTYPE_TIM12 TIMTYPE_COUNTUP16 +#define TIMTYPE_TIM13 TIMTYPE_COUNTUP16 +#define TIMTYPE_TIM14 TIMTYPE_COUNTUP16 +#define TIMTYPE_TIM20 TIMTYPE_ADVANCED + +/* Timer clock source, RCC EN offset, enable bit, + * RCC RST offset, reset bit to use + * + * TODO: simplify this and move somewhere else. + */ + +# define TIMCLK_TIM1 AT32_APB2_TIM1_CLKIN +# define TIMRCCEN_TIM1 AT32_CRM_APB2EN +# define TIMEN_TIM1 CRM_APB2EN_TMR1EN +# define TIMRCCRST_TIM1 AT32_CRM_APB2RST +# define TIMRST_TIM1 CRM_APB2RST_TMR1RST + +# define TIMCLK_TIM2 AT32_APB1_TIM2_CLKIN +# define TIMRCCEN_TIM2 AT32_CRM_APB1EN +# define TIMEN_TIM2 CRM_APB1EN_TMR2EN +# define TIMRCCRST_TIM2 AT32_CRM_APB1RST +# define TIMRST_TIM2 CRM_APB1RST_TMR2RST + +# define TIMCLK_TIM3 AT32_APB1_TIM3_CLKIN +# define TIMRCCEN_TIM3 AT32_CRM_APB1EN +# define TIMEN_TIM3 CRM_APB1EN_TMR3EN +# define TIMRCCRST_TIM3 AT32_CRM_APB1RST +# define TIMRST_TIM3 CRM_APB1RST_TMR3RST + +# define TIMCLK_TIM4 AT32_APB1_TIM4_CLKIN +# define TIMRCCEN_TIM4 AT32_CRM_APB1EN +# define TIMEN_TIM4 CRM_APB1EN_TMR4EN +# define TIMRCCRST_TIM4 AT32_CRM_APB1RST +# define TIMRST_TIM4 CRM_APB1RST_TMR4RST + +# define TIMCLK_TIM5 AT32_APB1_TIM5_CLKIN +# define TIMRCCEN_TIM5 AT32_CRM_APB1EN +# define TIMEN_TIM5 CRM_APB1EN_TMR5EN +# define TIMRCCRST_TIM5 AT32_CRM_APB1RST +# define TIMRST_TIM5 CRM_APB1RST_TMR5RST + +# define TIMCLK_TIM8 AT32_APB2_TIM8_CLKIN +# define TIMRCCEN_TIM8 AT32_CRM_APB2EN +# define TIMEN_TIM8 CRM_APB2EN_TMR8EN +# define TIMRCCRST_TIM8 AT32_CRM_APB2RST +# define TIMRST_TIM8 CRM_APB2RST_TMR8RST + +# define TIMCLK_TIM9 AT32_APB2_TIM9_CLKIN +# define TIMRCCEN_TIM9 AT32_CRM_APB2EN +# define TIMEN_TIM9 CRM_APB2EN_TMR9EN +# define TIMRCCRST_TIM9 AT32_CRM_APB2RST +# define TIMRST_TIM9 CRM_APB2RST_TMR9RST + +# define TIMCLK_TIM10 AT32_APB2_TIM10_CLKIN +# define TIMRCCEN_TIM10 AT32_CRM_APB2EN +# define TIMEN_TIM10 CRM_APB2EN_TMR10EN +# define TIMRCCRST_TIM10 AT32_CRM_APB2RST +# define TIMRST_TIM10 CRM_APB2RST_TMR10RST + +# define TIMCLK_TIM11 AT32_APB2_TIM11_CLKIN +# define TIMRCCEN_TIM11 AT32_CRM_APB2EN +# define TIMEN_TIM11 CRM_APB2EN_TMR11EN +# define TIMRCCRST_TIM11 AT32_CRM_APB2RST +# define TIMRST_TIM11 CRM_APB2RST_TMR11RST + +# define TIMCLK_TIM12 AT32_APB1_TIM12_CLKIN +# define TIMRCCEN_TIM12 AT32_CRM_APB1EN +# define TIMEN_TIM12 CRM_APB1EN_TMR12EN +# define TIMRCCRST_TIM12 AT32_CRM_APB1RST +# define TIMRST_TIM12 CRM_APB1RST_TMR12RST + +# define TIMCLK_TIM13 AT32_APB1_TIM13_CLKIN +# define TIMRCCEN_TIM13 AT32_CRM_APB1EN +# define TIMEN_TIM13 CRM_APB1EN_TMR13EN +# define TIMRCCRST_TIM13 AT32_CRM_APB1RST +# define TIMRST_TIM13 CRM_APB1RST_TMR13RST + +# define TIMCLK_TIM14 AT32_APB1_TIM14_CLKIN +# define TIMRCCEN_TIM14 AT32_CRM_APB1EN +# define TIMEN_TIM14 CRM_APB1EN_TMR14EN +# define TIMRCCRST_TIM14 AT32_CRM_APB1RST +# define TIMRST_TIM14 CRM_APB1RST_TMR14RST + +# define TIMCLK_TIM20 AT32_APB2_TIM20_CLKIN +# define TIMRCCEN_TIM20 AT32_CRM_APB2EN +# define TIMEN_TIM20 CRM_APB2EN_TMR20EN +# define TIMRCCRST_TIM20 AT32_CRM_APB2RST +# define TIMRST_TIM20 CRM_APB2RST_TMR20RST + +/* Default GPIO pins state */ + +#define PINCFG_DEFAULT (GPIO_INPUT | GPIO_FLOAT) + +/* Advanced Timer support + */ + +#if defined(CONFIG_AT32_TIM1_PWM) || defined(CONFIG_AT32_TIM8_PWM) || \ + defined(CONFIG_AT32_TIM20_PWM) +# define HAVE_ADVTIM +#else +# undef HAVE_ADVTIM +#endif + +/* Pulsecount support */ + +#ifdef CONFIG_PWM_PULSECOUNT +# ifndef HAVE_ADVTIM +# error "PWM_PULSECOUNT requires HAVE_ADVTIM" +# endif +# if defined(CONFIG_AT32_TIM1_PWM) || defined(CONFIG_AT32_TIM8_PWM) +# define HAVE_PWM_INTERRUPT +# endif +#endif + +/* TRGO/TRGO2 support */ + +#ifdef CONFIG_AT32_PWM_TRGO +# define HAVE_TRGO +#endif + +/* Break support */ + +#if defined(CONFIG_AT32_TIM1_BREAK1) || defined(CONFIG_AT32_TIM1_BREAK2) || \ + defined(CONFIG_AT32_TIM8_BREAK1) || defined(CONFIG_AT32_TIM8_BREAK2) || \ + defined(CONFIG_AT32_TIM20_BREAK1) || defined(CONFIG_AT32_TIM20_BREAK2) +# defined HAVE_BREAK +#endif + +/* Debug ********************************************************************/ + +#ifdef CONFIG_DEBUG_PWM_INFO +# define pwm_dumpgpio(p,m) at32_dumpgpio(p,m) +#else +# define pwm_dumpgpio(p,m) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* PWM output configuration */ + +struct at32_pwm_out_s +{ + uint8_t in_use:1; /* Output in use */ + uint8_t pol:1; /* Polarity. Default: positive */ + uint8_t idle:1; /* Idle state. Default: inactive */ + uint8_t _res:5; /* Reserved */ + uint32_t pincfg; /* Output pin configuration */ +}; + +/* PWM break configuration */ + +#ifdef HAVE_BREAK +struct at32_pwm_break_s +{ + uint8_t en1:1; /* Break 1 enable */ + uint8_t pol1:1; /* Break 1 polarity */ + uint8_t _res:6; /* Reserved */ +#ifdef HAVE_IP_TIMERS_V2 + uint8_t en2:1; /* Break 2 enable */ + uint8_t pol2:1; /* Break 2 polarity */ + uint8_t flt2:6; /* Break 2 filter */ +#endif +}; +#endif + +/* PWM channel configuration */ + +struct at32_pwmchan_s +{ + uint8_t channel:4; /* Timer output channel: {1,..4} */ + uint8_t mode:4; /* PWM channel mode (see at32_pwm_chanmode_e) */ + struct at32_pwm_out_s out1; /* PWM output configuration */ +#ifdef HAVE_BREAK + struct at32_pwm_break_s brk; /* PWM break configuration */ +#endif +#ifdef HAVE_PWM_COMPLEMENTARY + struct at32_pwm_out_s out2; /* PWM complementary output configuration */ +#endif +}; + +/* This structure represents the state of one PWM timer */ + +struct at32_pwmtimer_s +{ + const struct pwm_ops_s *ops; /* PWM operations */ +#ifdef CONFIG_AT32_PWM_LL_OPS + const struct at32_pwm_ops_s *llops; /* Low-level PWM ops */ +#endif + struct at32_pwmchan_s *channels; /* Channels configuration */ + uint8_t timid:5; /* Timer ID {1,...,17} */ + uint8_t chan_num:3; /* Number of configured channels */ + uint8_t timtype:3; /* See the TIMTYPE_* definitions */ + uint8_t mode:3; /* Timer mode (see at32_pwm_tim_mode_e) */ + uint8_t lock:2; /* Lock configuration */ + uint8_t t_dts:3; /* Clock division for t_DTS */ + uint8_t _res:5; /* Reserved */ +#ifdef HAVE_PWM_COMPLEMENTARY + uint8_t deadtime; /* Dead-time value */ +#endif +#ifdef HAVE_TRGO + uint8_t trgo; /* TRGO configuration: + * 4 LSB = TRGO, 4 MSB = TRGO2 + */ +#endif +#ifdef CONFIG_PWM_PULSECOUNT + uint8_t irq; /* Timer update IRQ */ + uint8_t prev; /* The previous value of the RCR (pre-loaded) */ + uint8_t curr; /* The current value of the RCR (pre-loaded) */ + uint32_t count; /* Remaining pulse count */ +#endif + uint32_t frequency; /* Current frequency setting */ + uint32_t base; /* The base address of the timer */ + uint32_t pclk; /* The frequency of the peripheral + * clock that drives the timer module + */ +#ifdef CONFIG_PWM_PULSECOUNT + void *handle; /* Handle used for upper-half callback */ +#endif +}; + +/**************************************************************************** + * Static Function Prototypes + ****************************************************************************/ + +/* Register access */ + +static uint32_t pwm_getreg(struct at32_pwmtimer_s *priv, int offset); +static void pwm_putreg(struct at32_pwmtimer_s *priv, int offset, + uint32_t value); +static void pwm_modifyreg(struct at32_pwmtimer_s *priv, uint32_t offset, + uint32_t clearbits, uint32_t setbits); + +#ifdef CONFIG_DEBUG_PWM_INFO +static void pwm_dumpregs(struct pwm_lowerhalf_s *dev, + const char *msg); +#else +# define pwm_dumpregs(priv,msg) +#endif + +/* Timer management */ + +static int pwm_frequency_update(struct pwm_lowerhalf_s *dev, + uint32_t frequency); +static int pwm_mode_configure(struct pwm_lowerhalf_s *dev, + uint8_t channel, uint32_t mode); +static int pwm_timer_configure(struct at32_pwmtimer_s *priv); +static int pwm_output_configure(struct at32_pwmtimer_s *priv, + struct at32_pwmchan_s *chan); +static int pwm_outputs_enable(struct pwm_lowerhalf_s *dev, + uint16_t outputs, bool state); +static int pwm_soft_update(struct pwm_lowerhalf_s *dev); +static int pwm_soft_break(struct pwm_lowerhalf_s *dev, bool state); +static int pwm_ccr_update(struct pwm_lowerhalf_s *dev, uint8_t index, + uint32_t ccr); +static int pwm_arr_update(struct pwm_lowerhalf_s *dev, uint32_t arr); +static uint32_t pwm_arr_get(struct pwm_lowerhalf_s *dev); +static int pwm_duty_update(struct pwm_lowerhalf_s *dev, uint8_t channel, + ub16_t duty); +static int pwm_timer_enable(struct pwm_lowerhalf_s *dev, bool state); + +#ifdef HAVE_ADVTIM +static int pwm_break_dt_configure(struct at32_pwmtimer_s *priv); +#endif +#ifdef HAVE_TRGO +static int pwm_trgo_configure(struct pwm_lowerhalf_s *dev, + uint8_t trgo); +#endif +#if defined(HAVE_PWM_COMPLEMENTARY) && defined(CONFIG_AT32_PWM_LL_OPS) +static int pwm_deadtime_update(struct pwm_lowerhalf_s *dev, uint8_t dt); +#endif +#ifdef CONFIG_AT32_PWM_LL_OPS +static uint32_t pwm_ccr_get(struct pwm_lowerhalf_s *dev, uint8_t index); +static uint16_t pwm_rcr_get(struct pwm_lowerhalf_s *dev); +#endif +#ifdef HAVE_ADVTIM +static int pwm_rcr_update(struct pwm_lowerhalf_s *dev, uint16_t rcr); +#endif + +#ifdef CONFIG_PWM_PULSECOUNT +static int pwm_pulsecount_configure(struct pwm_lowerhalf_s *dev); +#else +static int pwm_configure(struct pwm_lowerhalf_s *dev); +#endif +#ifdef CONFIG_PWM_PULSECOUNT +static int pwm_pulsecount_timer(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info); +#endif +static int pwm_timer(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info); +#ifdef HAVE_PWM_INTERRUPT +static int pwm_interrupt(struct pwm_lowerhalf_s *dev); +# ifdef CONFIG_AT32_TIM1_PWM +static int pwm_tim1interrupt(int irq, void *context, void *arg); +# endif +# ifdef CONFIG_AT32_TIM8_PWM +static int pwm_tim8interrupt(int irq, void *context, void *arg); +# endif +# ifdef CONFIG_AT32_TIM20_PWM +static int pwm_tim20interrupt(int irq, void *context, void *arg); +# endif +static uint8_t pwm_pulsecount(uint32_t count); +#endif + +/* PWM driver methods */ + +static int pwm_setup(struct pwm_lowerhalf_s *dev); +static int pwm_shutdown(struct pwm_lowerhalf_s *dev); + +#ifdef CONFIG_PWM_PULSECOUNT +static int pwm_start_pulsecount(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info, + void *handle); +#endif +static int pwm_start(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info); + +static int pwm_stop(struct pwm_lowerhalf_s *dev); +static int pwm_ioctl(struct pwm_lowerhalf_s *dev, + int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This is the list of lower half PWM driver methods used by the upper half + * driver. + */ + +static const struct pwm_ops_s g_pwmops = +{ + .setup = pwm_setup, + .shutdown = pwm_shutdown, +#ifdef CONFIG_PWM_PULSECOUNT + .start = pwm_start_pulsecount, +#else + .start = pwm_start, +#endif + .stop = pwm_stop, + .ioctl = pwm_ioctl, +}; + +#ifdef CONFIG_AT32_PWM_LL_OPS +static const struct at32_pwm_ops_s g_llpwmops = +{ + .configure = pwm_configure, + .soft_break = pwm_soft_break, + .ccr_update = pwm_ccr_update, + .mode_update = pwm_mode_configure, + .ccr_get = pwm_ccr_get, + .arr_update = pwm_arr_update, + .arr_get = pwm_arr_get, +#ifdef HAVE_ADVTIM + .rcr_update = pwm_rcr_update, +#endif + .rcr_get = pwm_rcr_get, +#ifdef HAVE_TRGO + .trgo_set = pwm_trgo_configure, +#endif + .outputs_enable = pwm_outputs_enable, + .soft_update = pwm_soft_update, + .freq_update = pwm_frequency_update, + .tim_enable = pwm_timer_enable, +# ifdef CONFIG_DEBUG_PWM_INFO + .dump_regs = pwm_dumpregs, +# endif +# ifdef HAVE_PWM_COMPLEMENTARY + .dt_update = pwm_deadtime_update, +# endif +}; +#endif + +#ifdef CONFIG_AT32_TIM1_PWM + +static struct at32_pwmchan_s g_pwm1channels[] = +{ + /* TIM1 has 4 channels, 4 complementary */ + +#ifdef CONFIG_AT32_TIM1_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM1_CH1MODE, +#ifdef HAVE_BREAK + .brk = + { +#ifdef CONFIG_AT32_TIM1_BREAK1 + .en1 = 1, + .pol1 = CONFIG_AT32_TIM1_BRK1POL, +#endif +#ifdef CONFIG_AT32_TIM1_BREAK2 + .en2 = 1, + .pol2 = CONFIG_AT32_TIM1_BRK2POL, + .flt2 = CONFIG_AT32_TIM1_BRK2FLT, +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM1_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM1_CH1POL, + .idle = CONFIG_AT32_TIM1_CH1IDLE, + .pincfg = PWM_TIM1_CH1CFG, + }, +#endif +#ifdef CONFIG_AT32_TIM1_CH1NOUT + .out2 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM1_CH1NPOL, + .idle = CONFIG_AT32_TIM1_CH1NIDLE, + .pincfg = PWM_TIM1_CH1NCFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM1_CHANNEL2 + { + .channel = 2, + .mode = CONFIG_AT32_TIM1_CH2MODE, +#ifdef CONFIG_AT32_TIM1_CH2OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM1_CH2POL, + .idle = CONFIG_AT32_TIM1_CH2IDLE, + .pincfg = PWM_TIM1_CH2CFG, + }, +#endif +#ifdef CONFIG_AT32_TIM1_CH2NOUT + .out2 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM1_CH2NPOL, + .idle = CONFIG_AT32_TIM1_CH2NIDLE, + .pincfg = PWM_TIM1_CH2NCFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM1_CHANNEL3 + { + .channel = 3, + .mode = CONFIG_AT32_TIM1_CH3MODE, +#ifdef CONFIG_AT32_TIM1_CH3OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM1_CH3POL, + .idle = CONFIG_AT32_TIM1_CH3IDLE, + .pincfg = PWM_TIM1_CH3CFG, + }, +#endif +#ifdef CONFIG_AT32_TIM1_CH3NOUT + .out2 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM1_CH3NPOL, + .idle = CONFIG_AT32_TIM1_CH3NIDLE, + .pincfg = PWM_TIM1_CH3NCFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM1_CHANNEL4 + { + .channel = 4, + .mode = CONFIG_AT32_TIM1_CH4MODE, +#ifdef CONFIG_AT32_TIM1_CH4OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM1_CH4POL, + .idle = CONFIG_AT32_TIM1_CH4IDLE, + .pincfg = PWM_TIM1_CH4CFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM1_CHANNEL5 + { + .channel = 5, + .mode = CONFIG_AT32_TIM1_CH5MODE, +#ifdef CONFIG_AT32_TIM1_CH5OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM1_CH5POL, + .idle = CONFIG_AT32_TIM1_CH5IDLE, + .pincfg = 0, /* Not available externally */ + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM1_CHANNEL6 + { + .channel = 6, + .mode = CONFIG_AT32_TIM1_CH6MODE, +#ifdef CONFIG_AT32_TIM1_CH6OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM1_CH6POL, + .idle = CONFIG_AT32_TIM1_CH6IDLE, + .pincfg = 0, /* Not available externally */ + } +#endif + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm1dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 1, + .chan_num = PWM_TIM1_NCHANNELS, + .channels = g_pwm1channels, + .timtype = TIMTYPE_TIM1, + .mode = CONFIG_AT32_TIM1_MODE, + .lock = CONFIG_AT32_TIM1_LOCK, + .t_dts = CONFIG_AT32_TIM1_TDTS, +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = CONFIG_AT32_TIM1_DEADTIME, +#endif +#if defined(HAVE_TRGO) && defined(AT32_TIM1_TRGO) + .trgo = AT32_TIM1_TRGO, +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM1UP, +#endif + .base = AT32_TMR1_BASE, + .pclk = TIMCLK_TIM1, +}; +#endif /* CONFIG_AT32_TIM1_PWM */ + +#ifdef CONFIG_AT32_TIM2_PWM + +static struct at32_pwmchan_s g_pwm2channels[] = +{ + /* TIM2 has 4 channels */ + +#ifdef CONFIG_AT32_TIM2_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM2_CH1MODE, +#ifdef CONFIG_AT32_TIM2_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM2_CH1POL, + .idle = CONFIG_AT32_TIM2_CH1IDLE, + .pincfg = PWM_TIM2_CH1CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM2_CHANNEL2 + { + .channel = 2, + .mode = CONFIG_AT32_TIM2_CH2MODE, +#ifdef CONFIG_AT32_TIM2_CH2OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM2_CH2POL, + .idle = CONFIG_AT32_TIM2_CH2IDLE, + .pincfg = PWM_TIM2_CH2CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM2_CHANNEL3 + { + .channel = 3, + .mode = CONFIG_AT32_TIM2_CH3MODE, +#ifdef CONFIG_AT32_TIM2_CH3OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM2_CH3POL, + .idle = CONFIG_AT32_TIM2_CH3IDLE, + .pincfg = PWM_TIM2_CH3CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM2_CHANNEL4 + { + .channel = 4, + .mode = CONFIG_AT32_TIM2_CH4MODE, +#ifdef CONFIG_AT32_TIM2_CH4OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM2_CH4POL, + .idle = CONFIG_AT32_TIM2_CH4IDLE, + .pincfg = PWM_TIM2_CH4CFG, + } +#endif + /* No complementary outputs */ + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm2dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 2, + .chan_num = PWM_TIM2_NCHANNELS, + .channels = g_pwm2channels, + .timtype = TIMTYPE_TIM2, + .mode = CONFIG_AT32_TIM2_MODE, + .lock = 0, /* No lock */ + .t_dts = 0, /* No t_dts */ +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = 0, /* No deadtime */ +#endif +#if defined(HAVE_TRGO) && defined(AT32_TIM2_TRGO) + .trgo = AT32_TIM2_TRGO, +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM2, +#endif + .base = AT32_TMR2_BASE, + .pclk = TIMCLK_TIM2, +}; +#endif /* CONFIG_AT32_TIM2_PWM */ + +#ifdef CONFIG_AT32_TIM3_PWM + +static struct at32_pwmchan_s g_pwm3channels[] = +{ + /* TIM3 has 4 channels */ + +#ifdef CONFIG_AT32_TIM3_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM3_CH1MODE, +#ifdef CONFIG_AT32_TIM3_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM3_CH1POL, + .idle = CONFIG_AT32_TIM3_CH1IDLE, + .pincfg = PWM_TIM3_CH1CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM3_CHANNEL2 + { + .channel = 2, + .mode = CONFIG_AT32_TIM3_CH2MODE, +#ifdef CONFIG_AT32_TIM3_CH2OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM3_CH2POL, + .idle = CONFIG_AT32_TIM3_CH2IDLE, + .pincfg = PWM_TIM3_CH2CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM3_CHANNEL3 + { + .channel = 3, + .mode = CONFIG_AT32_TIM3_CH3MODE, +#ifdef CONFIG_AT32_TIM3_CH3OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM3_CH3POL, + .idle = CONFIG_AT32_TIM3_CH3IDLE, + .pincfg = PWM_TIM3_CH3CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM3_CHANNEL4 + { + .channel = 4, + .mode = CONFIG_AT32_TIM3_CH4MODE, +#ifdef CONFIG_AT32_TIM3_CH4OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM3_CH4POL, + .idle = CONFIG_AT32_TIM3_CH4IDLE, + .pincfg = PWM_TIM3_CH4CFG, + } +#endif + /* No complementary outputs */ + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm3dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 3, + .chan_num = PWM_TIM3_NCHANNELS, + .channels = g_pwm3channels, + .timtype = TIMTYPE_TIM3, + .mode = CONFIG_AT32_TIM3_MODE, + .lock = 0, /* No lock */ + .t_dts = 0, /* No t_dts */ +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = 0, /* No deadtime */ +#endif +#if defined(HAVE_TRGO) && defined(AT32_TIM3_TRGO) + .trgo = AT32_TIM3_TRGO, +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM3, +#endif + .base = AT32_TMR3_BASE, + .pclk = TIMCLK_TIM3, +}; +#endif /* CONFIG_AT32_TIM3_PWM */ + +#ifdef CONFIG_AT32_TIM4_PWM + +static struct at32_pwmchan_s g_pwm4channels[] = +{ + /* TIM4 has 4 channels */ + +#ifdef CONFIG_AT32_TIM4_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM4_CH1MODE, +#ifdef CONFIG_AT32_TIM4_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM4_CH1POL, + .idle = CONFIG_AT32_TIM4_CH1IDLE, + .pincfg = PWM_TIM4_CH1CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM4_CHANNEL2 + { + .channel = 2, + .mode = CONFIG_AT32_TIM4_CH2MODE, +#ifdef CONFIG_AT32_TIM4_CH2OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM4_CH2POL, + .idle = CONFIG_AT32_TIM4_CH2IDLE, + .pincfg = PWM_TIM4_CH2CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM4_CHANNEL3 + { + .channel = 3, + .mode = CONFIG_AT32_TIM4_CH3MODE, +#ifdef CONFIG_AT32_TIM4_CH3OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM4_CH3POL, + .idle = CONFIG_AT32_TIM4_CH3IDLE, + .pincfg = PWM_TIM4_CH3CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM4_CHANNEL4 + { + .channel = 4, + .mode = CONFIG_AT32_TIM4_CH4MODE, +#ifdef CONFIG_AT32_TIM4_CH4OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM4_CH4POL, + .idle = CONFIG_AT32_TIM4_CH4IDLE, + .pincfg = PWM_TIM4_CH4CFG, + } +#endif + /* No complementary outputs */ + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm4dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 4, + .chan_num = PWM_TIM4_NCHANNELS, + .channels = g_pwm4channels, + .timtype = TIMTYPE_TIM4, + .mode = CONFIG_AT32_TIM4_MODE, + .lock = 0, /* No lock */ + .t_dts = 0, /* No t_dts */ +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = 0, /* No deadtime */ +#endif +#if defined(HAVE_TRGO) && defined(AT32_TIM4_TRGO) + .trgo = AT32_TIM4_TRGO, +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM4, +#endif + .base = AT32_TMR4_BASE, + .pclk = TIMCLK_TIM4, +}; +#endif /* CONFIG_AT32_TIM4_PWM */ + +#ifdef CONFIG_AT32_TIM5_PWM + +static struct at32_pwmchan_s g_pwm5channels[] = +{ + /* TIM5 has 4 channels */ + +#ifdef CONFIG_AT32_TIM5_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM5_CH1MODE, +#ifdef CONFIG_AT32_TIM5_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM5_CH1POL, + .idle = CONFIG_AT32_TIM5_CH1IDLE, + .pincfg = PWM_TIM5_CH1CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM5_CHANNEL2 + { + .channel = 2, + .mode = CONFIG_AT32_TIM5_CH2MODE, +#ifdef CONFIG_AT32_TIM5_CH2OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM5_CH2POL, + .idle = CONFIG_AT32_TIM5_CH2IDLE, + .pincfg = PWM_TIM5_CH2CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM5_CHANNEL3 + { + .channel = 3, + .mode = CONFIG_AT32_TIM5_CH3MODE, +#ifdef CONFIG_AT32_TIM5_CH3OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM5_CH3POL, + .idle = CONFIG_AT32_TIM5_CH3IDLE, + .pincfg = PWM_TIM5_CH3CFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM5_CHANNEL4 + { + .channel = 4, + .mode = CONFIG_AT32_TIM5_CH4MODE, +#ifdef CONFIG_AT32_TIM5_CH4OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM5_CH4POL, + .idle = CONFIG_AT32_TIM5_CH4IDLE, + .pincfg = PWM_TIM5_CH4CFG, + } +#endif + }, +#endif +}; + +static struct at32_pwmtimer_s g_pwm5dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 5, + .chan_num = PWM_TIM5_NCHANNELS, + .channels = g_pwm5channels, + .timtype = TIMTYPE_TIM5, + .mode = CONFIG_AT32_TIM5_MODE, + .lock = 0, /* No lock */ + .t_dts = 0, /* No t_dts */ +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = 0, /* No deadtime */ +#endif +#if defined(HAVE_TRGO) && defined(AT32_TIM5_TRGO) + .trgo = AT32_TIM5_TRGO, +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM5, +#endif + .base = AT32_TMR5_BASE, + .pclk = TIMCLK_TIM5, +}; +#endif /* CONFIG_AT32_TIM5_PWM */ + +#ifdef CONFIG_AT32_TIM8_PWM + +static struct at32_pwmchan_s g_pwm8channels[] = +{ + /* TIM8 has 4 channels, 4 complementary */ + +#ifdef CONFIG_AT32_TIM8_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM8_CH1MODE, +#ifdef HAVE_BREAK + .brk = + { +#ifdef CONFIG_AT32_TIM8_BREAK1 + .en1 = 1, + .pol1 = CONFIG_AT32_TIM8_BRK1POL, +#endif +#ifdef CONFIG_AT32_TIM8_BREAK2 + .en2 = 1, + .pol2 = CONFIG_AT32_TIM8_BRK2POL, + .flt2 = CONFIG_AT32_TIM8_BRK2FLT, +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM8_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM8_CH1POL, + .idle = CONFIG_AT32_TIM8_CH1IDLE, + .pincfg = PWM_TIM8_CH1CFG, + }, +#endif +#ifdef CONFIG_AT32_TIM8_CH1NOUT + .out2 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM8_CH1NPOL, + .idle = CONFIG_AT32_TIM8_CH1NIDLE, + .pincfg = PWM_TIM8_CH1NCFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM8_CHANNEL2 + { + .channel = 2, + .mode = CONFIG_AT32_TIM8_CH2MODE, +#ifdef CONFIG_AT32_TIM8_CH2OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM8_CH2POL, + .idle = CONFIG_AT32_TIM8_CH2IDLE, + .pincfg = PWM_TIM8_CH2CFG, + }, +#endif +#ifdef CONFIG_AT32_TIM8_CH2NOUT + .out2 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM8_CH2NPOL, + .idle = CONFIG_AT32_TIM8_CH2NIDLE, + .pincfg = PWM_TIM8_CH2NCFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM8_CHANNEL3 + { + .channel = 3, + .mode = CONFIG_AT32_TIM8_CH3MODE, +#ifdef CONFIG_AT32_TIM8_CH3OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM8_CH3POL, + .idle = CONFIG_AT32_TIM8_CH3IDLE, + .pincfg = PWM_TIM8_CH3CFG, + }, +#endif +#ifdef CONFIG_AT32_TIM8_CH3NOUT + .out2 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM8_CH3NPOL, + .idle = CONFIG_AT32_TIM8_CH3NIDLE, + .pincfg = PWM_TIM8_CH3NCFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM8_CHANNEL4 + { + .channel = 4, + .mode = CONFIG_AT32_TIM8_CH4MODE, +#ifdef CONFIG_AT32_TIM8_CH4OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM8_CH4POL, + .idle = CONFIG_AT32_TIM8_CH4IDLE, + .pincfg = PWM_TIM8_CH4CFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM8_CHANNEL5 + { + .channel = 5, + .mode = CONFIG_AT32_TIM8_CH5MODE, +#ifdef CONFIG_AT32_TIM8_CH5OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM8_CH5POL, + .idle = CONFIG_AT32_TIM8_CH5IDLE, + .pincfg = 0, /* Not available externally */ + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM8_CHANNEL6 + { + .channel = 6, + .mode = CONFIG_AT32_TIM8_CH6MODE, +#ifdef CONFIG_AT32_TIM8_CH6OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM8_CH6POL, + .idle = CONFIG_AT32_TIM8_CH6IDLE, + .pincfg = 0, /* Not available externally */ + } +#endif + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm8dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 8, + .chan_num = PWM_TIM8_NCHANNELS, + .channels = g_pwm8channels, + .timtype = TIMTYPE_TIM8, + .mode = CONFIG_AT32_TIM8_MODE, + .lock = CONFIG_AT32_TIM8_LOCK, + .t_dts = CONFIG_AT32_TIM8_TDTS, +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = CONFIG_AT32_TIM8_DEADTIME, +#endif +#if defined(HAVE_TRGO) && defined(AT32_TIM8_TRGO) + .trgo = AT32_TIM8_TRGO, +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM8UP, +#endif + .base = AT32_TMR8_BASE, + .pclk = TIMCLK_TIM8, +}; +#endif /* CONFIG_AT32_TIM8_PWM */ + +#ifdef CONFIG_AT32_TIM9_PWM + +static struct at32_pwmchan_s g_pwm9channels[] = +{ + /* TIM9 has 2 channels */ + +#ifdef CONFIG_AT32_TIM9_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM9_CH1MODE, +#ifdef CONFIG_AT32_TIM9_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM9_CH1POL, + .idle = CONFIG_AT32_TIM9_CH1IDLE, + .pincfg = PWM_TIM9_CH1CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM9_CHANNEL2 + { + .channel = 2, + .mode = CONFIG_AT32_TIM9_CH2MODE, +#ifdef CONFIG_AT32_TIM9_CH2OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM9_CH2POL, + .idle = CONFIG_AT32_TIM9_CH2IDLE, + .pincfg = PWM_TIM9_CH2CFG, + } +#endif + /* No complementary outputs */ + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm9dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 9, + .chan_num = PWM_TIM9_NCHANNELS, + .channels = g_pwm9channels, + .timtype = TIMTYPE_TIM9, + .mode = AT32_TIMMODE_COUNTUP, + .lock = 0, /* No lock */ + .t_dts = 0, /* No t_dts */ +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = 0, /* No deadtime */ +#endif +#if defined(HAVE_TRGO) + .trgo = 0, /* TRGO not supported for TIM9 */ +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM9, +#endif + .base = AT32_TMR9_BASE, + .pclk = TIMCLK_TIM9, +}; +#endif /* CONFIG_AT32_TIM9_PWM */ + +#ifdef CONFIG_AT32_TIM10_PWM + +static struct at32_pwmchan_s g_pwm10channels[] = +{ + /* TIM10 has 1 channel */ + +#ifdef CONFIG_AT32_TIM10_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM10_CH1MODE, +#ifdef CONFIG_AT32_TIM10_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM10_CH1POL, + .idle = CONFIG_AT32_TIM10_CH1IDLE, + .pincfg = PWM_TIM10_CH1CFG, + } +#endif + /* No complementary outputs */ + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm10dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 10, + .chan_num = PWM_TIM10_NCHANNELS, + .channels = g_pwm10channels, + .timtype = TIMTYPE_TIM10, + .mode = AT32_TIMMODE_COUNTUP, + .lock = 0, /* No lock */ + .t_dts = 0, /* No t_dts */ +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = 0, /* No deadtime */ +#endif +#if defined(HAVE_TRGO) + .trgo = 0, /* TRGO not supported for TIM10 */ +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM10, +#endif + .base = AT32_TMR10_BASE, + .pclk = TIMCLK_TIM10, +}; +#endif /* CONFIG_AT32_TIM10_PWM */ + +#ifdef CONFIG_AT32_TIM11_PWM + +static struct at32_pwmchan_s g_pwm11channels[] = +{ + /* TIM11 has 1 channel */ + +#ifdef CONFIG_AT32_TIM11_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM11_CH1MODE, +#ifdef CONFIG_AT32_TIM11_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM11_CH1POL, + .idle = CONFIG_AT32_TIM11_CH1IDLE, + .pincfg = PWM_TIM11_CH1CFG, + } +#endif + /* No complementary outputs */ + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm11dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 11, + .chan_num = PWM_TIM11_NCHANNELS, + .channels = g_pwm11channels, + .timtype = TIMTYPE_TIM11, + .mode = AT32_TIMMODE_COUNTUP, + .lock = 0, /* No lock */ + .t_dts = 0, /* No t_dts */ +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = 0, /* No deadtime */ +#endif +#if defined(HAVE_TRGO) + .trgo = 0, /* TRGO not supported for TIM11 */ +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM11, +#endif + .base = AT32_TMR11_BASE, + .pclk = TIMCLK_TIM11, +}; +#endif /* CONFIG_AT32_TIM11_PWM */ + +#ifdef CONFIG_AT32_TIM12_PWM + +static struct at32_pwmchan_s g_pwm12channels[] = +{ + /* TIM12 has 2 channels */ + +#ifdef CONFIG_AT32_TIM12_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM12_CH1MODE, +#ifdef CONFIG_AT32_TIM12_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM12_CH1POL, + .idle = CONFIG_AT32_TIM12_CH1IDLE, + .pincfg = PWM_TIM12_CH1CFG, + } +#endif + /* No complementary outputs */ + }, +#endif +#ifdef CONFIG_AT32_TIM12_CHANNEL2 + { + .channel = 2, + .mode = CONFIG_AT32_TIM12_CH2MODE, +#ifdef CONFIG_AT32_TIM12_CH2OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM12_CH2POL, + .idle = CONFIG_AT32_TIM12_CH2IDLE, + .pincfg = PWM_TIM12_CH2CFG, + } +#endif + /* No complementary outputs */ + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm12dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 12, + .chan_num = PWM_TIM12_NCHANNELS, + .channels = g_pwm12channels, + .timtype = TIMTYPE_TIM12, + .mode = AT32_TIMMODE_COUNTUP, + .lock = 0, /* No lock */ + .t_dts = 0, /* No t_dts */ +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = 0, /* No deadtime */ +#endif +#if defined(HAVE_TRGO) + .trgo = 0, /* TRGO not supported for TIM12 */ +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM12, +#endif + .base = AT32_TMR12_BASE, + .pclk = TIMCLK_TIM12, +}; +#endif /* CONFIG_AT32_TIM12_PWM */ + +#ifdef CONFIG_AT32_TIM13_PWM + +static struct at32_pwmchan_s g_pwm13channels[] = +{ + /* TIM13 has 1 channel */ + +#ifdef CONFIG_AT32_TIM13_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM13_CH1MODE, +#ifdef CONFIG_AT32_TIM13_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM13_CH1POL, + .idle = CONFIG_AT32_TIM13_CH1IDLE, + .pincfg = PWM_TIM13_CH1CFG, + } +#endif + /* No complementary outputs */ + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm13dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 13, + .chan_num = PWM_TIM13_NCHANNELS, + .channels = g_pwm13channels, + .timtype = TIMTYPE_TIM13, + .mode = AT32_TIMMODE_COUNTUP, + .lock = 0, /* No lock */ + .t_dts = 0, /* No t_dts */ +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = 0, /* No deadtime */ +#endif +#if defined(HAVE_TRGO) + .trgo = 0, /* TRGO not supported for TIM13 */ +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM13, +#endif + .base = AT32_TMR13_BASE, + .pclk = TIMCLK_TIM13, +}; +#endif /* CONFIG_AT32_TIM13_PWM */ + +#ifdef CONFIG_AT32_TIM14_PWM + +static struct at32_pwmchan_s g_pwm14channels[] = +{ + /* TIM14 has 1 channel */ + +#ifdef CONFIG_AT32_TIM14_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM14_CH1MODE, +#ifdef CONFIG_AT32_TIM14_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM14_CH1POL, + .idle = CONFIG_AT32_TIM14_CH1IDLE, + .pincfg = PWM_TIM14_CH1CFG, + } +#endif + /* No complementary outputs */ + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm14dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 14, + .chan_num = PWM_TIM14_NCHANNELS, + .channels = g_pwm14channels, + .timtype = TIMTYPE_TIM14, + .mode = AT32_TIMMODE_COUNTUP, + .lock = 0, /* No lock */ + .t_dts = 0, /* No t_dts */ +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = 0, /* No deadtime */ +#endif +#if defined(HAVE_TRGO) + .trgo = 0, /* TRGO not supported for TIM14 */ +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM14, +#endif + .base = AT32_TMR14_BASE, + .pclk = TIMCLK_TIM14, +}; +#endif /* CONFIG_AT32_TIM14_PWM */ + +#ifdef CONFIG_AT32_TIM20_PWM + +static struct at32_pwmchan_s g_pwm20channels[] = +{ + /* TIM20 has 4 channels, 4 complementary */ + +#ifdef CONFIG_AT32_TIM20_CHANNEL1 + { + .channel = 1, + .mode = CONFIG_AT32_TIM20_CH1MODE, +#ifdef HAVE_BREAK + .brk = + { +#ifdef CONFIG_AT32_TIM20_BREAK1 + .en1 = 1, + .pol1 = CONFIG_AT32_TIM20_BRK1POL, +#endif +#ifdef CONFIG_AT32_TIM20_BREAK2 + .en2 = 1, + .pol2 = CONFIG_AT32_TIM20_BRK2POL, + .flt2 = CONFIG_AT32_TIM20_BRK2FLT, +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM20_CH1OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM20_CH1POL, + .idle = CONFIG_AT32_TIM20_CH1IDLE, + .pincfg = PWM_TIM20_CH1CFG, + }, +#endif +#ifdef CONFIG_AT32_TIM20_CH1NOUT + .out2 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM20_CH1NPOL, + .idle = CONFIG_AT32_TIM20_CH1NIDLE, + .pincfg = PWM_TIM20_CH1NCFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM20_CHANNEL2 + { + .channel = 2, + .mode = CONFIG_AT32_TIM20_CH2MODE, +#ifdef CONFIG_AT32_TIM20_CH2OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM20_CH2POL, + .idle = CONFIG_AT32_TIM20_CH2IDLE, + .pincfg = PWM_TIM20_CH2CFG, + }, +#endif +#ifdef CONFIG_AT32_TIM20_CH2NOUT + .out2 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM20_CH2NPOL, + .idle = CONFIG_AT32_TIM20_CH2NIDLE, + .pincfg = PWM_TIM20_CH2NCFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM20_CHANNEL3 + { + .channel = 3, + .mode = CONFIG_AT32_TIM20_CH3MODE, +#ifdef CONFIG_AT32_TIM20_CH3OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM20_CH3POL, + .idle = CONFIG_AT32_TIM20_CH3IDLE, + .pincfg = PWM_TIM20_CH3CFG, + }, +#endif +#ifdef CONFIG_AT32_TIM20_CH3NOUT + .out2 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM20_CH3NPOL, + .idle = CONFIG_AT32_TIM20_CH3NIDLE, + .pincfg = PWM_TIM20_CH3NCFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM20_CHANNEL4 + { + .channel = 4, + .mode = CONFIG_AT32_TIM20_CH4MODE, +#ifdef CONFIG_AT32_TIM20_CH4OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM20_CH4POL, + .idle = CONFIG_AT32_TIM20_CH4IDLE, + .pincfg = PWM_TIM20_CH4CFG, + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM20_CHANNEL5 + { + .channel = 5, + .mode = CONFIG_AT32_TIM20_CH5MODE, +#ifdef CONFIG_AT32_TIM20_CH5OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM20_CH5POL, + .idle = CONFIG_AT32_TIM20_CH5IDLE, + .pincfg = 0, /* Not available externally */ + } +#endif + }, +#endif +#ifdef CONFIG_AT32_TIM20_CHANNEL6 + { + .channel = 6, + .mode = CONFIG_AT32_TIM20_CH6MODE, +#ifdef CONFIG_AT32_TIM20_CH6OUT + .out1 = + { + .in_use = 1, + .pol = CONFIG_AT32_TIM20_CH6POL, + .idle = CONFIG_AT32_TIM20_CH6IDLE, + .pincfg = 0, /* Not available externally */ + } +#endif + } +#endif +}; + +static struct at32_pwmtimer_s g_pwm20dev = +{ + .ops = &g_pwmops, +#ifdef CONFIG_AT32_PWM_LL_OPS + .llops = &g_llpwmops, +#endif + .timid = 20, + .chan_num = PWM_TIM20_NCHANNELS, + .channels = g_pwm20channels, + .timtype = TIMTYPE_TIM20, + .mode = CONFIG_AT32_TIM20_MODE, + .lock = CONFIG_AT32_TIM20_LOCK, + .t_dts = CONFIG_AT32_TIM20_TDTS, +#ifdef HAVE_PWM_COMPLEMENTARY + .deadtime = CONFIG_AT32_TIM20_DEADTIME, +#endif +#if defined(HAVE_TRGO) && defined(AT32_TIM20_TRGO) + .trgo = AT32_TIM20_TRGO, +#endif +#ifdef CONFIG_PWM_PULSECOUNT + .irq = AT32_IRQ_TIM20UP, +#endif + .base = AT32_TMR20_BASE, + .pclk = TIMCLK_TIM20, +}; +#endif /* CONFIG_AT32_TIM20_PWM */ + +/* TODO: support for TIM19,20,21,22 */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pwm_reg_is_32bit + ****************************************************************************/ + +static bool pwm_reg_is_32bit(uint8_t timtype, uint32_t offset) +{ + bool ret = false; + + if (timtype == TIMTYPE_GENERAL32) + { + if (offset == AT32_GTIM_CNT_OFFSET || + offset == AT32_GTIM_ARR_OFFSET || + offset == AT32_GTIM_CCR1_OFFSET || + offset == AT32_GTIM_CCR2_OFFSET || + offset == AT32_GTIM_CCR3_OFFSET || + offset == AT32_GTIM_CCR4_OFFSET) + { + ret = true; + } + } +#ifdef HAVE_IP_TIMERS_V2 + else if (timtype == TIMTYPE_ADVANCED) + { + if (offset == AT32_ATIM_CR2_OFFSET || + offset == AT32_ATIM_CCMR1_OFFSET || + offset == AT32_ATIM_CCMR2_OFFSET || + offset == AT32_ATIM_CCER_OFFSET || + offset == AT32_ATIM_BDTR_OFFSET || + offset == AT32_ATIM_CCMR3_OFFSET || + offset == AT32_ATIM_CCR5_OFFSET) + { + ret = true; + } + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: pwm_getreg + * + * Description: + * Read the value of an PWM timer register + * + * Input Parameters: + * priv - A reference to the PWM block status + * offset - The offset to the register to read + * + * Returned Value: + * The current contents of the specified register + * + ****************************************************************************/ + +static uint32_t pwm_getreg(struct at32_pwmtimer_s *priv, int offset) +{ + uint32_t retval = 0; + + if (pwm_reg_is_32bit(priv->timtype, offset) == true) + { + /* 32-bit register */ + + retval = getreg32(priv->base + offset); + } + else + { + /* 16-bit register */ + + retval = getreg16(priv->base + offset); + } + + /* Return 32-bit value */ + + return retval; +} + +/**************************************************************************** + * Name: pwm_putreg + * + * Description: + * Read the value of an PWM timer register + * + * Input Parameters: + * priv - A reference to the PWM block status + * offset - The offset to the register to read + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void pwm_putreg(struct at32_pwmtimer_s *priv, int offset, + uint32_t value) +{ + if (pwm_reg_is_32bit(priv->timtype, offset) == true) + { + /* 32-bit register */ + + putreg32(value, priv->base + offset); + } + else + { + /* 16-bit register */ + + putreg16((uint16_t)value, priv->base + offset); + } +} + +/**************************************************************************** + * Name: pwm_modifyreg + * + * Description: + * Modify PWM register (32-bit or 16-bit) + * + * Input Parameters: + * priv - A reference to the PWM block status + * offset - The offset to the register to read + * clrbits - The bits to clear + * setbits - The bits to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void pwm_modifyreg(struct at32_pwmtimer_s *priv, uint32_t offset, + uint32_t clearbits, uint32_t setbits) +{ + if (pwm_reg_is_32bit(priv->timtype, offset) == true) + { + /* 32-bit register */ + + modifyreg32(priv->base + offset, clearbits, setbits); + } + else + { + /* 16-bit register */ + + modifyreg16(priv->base + offset, (uint16_t)clearbits, + (uint16_t)setbits); + } +} + +/**************************************************************************** + * Name: pwm_dumpregs + * + * Description: + * Dump all timer registers. + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_PWM_INFO +static void pwm_dumpregs(struct pwm_lowerhalf_s *dev, const char *msg) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + + pwminfo("%s:\n", msg); + if (priv->timid == 16 || priv->timid == 17) + { + pwminfo(" CR1: %04x CR2: %04x DIER: %04x\n", + pwm_getreg(priv, AT32_GTIM_CR1_OFFSET), + pwm_getreg(priv, AT32_GTIM_CR2_OFFSET), + pwm_getreg(priv, AT32_GTIM_DIER_OFFSET)); + } + else + { + pwminfo(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n", + pwm_getreg(priv, AT32_GTIM_CR1_OFFSET), + pwm_getreg(priv, AT32_GTIM_CR2_OFFSET), + pwm_getreg(priv, AT32_GTIM_SMCR_OFFSET), + pwm_getreg(priv, AT32_GTIM_DIER_OFFSET)); + } + + if (priv->timid >= 15 && priv->timid <= 17) + { + pwminfo(" SR: %04x EGR: %04x CCMR1: %04x\n", + pwm_getreg(priv, AT32_GTIM_SR_OFFSET), + pwm_getreg(priv, AT32_GTIM_EGR_OFFSET), + pwm_getreg(priv, AT32_GTIM_CCMR1_OFFSET)); + } + else + { + pwminfo(" SR: %04x EGR: %04x CCMR1: %04x CCMR2: %04x\n", + pwm_getreg(priv, AT32_GTIM_SR_OFFSET), + pwm_getreg(priv, AT32_GTIM_EGR_OFFSET), + pwm_getreg(priv, AT32_GTIM_CCMR1_OFFSET), + pwm_getreg(priv, AT32_GTIM_CCMR2_OFFSET)); + } + + /* REVISIT: CNT and ARR may be 32-bits wide */ + + pwminfo(" CCER: %04x CNT: %04x PSC: %04x ARR: %04x\n", + pwm_getreg(priv, AT32_GTIM_CCER_OFFSET), + pwm_getreg(priv, AT32_GTIM_CNT_OFFSET), + pwm_getreg(priv, AT32_GTIM_PSC_OFFSET), + pwm_getreg(priv, AT32_GTIM_ARR_OFFSET)); + + if (priv->timid == 1 || priv->timid == 8 || + (priv->timid >= 15 && priv->timid <= 17)) + { + pwminfo(" RCR: %04x BDTR: %04x\n", + pwm_getreg(priv, AT32_ATIM_RCR_OFFSET), + pwm_getreg(priv, AT32_ATIM_BDTR_OFFSET)); + } + + /* REVISIT: CCR1-CCR4 may be 32-bits wide */ + + if (priv->timid == 16 || priv->timid == 17) + { + pwminfo(" CCR1: %04x\n", + pwm_getreg(priv, AT32_GTIM_CCR1_OFFSET)); + } + else if (priv->timid == 15) + { + pwminfo(" CCR1: %04x CCR2: %04x\n", + pwm_getreg(priv, AT32_GTIM_CCR1_OFFSET), + pwm_getreg(priv, AT32_GTIM_CCR2_OFFSET)); + } + else + { + pwminfo(" CCR1: %04x CCR2: %04x CCR3: %04x CCR4: %04x\n", + pwm_getreg(priv, AT32_GTIM_CCR1_OFFSET), + pwm_getreg(priv, AT32_GTIM_CCR2_OFFSET), + pwm_getreg(priv, AT32_GTIM_CCR3_OFFSET), + pwm_getreg(priv, AT32_GTIM_CCR4_OFFSET)); + } + + pwminfo(" DCR: %04x DMAR: %04x\n", + pwm_getreg(priv, AT32_GTIM_DCR_OFFSET), + pwm_getreg(priv, AT32_GTIM_DMAR_OFFSET)); + +#ifdef HAVE_IP_TIMERS_V2 + if (priv->timtype == TIMTYPE_ADVANCED) + { + pwminfo(" CCMR3: %04x CCR5: %04x CCR6: %04x\n", + pwm_getreg(priv, AT32_ATIM_CCMR3_OFFSET), + pwm_getreg(priv, AT32_ATIM_CCR5_OFFSET), + pwm_getreg(priv, AT32_ATIM_CCR6_OFFSET)); + } +#endif +} +#endif + +/**************************************************************************** + * Name: pwm_ccr_update + ****************************************************************************/ + +static int pwm_ccr_update(struct pwm_lowerhalf_s *dev, uint8_t index, + uint32_t ccr) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint32_t offset = 0; + + /* Only ADV timers have CC5 and CC6 */ + +#ifdef HAVE_IP_TIMERS_V2 + if (priv->timtype != TIMTYPE_ADVANCED && (index == 5 || index == 6)) + { + pwmerr("ERROR: No such CCR: %u\n", index); + return -EINVAL; + } +#endif + + /* REVISIT: start index from 0? */ + + switch (index) + { + case AT32_PWM_CHAN1: + { + offset = AT32_GTIM_CCR1_OFFSET; + break; + } + + case AT32_PWM_CHAN2: + { + offset = AT32_GTIM_CCR2_OFFSET; + break; + } + + case AT32_PWM_CHAN3: + { + offset = AT32_GTIM_CCR3_OFFSET; + break; + } + + case AT32_PWM_CHAN4: + { + offset = AT32_GTIM_CCR4_OFFSET; + break; + } + +#ifdef HAVE_IP_TIMERS_V2 + case AT32_PWM_CHAN5: + { + offset = AT32_ATIM_CCR5_OFFSET; + break; + } + + case AT32_PWM_CHAN6: + { + offset = AT32_ATIM_CCR6_OFFSET; + break; + } +#endif + + default: + { + pwmerr("ERROR: No such CCR: %u\n", index); + return -EINVAL; + } + } + + /* Update CCR register */ + + pwm_putreg(priv, offset, ccr); + + return OK; +} + +/**************************************************************************** + * Name: pwm_ccr_get + ****************************************************************************/ + +#ifdef CONFIG_AT32_PWM_LL_OPS +static uint32_t pwm_ccr_get(struct pwm_lowerhalf_s *dev, uint8_t index) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint32_t offset = 0; + + switch (index) + { + case AT32_PWM_CHAN1: + { + offset = AT32_GTIM_CCR1_OFFSET; + break; + } + + case AT32_PWM_CHAN2: + { + offset = AT32_GTIM_CCR2_OFFSET; + break; + } + + case AT32_PWM_CHAN3: + { + offset = AT32_GTIM_CCR3_OFFSET; + break; + } + + case AT32_PWM_CHAN4: + { + offset = AT32_GTIM_CCR4_OFFSET; + break; + } + +#ifdef HAVE_IP_TIMERS_V2 + case AT32_PWM_CHAN5: + { + offset = AT32_ATIM_CCR5_OFFSET; + break; + } + + case AT32_PWM_CHAN6: + { + offset = AT32_ATIM_CCR6_OFFSET; + break; + } +#endif + + default: + { + pwmerr("ERROR: No such CCR: %u\n", index); + return -EINVAL; + } + } + + /* Return CCR register */ + + return pwm_getreg(priv, offset); +} +#endif /* CONFIG_AT32_PWM_LL_OPS */ + +/**************************************************************************** + * Name: pwm_arr_update + ****************************************************************************/ + +static int pwm_arr_update(struct pwm_lowerhalf_s *dev, uint32_t arr) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + + /* Update ARR register */ + + pwm_putreg(priv, AT32_GTIM_ARR_OFFSET, arr); + + return OK; +} + +/**************************************************************************** + * Name: pwm_arr_get + ****************************************************************************/ + +static uint32_t pwm_arr_get(struct pwm_lowerhalf_s *dev) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + + return pwm_getreg(priv, AT32_GTIM_ARR_OFFSET); +} + +#ifdef HAVE_ADVTIM +/**************************************************************************** + * Name: pwm_rcr_update + ****************************************************************************/ + +static int pwm_rcr_update(struct pwm_lowerhalf_s *dev, uint16_t rcr) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + + /* Update RCR register */ + + pwm_putreg(priv, AT32_ATIM_RCR_OFFSET, rcr); + + return OK; +} +#endif + +#ifdef CONFIG_AT32_PWM_LL_OPS +/**************************************************************************** + * Name: pwm_rcr_get + ****************************************************************************/ + +static uint16_t pwm_rcr_get(struct pwm_lowerhalf_s *dev) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + + return pwm_getreg(priv, AT32_ATIM_RCR_OFFSET); +} +#endif + +/**************************************************************************** + * Name: pwm_duty_update + * + * Description: + * Try to change only channel duty + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * channel - Channel to by updated + * duty - New duty + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_duty_update(struct pwm_lowerhalf_s *dev, uint8_t channel, + ub16_t duty) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint32_t reload = 0; + uint32_t ccr = 0; + + /* We don't want compilation warnings if no DEBUGASSERT */ + + UNUSED(priv); + + DEBUGASSERT(priv != NULL); + + pwminfo("TIM%u channel: %u duty: %08" PRIx32 "\n", + priv->timid, channel, duty); + +#ifndef CONFIG_PWM_MULTICHAN + DEBUGASSERT(channel == priv->channels[0].channel); + DEBUGASSERT(duty >= 0 && duty < uitoub16(100)); +#endif + + /* Get the reload values */ + + reload = pwm_arr_get(dev); + + /* Duty cycle: + * + * duty cycle = ccr / reload (fractional value) + */ + + ccr = b16toi(duty * reload + b16HALF); + + pwminfo("ccr: %" PRIu32 "\n", ccr); + + /* Write corresponding CCR register */ + + pwm_ccr_update(dev, channel, ccr); + + return OK; +} + +/**************************************************************************** + * Name: pwm_timer_enable + ****************************************************************************/ + +static int pwm_timer_enable(struct pwm_lowerhalf_s *dev, bool state) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + + if (state == true) + { + /* Enable timer counter */ + + pwm_modifyreg(priv, AT32_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN); + } + else + { + /* Disable timer counter */ + + pwm_modifyreg(priv, AT32_GTIM_CR1_OFFSET, GTIM_CR1_CEN, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: pwm_frequency_update + * + * Description: + * Update a PWM timer frequency + * + ****************************************************************************/ + +static int pwm_frequency_update(struct pwm_lowerhalf_s *dev, + uint32_t frequency) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint32_t reload = 0; + uint32_t timclk = 0; + uint32_t prescaler = 0; + + /* Calculate optimal values for the timer prescaler and for the timer + * reload register. If 'frequency' is the desired frequency, then + * + * reload = timclk / frequency + * timclk = pclk / presc + * + * Or, + * + * reload = pclk / presc / frequency + * + * There are many solutions to this, but the best solution will be the one + * that has the largest reload value and the smallest prescaler value. + * That is the solution that should give us the most accuracy in the timer + * control. Subject to: + * + * 0 <= presc <= 65536 + * 1 <= reload <= 65535 + * + * So presc = pclk / 65535 / frequency would be optimal. + * + * Example: + * + * pclk = 42 MHz + * frequency = 100 Hz + * + * prescaler = 42,000,000 / 65,535 / 100 + * = 6.4 (or 7 -- taking the ceiling always) + * timclk = 42,000,000 / 7 + * = 6,000,000 + * reload = 6,000,000 / 100 + * = 60,000 + */ + + prescaler = (priv->pclk / frequency + 65534) / 65535; + if (prescaler < 1) + { + prescaler = 1; + } + else if (prescaler > 65536) + { + prescaler = 65536; + } + + timclk = priv->pclk / prescaler; + + reload = timclk / frequency; + if (reload < 2) + { + reload = 1; + } + else if (reload > 65535) + { + reload = 65535; + } + else + { + reload--; + } + + pwminfo("TIM%u PCLK: %" PRIu32" frequency: %" PRIu32 + " TIMCLK: %" PRIu32 " " + "prescaler: %" PRIu32 " reload: %" PRIu32 "\n", + priv->timid, priv->pclk, frequency, timclk, prescaler, reload); + + /* Set the reload and prescaler values */ + + pwm_arr_update(dev, reload); + pwm_putreg(priv, AT32_GTIM_PSC_OFFSET, (uint16_t)(prescaler - 1)); + + return OK; +} + +/**************************************************************************** + * Name: pwm_timer_configure + * + * Description: + * Initial configuration for PWM timer + * + ****************************************************************************/ + +static int pwm_timer_configure(struct at32_pwmtimer_s *priv) +{ + uint16_t cr1 = 0; + int ret = OK; + + /* Set up the timer CR1 register: + * + * 1,8 CKD[1:0] ARPE CMS[1:0] DIR OPM URS UDIS CEN + * 2-5 CKD[1:0] ARPE CMS DIR OPM URS UDIS CEN + * 6-7 ARPE OPM URS UDIS CEN + * 9-14 CKD[1:0] ARPE URS UDIS CEN + * 15-17 CKD[1:0] ARPE OPM URS UDIS CEN + */ + + cr1 = pwm_getreg(priv, AT32_GTIM_CR1_OFFSET); + + /* Set the counter mode for the advanced timers (1,8) and most general + * purpose timers (all 2-5, but not 9-17), i.e., all but TIMTYPE_COUNTUP16 + * and TIMTYPE_BASIC + */ + + if (priv->timtype != TIMTYPE_BASIC && priv->timtype != TIMTYPE_COUNTUP16) + { + /* Select the Counter Mode: + * + * GTIM_CR1_EDGE: The counter counts up or down depending on the + * direction bit (DIR). + * GTIM_CR1_CENTER1, GTIM_CR1_CENTER2, GTIM_CR1_CENTER3: The counter + * counts up then down. + * GTIM_CR1_DIR: 0: count up, 1: count down + */ + + cr1 &= ~(GTIM_CR1_DIR | GTIM_CR1_CMS_MASK); + + switch (priv->mode) + { + case AT32_TIMMODE_COUNTUP: + { + cr1 |= GTIM_CR1_EDGE; + break; + } + + case AT32_TIMMODE_COUNTDOWN: + { + cr1 |= GTIM_CR1_EDGE | GTIM_CR1_DIR; + break; + } + + case AT32_TIMMODE_CENTER1: + { + cr1 |= GTIM_CR1_CENTER1; + break; + } + + case AT32_TIMMODE_CENTER2: + { + cr1 |= GTIM_CR1_CENTER2; + break; + } + + case AT32_TIMMODE_CENTER3: + { + cr1 |= GTIM_CR1_CENTER3; + break; + } + + default: + { + pwmerr("ERROR: No such timer mode: %u\n", + (unsigned int)priv->mode); + ret = -EINVAL; + goto errout; + } + } + } + + /* Enable ARR Preload + * TODO: this should be configurable + */ + + cr1 |= GTIM_CR1_ARPE; + + /* Write CR1 */ + + pwm_putreg(priv, AT32_GTIM_CR1_OFFSET, cr1); + +errout: + return ret; +} + +/**************************************************************************** + * Name: pwm_mode_configure + * + * Description: + * Configure a PWM mode for given channel + * + ****************************************************************************/ + +static int pwm_mode_configure(struct pwm_lowerhalf_s *dev, + uint8_t channel, uint32_t mode) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint32_t chanmode = 0; + uint32_t ocmode = 0; + uint32_t ccmr = 0; + uint32_t offset = 0; + int ret = OK; +#ifdef HAVE_IP_TIMERS_V2 + bool ocmbit = false; +#endif + +#ifdef HAVE_IP_TIMERS_V2 + /* Only advanced timers have channels 5-6 */ + + if (channel > 4 && priv->timtype != TIMTYPE_ADVANCED) + { + pwmerr("ERROR: No such channel: %u\n", channel); + ret = -EINVAL; + goto errout; + } +#endif + + /* Get channel mode + * TODO: configurable preload for CCxR + */ + + switch (mode) + { + case AT32_CHANMODE_FRZN: + { + chanmode = GTIM_CCMR_MODE_FRZN; + break; + } + + case AT32_CHANMODE_CHACT: + { + chanmode = GTIM_CCMR_MODE_CHACT; + break; + } + + case AT32_CHANMODE_CHINACT: + { + chanmode = GTIM_CCMR_MODE_CHINACT; + break; + } + + case AT32_CHANMODE_OCREFTOG: + { + chanmode = GTIM_CCMR_MODE_OCREFTOG; + break; + } + + case AT32_CHANMODE_OCREFLO: + { + chanmode = GTIM_CCMR_MODE_OCREFLO; + break; + } + + case AT32_CHANMODE_OCREFHI: + { + chanmode = GTIM_CCMR_MODE_OCREFHI; + break; + } + + case AT32_CHANMODE_PWM1: + { + chanmode = GTIM_CCMR_MODE_PWM1; + break; + } + + case AT32_CHANMODE_PWM2: + { + chanmode = GTIM_CCMR_MODE_PWM2; + break; + } + +#ifdef HAVE_IP_TIMERS_V2 + case AT32_CHANMODE_COMBINED1: + { + chanmode = ATIM_CCMR_MODE_COMBINED1; + ocmbit = true; + break; + } + + case AT32_CHANMODE_COMBINED2: + { + chanmode = ATIM_CCMR_MODE_COMBINED2; + ocmbit = true; + break; + } + + case AT32_CHANMODE_ASYMMETRIC1: + { + chanmode = ATIM_CCMR_MODE_ASYMMETRIC1; + ocmbit = true; + break; + } + + case AT32_CHANMODE_ASYMMETRIC2: + { + chanmode = ATIM_CCMR_MODE_ASYMMETRIC2; + ocmbit = true; + break; + } +#endif + + default: + { + pwmerr("ERROR: No such mode: %u\n", (unsigned int)mode); + ret = -EINVAL; + goto errout; + } + } + + /* Get CCMR offset */ + + switch (channel) + { + case AT32_PWM_CHAN1: + case AT32_PWM_CHAN2: + { + offset = AT32_GTIM_CCMR1_OFFSET; + break; + } + + case AT32_PWM_CHAN3: + case AT32_PWM_CHAN4: + { + offset = AT32_GTIM_CCMR2_OFFSET; + break; + } + +#ifdef HAVE_IP_TIMERS_V2 + case AT32_PWM_CHAN5: + case AT32_PWM_CHAN6: + { + offset = AT32_ATIM_CCMR3_OFFSET; + break; + } +#endif + + default: + { + pwmerr("ERROR: No such channel: %u\n", channel); + ret = -EINVAL; + goto errout; + } + } + + /* Get current registers */ + + ccmr = pwm_getreg(priv, offset); + + /* PWM mode configuration. + * NOTE: The CCMRx registers are identical if the channels are outputs. + */ + + switch (channel) + { + /* Configure channel 1/3/5 */ + + case AT32_PWM_CHAN1: + case AT32_PWM_CHAN3: +#ifdef HAVE_IP_TIMERS_V2 + case AT32_PWM_CHAN5: +#endif + { + /* Reset current channel 1/3/5 mode configuration */ + + ccmr &= ~(ATIM_CCMR1_CC1S_MASK | ATIM_CCMR1_OC1M_MASK | + ATIM_CCMR1_OC1PE); + + /* Configure CC1/3/5 as output */ + + ocmode |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT); + + /* Configure Compare 1/3/5 mode */ + + ocmode |= (chanmode << ATIM_CCMR1_OC1M_SHIFT); + + /* Enable CCR1/3/5 preload */ + + ocmode |= ATIM_CCMR1_OC1PE; + +#ifdef HAVE_IP_TIMERS_V2 + /* Reset current OC bit */ + + ccmr &= ~(ATIM_CCMR1_OC1M); + + /* Set an additional OC1/3/5M bit */ + + if (ocmbit) + { + ocmode |= ATIM_CCMR1_OC1M; + } +#endif + break; + } + + /* Configure channel 2/4/6 */ + + case AT32_PWM_CHAN2: + case AT32_PWM_CHAN4: +#ifdef HAVE_IP_TIMERS_V2 + case AT32_PWM_CHAN6: +#endif + { + /* Reset current channel 2/4/6 mode configuration */ + + ccmr &= ~(ATIM_CCMR1_CC2S_MASK | ATIM_CCMR1_OC2M_MASK | + ATIM_CCMR1_OC2PE); + + /* Configure CC2/4/6 as output */ + + ocmode |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT); + + /* Configure Compare 2/4/6 mode */ + + ocmode |= (chanmode << ATIM_CCMR1_OC2M_SHIFT); + + /* Enable CCR2/4/6 preload */ + + ocmode |= ATIM_CCMR1_OC2PE; + +#ifdef HAVE_IP_TIMERS_V2 + /* Reset current OC bit */ + + ccmr &= ~(ATIM_CCMR1_OC2M); + + /* Set an additioneal OC2/4/6M bit */ + + if (ocmbit) + { + ocmode |= ATIM_CCMR1_OC2M; + } +#endif + break; + } + } + + /* Set the selected output compare mode */ + + ccmr |= ocmode; + + /* Write CCMRx registers */ + + pwm_putreg(priv, offset, ccmr); + +errout: + return ret; +} + +/**************************************************************************** + * Name: pwm_output_configure + * + * Description: + * Configure PWM output for given channel + * + ****************************************************************************/ + +static int pwm_output_configure(struct at32_pwmtimer_s *priv, + struct at32_pwmchan_s *chan) +{ + uint32_t cr2 = 0; + uint32_t ccer = 0; + uint8_t channel = 0; + + /* Get channel */ + + channel = chan->channel; + + /* Get current registers state */ + + cr2 = pwm_getreg(priv, AT32_GTIM_CR2_OFFSET); + ccer = pwm_getreg(priv, AT32_GTIM_CCER_OFFSET); + + /* | OISx/OISxN | IDLE | for ADVANCED and COUNTUP16 | CR2 register + * | CCxP/CCxNP | POL | all PWM timers | CCER register + */ + + /* Configure output polarity (all PWM timers) */ + + if (chan->out1.pol == AT32_POL_NEG) + { + ccer |= (GTIM_CCER_CC1P << ((channel - 1) * 4)); + } + else + { + ccer &= ~(GTIM_CCER_CC1P << ((channel - 1) * 4)); + } + +#ifdef HAVE_ADVTIM + if (priv->timtype == TIMTYPE_ADVANCED || + priv->timtype == TIMTYPE_COUNTUP16_N) + { + /* Configure output IDLE State */ + + if (chan->out1.idle == AT32_IDLE_ACTIVE) + { + cr2 |= (ATIM_CR2_OIS1 << ((channel - 1) * 2)); + } + else + { + cr2 &= ~(ATIM_CR2_OIS1 << ((channel - 1) * 2)); + } + +#ifdef HAVE_PWM_COMPLEMENTARY + /* Configure complementary output IDLE state */ + + if (chan->out2.idle == AT32_IDLE_ACTIVE) + { + cr2 |= (ATIM_CR2_OIS1N << ((channel - 1) * 2)); + } + else + { + cr2 &= ~(ATIM_CR2_OIS1N << ((channel - 1) * 2)); + } + + /* Configure complementary output polarity */ + + if (chan->out2.pol == AT32_POL_NEG) + { + ccer |= (ATIM_CCER_CC1NP << ((channel - 1) * 4)); + } + else + { + ccer &= ~(ATIM_CCER_CC1NP << ((channel - 1) * 4)); + } +#endif /* HAVE_PWM_COMPLEMENTARY */ + +#ifdef HAVE_IP_TIMERS_V2 + /* TODO: OIS5 and OIS6 */ + + cr2 &= ~(ATIM_CR2_OIS5 | ATIM_CR2_OIS6); + + /* TODO: CC5P and CC6P */ + + ccer &= ~(ATIM_CCER_CC5P | ATIM_CCER_CC6P); +#endif /* HAVE_IP_TIMERS_V2 */ + } +#ifdef HAVE_GTIM_CCXNP + else +#endif /* HAVE_GTIM_CCXNP */ +#endif /* HAVE_ADVTIM */ +#ifdef HAVE_GTIM_CCXNP + { + /* CCxNP must be cleared if not ADVANCED timer. + * + * REVISIT: not all families have CCxNP bits for GTIM, + * which causes an ugly condition above + */ + + ccer &= ~(GTIM_CCER_CC1NP << ((channel - 1) * 4)); + } +#endif /* HAVE_GTIM_CCXNP */ + + /* Write registers */ + + pwm_modifyreg(priv, AT32_GTIM_CR2_OFFSET, 0, cr2); + pwm_modifyreg(priv, AT32_GTIM_CCER_OFFSET, 0, ccer); + + return OK; +} + +/**************************************************************************** + * Name: pwm_outputs_enable + * + * Description: + * Enable/disable given timer PWM outputs. + * + * NOTE: This is bulk operation - we can enable/disable many outputs + * at one time + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * outputs - outputs to set (look at enum at32_chan_e in at32_pwm.h) + * state - Enable/disable operation + * + ****************************************************************************/ + +static int pwm_outputs_enable(struct pwm_lowerhalf_s *dev, + uint16_t outputs, bool state) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint32_t ccer = 0; + uint32_t regval = 0; + + /* Get curren register state */ + + ccer = pwm_getreg(priv, AT32_GTIM_CCER_OFFSET); + + /* Get outputs configuration */ + + regval |= ((outputs & AT32_PWM_OUT1) ? GTIM_CCER_CC1E : 0); + regval |= ((outputs & AT32_PWM_OUT1N) ? ATIM_CCER_CC1NE : 0); + regval |= ((outputs & AT32_PWM_OUT2) ? GTIM_CCER_CC2E : 0); + regval |= ((outputs & AT32_PWM_OUT2N) ? ATIM_CCER_CC2NE : 0); + regval |= ((outputs & AT32_PWM_OUT3) ? GTIM_CCER_CC3E : 0); + regval |= ((outputs & AT32_PWM_OUT3N) ? ATIM_CCER_CC3NE : 0); + regval |= ((outputs & AT32_PWM_OUT4) ? GTIM_CCER_CC4E : 0); + + /* NOTE: CC4N doesn't exist, but some docs show configuration bits for it */ + +#ifdef HAVE_IP_TIMERS_V2 + regval |= ((outputs & AT32_PWM_OUT5) ? ATIM_CCER_CC5E : 0); + regval |= ((outputs & AT32_PWM_OUT6) ? ATIM_CCER_CC6E : 0); +#endif + + if (state == true) + { + /* Enable outpus - set bits */ + + ccer |= regval; + } + else + { + /* Disable outputs - reset bits */ + + ccer &= ~regval; + } + + /* Write register */ + + pwm_putreg(priv, AT32_GTIM_CCER_OFFSET, ccer); + + return OK; +} + +#if defined(HAVE_PWM_COMPLEMENTARY) && defined(CONFIG_AT32_PWM_LL_OPS) + +/**************************************************************************** + * Name: pwm_deadtime_update + ****************************************************************************/ + +static int pwm_deadtime_update(struct pwm_lowerhalf_s *dev, uint8_t dt) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint32_t bdtr = 0; + int ret = OK; + + /* Check if locked */ + + if (priv->lock > 0) + { + ret = -EACCES; + goto errout; + } + + /* Get current register state */ + + bdtr = pwm_getreg(priv, AT32_ATIM_BDTR_OFFSET); + + /* TODO: check if BDTR not locked */ + + /* Update deadtime */ + + bdtr &= ~(ATIM_BDTR_DTG_MASK); + bdtr |= (dt << ATIM_BDTR_DTG_SHIFT); + + /* Write BDTR register */ + + pwm_putreg(priv, AT32_ATIM_BDTR_OFFSET, bdtr); + +errout: + return ret; +} +#endif + +#ifdef HAVE_TRGO +/**************************************************************************** + * Name: pwm_trgo_configure + * + * Description: + * Confiugre an output synchronisation event for PWM timer (TRGO/TRGO2) + * + ****************************************************************************/ + +static int pwm_trgo_configure(struct pwm_lowerhalf_s *dev, + uint8_t trgo) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint32_t cr2 = 0; + + /* Configure TRGO (4 LSB in trgo) */ + + cr2 |= (((trgo >> 0) & 0x0f) << ATIM_CR2_MMS_SHIFT) & ATIM_CR2_MMS_MASK; + +#ifdef HAVE_IP_TIMERS_V2 + /* Configure TRGO2 (4 MSB in trgo) */ + + cr2 |= (((trgo >> 4) & 0x0f) << ATIM_CR2_MMS2_SHIFT) & ATIM_CR2_MMS2_MASK; +#endif + + /* Write register */ + + pwm_modifyreg(priv, AT32_GTIM_CR2_OFFSET, 0, cr2); + + return OK; +} +#endif + +/**************************************************************************** + * Name: pwm_soft_update + * + * Description: + * Generate an software update event + * + ****************************************************************************/ + +static int pwm_soft_update(struct pwm_lowerhalf_s *dev) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + + pwm_putreg(priv, AT32_GTIM_EGR_OFFSET, GTIM_EGR_UG); + + return OK; +} + +/**************************************************************************** + * Name: pwm_soft_break + * + * Description: + * Generate an software break event + * + * Outputs are enabled if state is false. + * Outputs are disabled if state is true. + * + * NOTE: only timers with complementary outputs have BDTR register and + * support software break. + * + ****************************************************************************/ + +static int pwm_soft_break(struct pwm_lowerhalf_s *dev, bool state) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + + if (state == true) + { + /* Reset MOE bit */ + + pwm_modifyreg(priv, AT32_ATIM_BDTR_OFFSET, ATIM_BDTR_MOE, 0); + } + else + { + /* Set MOE bit */ + + pwm_modifyreg(priv, AT32_ATIM_BDTR_OFFSET, 0, ATIM_BDTR_MOE); + } + + return OK; +} + +/**************************************************************************** + * Name: pwm_outputs_from_channels + * + * Description: + * Get enabled outputs configuration from the PWM timer state + * + ****************************************************************************/ + +static uint16_t pwm_outputs_from_channels(struct at32_pwmtimer_s *priv) +{ + uint16_t outputs = 0; + uint8_t channel = 0; + uint8_t i = 0; + + for (i = 0; i < priv->chan_num; i += 1) + { + /* Get channel */ + + channel = priv->channels[i].channel; + + /* Set outputs if channel configured */ + + if (channel != 0) + { + /* Enable output if confiugred */ + + if (priv->channels[i].out1.in_use == 1) + { + outputs |= (AT32_PWM_OUT1 << ((channel - 1) * 2)); + } + +#ifdef HAVE_PWM_COMPLEMENTARY + /* Enable complementary output if configured */ + + if (priv->channels[i].out2.in_use == 1) + { + outputs |= (AT32_PWM_OUT1N << ((channel - 1) * 2)); + } +#endif + } + } + + return outputs; +} + +#ifdef HAVE_ADVTIM + +/**************************************************************************** + * Name: pwm_break_dt_configure + * + * Description: + * Configure break and deadtime + * + * NOTE: we have to configure all BDTR registers at once due to possible + * lock configuration + * + ****************************************************************************/ + +static int pwm_break_dt_configure(struct at32_pwmtimer_s *priv) +{ + uint32_t bdtr = 0; + + /* Set the clock division to zero for all (but the basic timers, but there + * should be no basic timers in this context + */ + + pwm_modifyreg(priv, AT32_GTIM_CR1_OFFSET, GTIM_CR1_CKD_MASK, + priv->t_dts << GTIM_CR1_CKD_SHIFT); + +#ifdef HAVE_PWM_COMPLEMENTARY + /* Initialize deadtime */ + + bdtr |= (priv->deadtime << ATIM_BDTR_DTG_SHIFT); +#endif + +#ifdef HAVE_BREAK + /* Configure Break 1 */ + + if (priv->brk.en1 == 1) + { + /* Enable Break 1 */ + + bdtr |= ATIM_BDTR_BKE; + + /* Set Break 1 polarity */ + + bdtr |= (priv->brk.pol1 == AT32_POL_NEG ? ATIM_BDTR_BKP : 0); + } + +#ifdef HAVE_IP_TIMERS_V2 + /* Configure Break 1 */ + + if (priv->brk.en2 == 1) + { + /* Enable Break 2 */ + + bdtr |= ATIM_BDTR_BK2E; + + /* Set Break 2 polarity */ + + bdtr |= (priv->brk.pol2 == AT32_POL_NEG ? ATIM_BDTR_BK2P : 0); + + /* Configure BRK2 filter */ + + bdtr |= (priv->brk.flt2 << ATIM_BDTR_BK2F_SHIFT); + } +#endif /* HAVE_IP_TIMERS_V2 */ +#endif /* HAVE_BREAK */ + + /* Clear the OSSI and OSSR bits in the BDTR register. + * + * REVISIT: this should be configurable + */ + + bdtr &= ~(ATIM_BDTR_OSSI | ATIM_BDTR_OSSR); + + /* Configure lock */ + + bdtr |= priv->lock << ATIM_BDTR_LOCK_SHIFT; + + /* Write BDTR register at once */ + + pwm_putreg(priv, AT32_ATIM_BDTR_OFFSET, bdtr); + + return OK; +} +#endif + +#ifdef CONFIG_PWM_PULSECOUNT + +/**************************************************************************** + * Name: pwm_pulsecount_configure + * + * Description: + * Configure PWM timer in PULSECOUNT mode + * + ****************************************************************************/ + +static int pwm_pulsecount_configure(struct pwm_lowerhalf_s *dev) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint16_t outputs = 0; + uint8_t j = 0; + int ret = OK; + + /* NOTE: leave timer counter disabled and all outputs disabled! */ + + /* Disable the timer until we get it configured */ + + pwm_timer_enable(dev, false); + + /* Get configured outputs */ + + outputs = pwm_outputs_from_channels(priv); + + /* REVISIT: Disable outputs */ + + ret = pwm_outputs_enable(dev, outputs, false); + if (ret < 0) + { + goto errout; + } + + /* Initial timer configuration */ + + ret = pwm_timer_configure(priv); + if (ret < 0) + { + goto errout; + } + + /* Configure break and deadtime register */ + + ret = pwm_break_dt_configure(priv); + if (ret < 0) + { + goto errout; + } + + /* Disable software break (enable outputs) */ + + ret = pwm_soft_break(dev, false); + if (ret < 0) + { + goto errout; + } + +#ifdef HAVE_TRGO + /* Configure TRGO/TRGO2 */ + + ret = pwm_trgo_configure(dev, priv->trgo); + if (ret < 0) + { + goto errout; + } +#endif + + /* Configure timer channels */ + + for (j = 0; j < priv->chan_num; j++) + { + /* Skip channel if not in use */ + + if (priv->channels[j].channel != 0) + { + /* Update PWM mode */ + + pwm_mode_configure(dev, priv->channels[j].channel, + priv->channels[j].mode); + + /* PWM outputs configuration */ + + pwm_output_configure(priv, &priv->channels[j]); + } + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: pwm_pulsecount_timer + * + * Description: + * (Re-)initialize the timer resources and start the pulsed output + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * info - A reference to the characteristics of the pulsed output + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * TODO: PWM_PULSECOUNT should be configurable for each timer instance + * TODO: PULSECOUNT doesn't work with MULTICHAN at this moment + * + ****************************************************************************/ + +static int pwm_pulsecount_timer(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + ub16_t duty = 0; + uint8_t channel = 0; + uint16_t outputs = 0; + int ret = OK; + + /* If we got here it means that timer instance support pulsecount mode! */ + + DEBUGASSERT(priv != NULL && info != NULL); + + pwminfo("TIM%u channel: %u frequency: %" PRIx32 " duty: %08" PRIx32 + " count: %" PRIx32 "\n", + priv->timid, priv->channels[0].channel, info->frequency, + info->duty, info->count); + + DEBUGASSERT(info->frequency > 0); + + /* Channel specific setup */ + + duty = info->duty; + channel = priv->channels[0].channel; + + /* Disable all interrupts and DMA requests, clear all pending status */ + + pwm_putreg(priv, AT32_GTIM_DIER_OFFSET, 0); + pwm_putreg(priv, AT32_GTIM_SR_OFFSET, 0); + + /* Set timer frequency */ + + ret = pwm_frequency_update(dev, info->frequency); + if (ret < 0) + { + goto errout; + } + + /* Update duty cycle */ + + ret = pwm_duty_update(dev, channel, duty); + if (ret < 0) + { + goto errout; + } + + /* If a non-zero repetition count has been selected, then set the + * repetition counter to the count-1 (pwm_pulsecount_start() has already + * assured us that the count value is within range). + */ + + if (info->count > 0) + { + /* Save the remaining count and the number of counts that will have + * elapsed on the first interrupt. + */ + + /* If the first interrupt occurs at the end end of the first + * repetition count, then the count will be the same as the RCR + * value. + */ + + priv->prev = pwm_pulsecount(info->count); + pwm_rcr_update(dev, priv->prev - 1); + + /* Generate an update event to reload the prescaler. This should + * preload the RCR into active repetition counter. + */ + + pwm_soft_update(dev); + + /* Now set the value of the RCR that will be loaded on the next + * update event. + */ + + priv->count = info->count; + priv->curr = pwm_pulsecount(info->count - priv->prev); + pwm_rcr_update(dev, priv->curr - 1); + } + + /* Otherwise, just clear the repetition counter */ + + else + { + /* Set the repetition counter to zero */ + + pwm_rcr_update(dev, 0); + + /* Generate an update event to reload the prescaler */ + + pwm_soft_update(dev); + } + + /* Get configured outputs */ + + outputs = pwm_outputs_from_channels(priv); + + /* Enable output */ + + ret = pwm_outputs_enable(dev, outputs, true); + if (ret < 0) + { + goto errout; + } + + /* Setup update interrupt. If info->count is > 0, then we can be + * assured that pwm_pulsecount_start() has already verified: (1) that this + * is an advanced timer, and that (2) the repetition count is within range. + */ + + if (info->count > 0) + { + /* Clear all pending interrupts and enable the update interrupt. */ + + pwm_putreg(priv, AT32_GTIM_SR_OFFSET, 0); + pwm_putreg(priv, AT32_GTIM_DIER_OFFSET, GTIM_DIER_UIE); + + /* Enable the timer */ + + pwm_timer_enable(dev, true); + + /* And enable timer interrupts at the NVIC */ + + up_enable_irq(priv->irq); + } + + pwm_dumpregs(dev, "After starting"); + +errout: + return ret; +} + +#endif /* CONFIG_PWM_PULSECOUNT */ + +/**************************************************************************** + * Name: pwm_configure + * + * Description: + * Configure PWM timer in normal mode (no PULSECOUNT) + * + ****************************************************************************/ + +static int pwm_configure(struct pwm_lowerhalf_s *dev) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint16_t outputs = 0; + uint8_t j = 0; + int ret = OK; + + /* NOTE: leave timer counter disabled and all outputs disabled! */ + + /* Get configured outputs */ + + outputs = pwm_outputs_from_channels(priv); + + /* Disable outputs */ + + ret = pwm_outputs_enable(dev, outputs, false); + if (ret < 0) + { + goto errout; + } + + /* Disable the timer until we get it configured */ + + pwm_timer_enable(dev, false); + + /* Initial timer configuration */ + + ret = pwm_timer_configure(priv); + if (ret < 0) + { + goto errout; + } + + /* Some special setup for advanced timers */ + +#ifdef HAVE_ADVTIM + if (priv->timtype == TIMTYPE_ADVANCED || + priv->timtype == TIMTYPE_COUNTUP16_N) + { + /* Configure break and deadtime register */ + + ret = pwm_break_dt_configure(priv); + if (ret < 0) + { + goto errout; + } + +#ifdef HAVE_TRGO + /* Configure TRGO/TRGO2 */ + + ret = pwm_trgo_configure(dev, priv->trgo); + if (ret < 0) + { + goto errout; + } +#endif + } +#endif + + /* Configure timer channels */ + + for (j = 0; j < priv->chan_num; j++) + { + /* Skip channel if not in use */ + + if (priv->channels[j].channel != 0) + { + /* Update PWM mode */ + + ret = pwm_mode_configure(dev, priv->channels[j].channel, + priv->channels[j].mode); + if (ret < 0) + { + goto errout; + } + + /* PWM outputs configuration */ + + ret = pwm_output_configure(priv, &priv->channels[j]); + if (ret < 0) + { + goto errout; + } + } + } + + /* Disable software break at the end of the outputs configuration (enablei + * outputs). + * + * NOTE: Only timers with complementary outputs have BDTR register and + * support software break. + */ + + if (priv->timtype == TIMTYPE_ADVANCED || + priv->timtype == TIMTYPE_COUNTUP16_N) + { + ret = pwm_soft_break(dev, false); + if (ret < 0) + { + goto errout; + } + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: pwm_duty_channels_update + * + * Description: + * Update duty cycle for given channels + * + ****************************************************************************/ + +static int pwm_duty_channels_update(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint8_t channel = 0; + ub16_t duty = 0; + int ret = OK; +#ifdef CONFIG_PWM_MULTICHAN + int i = 0; + int j = 0; +#endif + +#ifdef CONFIG_PWM_MULTICHAN + for (i = 0; i < CONFIG_PWM_NCHANNELS; i++) +#endif + { +#ifdef CONFIG_PWM_MULTICHAN + /* Break the loop if all following channels are not configured */ + + if (info->channels[i].channel == -1) + { + break; + } + + duty = info->channels[i].duty; + channel = info->channels[i].channel; + + /* A value of zero means to skip this channel */ + + if (channel != 0) + { + /* Find the channel */ + + for (j = 0; j < priv->chan_num; j++) + { + if (priv->channels[j].channel == channel) + { + break; + } + } + + /* Check range */ + + if (j >= priv->chan_num) + { + pwmerr("ERROR: No such channel: %u\n", channel); + ret = -EINVAL; + goto errout; + } +#else + duty = info->duty; + channel = priv->channels[0].channel; +#endif + + /* Update duty cycle */ + + ret = pwm_duty_update(dev, channel, duty); + if (ret < 0) + { + goto errout; + } +#ifdef CONFIG_PWM_MULTICHAN + } +#endif + } + +errout: + return OK; +} + +/**************************************************************************** + * Name: pwm_timer + * + * Description: + * (Re-)initialize the timer resources and start the pulsed output + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * info - A reference to the characteristics of the pulsed output + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_timer(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint16_t outputs = 0; + int ret = OK; + + DEBUGASSERT(priv != NULL && info != NULL); + +#if defined(CONFIG_PWM_MULTICHAN) + pwminfo("TIM%u frequency: %" PRIu32 "\n", + priv->timid, info->frequency); +#else + pwminfo("TIM%u channel: %u frequency: %" PRIu32 " duty: %08" PRIx32 "\n", + priv->timid, priv->channels[0].channel, + info->frequency, info->duty); +#endif + + DEBUGASSERT(info->frequency > 0); +#ifndef CONFIG_PWM_MULTICHAN + DEBUGASSERT(info->duty >= 0 && info->duty < uitoub16(100)); +#endif + + /* TODO: what if we have pwm running and we want disable some channels ? */ + + /* Set timer frequency */ + + ret = pwm_frequency_update(dev, info->frequency); + if (ret < 0) + { + goto errout; + } + + /* Channel specific configuration */ + + ret = pwm_duty_channels_update(dev, info); + if (ret < 0) + { + goto errout; + } + + /* Set the advanced timer's repetition counter */ + +#ifdef HAVE_ADVTIM + if (priv->timtype == TIMTYPE_ADVANCED || + priv->timtype == TIMTYPE_COUNTUP16_N) + { + /* If a non-zero repetition count has been selected, then set the + * repetition counter to the count-1 (pwm_start() has already + * assured us that the count value is within range). + */ + + /* Set the repetition counter to zero */ + + pwm_rcr_update(dev, 0); + + /* Generate an update event to reload the prescaler */ + + pwm_soft_update(dev); + } + else +#endif + { + /* Generate an update event to reload the prescaler (all timers) */ + + pwm_soft_update(dev); + } + + /* Get configured outputs */ + + outputs = pwm_outputs_from_channels(priv); + + /* Enable outputs */ + + ret = pwm_outputs_enable(dev, outputs, true); + if (ret < 0) + { + goto errout; + } + + /* Just enable the timer, leaving all interrupts disabled */ + + pwm_timer_enable(dev, true); + + pwm_dumpregs(dev, "After starting"); + +errout: + return ret; +} + +#ifdef HAVE_PWM_INTERRUPT + +/**************************************************************************** + * Name: pwm_interrupt + * + * Description: + * Handle timer interrupts. + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_interrupt(struct pwm_lowerhalf_s *dev) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint16_t regval; + + /* Verify that this is an update interrupt. Nothing else is expected. */ + + regval = pwm_getreg(priv, AT32_ATIM_SR_OFFSET); + DEBUGASSERT((regval & ATIM_SR_UIF) != 0); + + /* Clear the UIF interrupt bit */ + + pwm_putreg(priv, AT32_ATIM_SR_OFFSET, (regval & ~ATIM_SR_UIF)); + + /* Calculate the new count by subtracting the number of pulses + * since the last interrupt. + */ + + if (priv->count <= priv->prev) + { + /* We are finished. Turn off the master output to stop the output as + * quickly as possible. + */ + + pwm_soft_break(dev, true); + + /* Disable first interrupts, stop and reset the timer */ + + pwm_stop(dev); + + /* Then perform the callback into the upper half driver */ + + pwm_expired(priv->handle); + + priv->handle = NULL; + priv->count = 0; + priv->prev = 0; + priv->curr = 0; + } + else + { + /* Decrement the count of pulses remaining using the number of + * pulses generated since the last interrupt. + */ + + priv->count -= priv->prev; + + /* Set up the next RCR. Set 'prev' to the value of the RCR that + * was loaded when the update occurred (just before this interrupt) + * and set 'curr' to the current value of the RCR register (which + * will bet loaded on the next update event). + */ + + priv->prev = priv->curr; + priv->curr = pwm_pulsecount(priv->count - priv->prev); + pwm_rcr_update(dev, priv->curr - 1); + } + + /* Now all of the time critical stuff is done so we can do some debug + * output. + */ + + pwminfo("Update interrupt SR: %04x prev: %u curr: %u count: %" PRIx32 "\n", + regval, priv->prev, priv->curr, priv->count); + + return OK; +} + +/**************************************************************************** + * Name: pwm_tim1/8interrupt + * + * Description: + * Handle timer 1 and 8 interrupts. + * + * Input Parameters: + * Standard NuttX interrupt inputs + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_TIM1_PWM +static int pwm_tim1interrupt(int irq, void *context, void *arg) +{ + return pwm_interrupt((struct pwm_lowerhalf_s *)&g_pwm1dev); +} +#endif /* CONFIG_AT32_TIM1_PWM */ + +#ifdef CONFIG_AT32_TIM8_PWM +static int pwm_tim8interrupt(int irq, void *context, void *arg) +{ + return pwm_interrupt((struct pwm_lowerhalf_s *)&g_pwm8dev); +} +#endif /* CONFIG_AT32_TIM8_PWM */ + +#ifdef CONFIG_AT32_TIM20_PWM +static int pwm_tim20interrupt(int irq, void *context, void *arg) +{ + return pwm_interrupt((struct pwm_lowerhalf_s *)&g_pwm20dev); +} +#endif /* CONFIG_AT32_TIM20_PWM */ + +/**************************************************************************** + * Name: pwm_pulsecount + * + * Description: + * Pick an optimal pulse count to program the RCR. + * + * Input Parameters: + * count - The total count remaining + * + * Returned Value: + * The recommended pulse count + * + ****************************************************************************/ + +static uint8_t pwm_pulsecount(uint32_t count) +{ + /* REVISIT: RCR_REP_MAX for GTIM or ATIM ? */ + + /* The the remaining pulse count is less than or equal to the maximum, the + * just return the count. + */ + + if (count <= ATIM_RCR_REP_MAX) + { + return (uint8_t)count; + } + + /* Otherwise, we have to be careful. We do not want a small number of + * counts at the end because we might have trouble responding fast enough. + * If the remaining count is less than 150% of the maximum, then return + * half of the maximum. In this case the final sequence will be between 64 + * and 128. + */ + + else if (count < (3 * ATIM_RCR_REP_MAX / 2)) + { + return (uint8_t)((ATIM_RCR_REP_MAX + 1) >> 1); + } + + /* Otherwise, return the maximum. The final count will be 64 or more */ + + else + { + return (uint8_t)ATIM_RCR_REP_MAX; + } +} +#endif /* HAVE_PWM_INTERRUPT */ + +/**************************************************************************** + * Name: pwm_set_apb_clock + * + * Description: + * Enable or disable APB clock for the timer peripheral + * + * Input Parameters: + * priv - A reference to the PWM block status + * on - Enable clock if 'on' is 'true' and disable if 'false' + * + ****************************************************************************/ + +static int pwm_set_apb_clock(struct at32_pwmtimer_s *priv, bool on) +{ + uint32_t en_bit = 0; + uint32_t regaddr = 0; + int ret = OK; + + pwminfo("timer %d clock enable: %d\n", priv->timid, on ? 1 : 0); + + /* Determine which timer to configure */ + + switch (priv->timid) + { +#ifdef CONFIG_AT32_TIM1_PWM + case 1: + { + regaddr = TIMRCCEN_TIM1; + en_bit = TIMEN_TIM1; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM2_PWM + case 2: + { + regaddr = TIMRCCEN_TIM2; + en_bit = TIMEN_TIM2; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM3_PWM + case 3: + { + regaddr = TIMRCCEN_TIM3; + en_bit = TIMEN_TIM3; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM4_PWM + case 4: + { + regaddr = TIMRCCEN_TIM4; + en_bit = TIMEN_TIM4; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM5_PWM + case 5: + { + regaddr = TIMRCCEN_TIM5; + en_bit = TIMEN_TIM5; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM8_PWM + case 8: + { + regaddr = TIMRCCEN_TIM8; + en_bit = TIMEN_TIM8; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM9_PWM + case 9: + { + regaddr = TIMRCCEN_TIM9; + en_bit = TIMEN_TIM9; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM10_PWM + case 10: + { + regaddr = TIMRCCEN_TIM10; + en_bit = TIMEN_TIM10; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM11_PWM + case 11: + { + regaddr = TIMRCCEN_TIM11; + en_bit = TIMEN_TIM11; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM12_PWM + case 12: + { + regaddr = TIMRCCEN_TIM12; + en_bit = TIMEN_TIM12; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM13_PWM + case 13: + { + regaddr = TIMRCCEN_TIM13; + en_bit = TIMEN_TIM13; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM14_PWM + case 14: + { + regaddr = TIMRCCEN_TIM14; + en_bit = TIMEN_TIM14; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM20_PWM + case 20: + { + regaddr = TIMRCCEN_TIM20; + en_bit = TIMEN_TIM20; + break; + } +#endif + + default: + { + pwmerr("ERROR: No such timer configured %d\n", priv->timid); + ret = -EINVAL; + goto errout; + } + } + + /* Enable/disable APB 1/2 clock for timer */ + + pwminfo("RCC_APBxENR base: %08" PRIx32 " bits: %04" PRIx32 "\n", + regaddr, en_bit); + + if (on) + { + modifyreg32(regaddr, 0, en_bit); + } + else + { + modifyreg32(regaddr, en_bit, 0); + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: pwm_setup + * + * Description: + * This method is called when the driver is opened. The lower half driver + * should configure and initialize the device so that it is ready for use. + * It should not, however, output pulses until the start method is called. + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * Assumptions: + * APB1 or 2 clocking for the GPIOs has already been configured by the RCC + * logic at power up. + * + ****************************************************************************/ + +static int pwm_setup(struct pwm_lowerhalf_s *dev) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint32_t pincfg = 0; + int ret = OK; + int i = 0; + + pwminfo("TIM%u\n", priv->timid); + + /* Enable APB1/2 clocking for timer. */ + + ret = pwm_set_apb_clock(priv, true); + if (ret < 0) + { + goto errout; + } + + pwm_dumpregs(dev, "Initially"); + + /* Configure the PWM output pins, but do not start the timer yet */ + + for (i = 0; i < priv->chan_num; i++) + { + if (priv->channels[i].out1.in_use == 1) + { + /* Do not configure the pin if pincfg is not specified. + * This prevents overwriting the PA0 configuration if the + * channel is used internally. + */ + + pincfg = priv->channels[i].out1.pincfg; + if (pincfg != 0) + { + pwminfo("pincfg: %08" PRIx32 "\n", pincfg); + + at32_configgpio(pincfg); + pwm_dumpgpio(pincfg, "PWM setup"); + } + } + +#ifdef HAVE_PWM_COMPLEMENTARY + if (priv->channels[i].out2.in_use == 1) + { + pincfg = priv->channels[i].out2.pincfg; + + /* Do not configure the pin if pincfg is not specified. + * This prevents overwriting the PA0 configuration if the + * channel is used internally. + */ + + if (pincfg != 0) + { + pwminfo("pincfg: %08" PRIx32 "\n", pincfg); + + at32_configgpio(pincfg); + pwm_dumpgpio(pincfg, "PWM setup"); + } + } +#endif + } + + /* Configure PWM timer with the selected configuration. + * + * NOTE: We configure PWM here during setup, but leave timer with disabled + * counter, disabled outputs, not configured frequency and duty cycle + */ + +#ifdef CONFIG_PWM_PULSECOUNT + if (priv->timtype == TIMTYPE_ADVANCED) + { + ret = pwm_pulsecount_configure(dev); + } + else +#endif + { + ret = pwm_configure(dev); + } + + if (ret < 0) + { + pwmerr("failed to configure PWM %d\n", priv->timid); + ret = ERROR; + goto errout; + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: pwm_shutdown + * + * Description: + * This method is called when the driver is closed. The lower half driver + * stop pulsed output, free any resources, disable the timer hardware, and + * put the system into the lowest possible power usage state + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_shutdown(struct pwm_lowerhalf_s *dev) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + uint32_t pincfg = 0; + int i = 0; + int ret = OK; + + pwminfo("TIM%u\n", priv->timid); + + /* Make sure that the output has been stopped */ + + pwm_stop(dev); + + /* Disable APB1/2 clocking for timer. */ + + ret = pwm_set_apb_clock(priv, false); + if (ret < 0) + { + goto errout; + } + + /* Then put the GPIO pins back to the default state */ + + for (i = 0; i < priv->chan_num; i++) + { + pincfg = priv->channels[i].out1.pincfg; + if (pincfg != 0) + { + pwminfo("pincfg: %08" PRIx32 "\n", pincfg); + + pincfg &= (GPIO_PORT_MASK | GPIO_PIN_MASK); + pincfg |= PINCFG_DEFAULT; + + at32_configgpio(pincfg); + } + +#ifdef HAVE_PWM_COMPLEMENTARY + pincfg = priv->channels[i].out2.pincfg; + if (pincfg != 0) + { + pwminfo("pincfg: %08" PRIx32 "\n", pincfg); + + pincfg &= (GPIO_PORT_MASK | GPIO_PIN_MASK); + pincfg |= PINCFG_DEFAULT; + + at32_configgpio(pincfg); + } +#endif + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: pwm_start + * + * Description: + * (Re-)initialize the timer resources and start the pulsed output + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * info - A reference to the characteristics of the pulsed output + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +#ifdef CONFIG_PWM_PULSECOUNT +static int pwm_start_pulsecount(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info, + void *handle) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + + /* Generate an indefinite number of pulses */ + + if (info->count == 0) + { + return pwm_start(dev, info); + } + + /* Check if a pulsecount has been selected */ + + if (info->count > 0) + { + /* Only the advanced timers (TIM1,8 can support the pulse counting) + * REVISIT: verify if TIMTYPE_COUNTUP16_N works with it + */ + + if (priv->timtype != TIMTYPE_ADVANCED) + { + pwmerr("ERROR: TIM%u cannot support pulse count: %" PRIx32 "\n", + priv->timid, info->count); + return -EPERM; + } + } + + /* Save the handle */ + + priv->handle = handle; + + /* Start the time */ + + return pwm_pulsecount_timer(dev, info); +} +#endif /* CONFIG_PWM_PULSECOUNT */ + +static int pwm_start(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + int ret = OK; + + /* if frequency has not changed we just update duty */ + + if (info->frequency == priv->frequency) + { +#ifdef CONFIG_PWM_MULTICHAN + int i; + + for (i = 0; ret == OK && i < CONFIG_PWM_NCHANNELS; i++) + { + /* Break the loop if all following channels are not configured */ + + if (info->channels[i].channel == -1) + { + break; + } + + /* Set output if channel configured */ + + if (info->channels[i].channel != 0) + { + ret = pwm_duty_update(dev, info->channels[i].channel, + info->channels[i].duty); + } + } +#else + ret = pwm_duty_update(dev, priv->channels[0].channel, info->duty); +#endif /* CONFIG_PWM_MULTICHAN */ + } + else + { + ret = pwm_timer(dev, info); + + /* Save current frequency */ + + if (ret == OK) + { + priv->frequency = info->frequency; + } + } + + return ret; +} + +/**************************************************************************** + * Name: pwm_stop + * + * Description: + * Stop the pulsed output and reset the timer resources + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * Assumptions: + * This function is called to stop the pulsed output at anytime. This + * method is also called from the timer interrupt handler when a repetition + * count expires... automatically stopping the timer. + * + ****************************************************************************/ + +static int pwm_stop(struct pwm_lowerhalf_s *dev) +{ + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + irqstate_t flags = 0; + uint16_t outputs = 0; + int ret = OK; + + pwminfo("TIM%u\n", priv->timid); + + /* Disable interrupts momentary to stop any ongoing timer processing and + * to prevent any concurrent access to the reset register. + */ + + flags = enter_critical_section(); + + /* Stopped so frequency is zero */ + + priv->frequency = 0; + + /* Disable further interrupts and stop the timer */ + + pwm_putreg(priv, AT32_GTIM_DIER_OFFSET, 0); + pwm_putreg(priv, AT32_GTIM_SR_OFFSET, 0); + + /* Disable the timer and timer outputs */ + + pwm_timer_enable(dev, false); + outputs = pwm_outputs_from_channels(priv); + ret = pwm_outputs_enable(dev, outputs, false); + + leave_critical_section(flags); + + pwm_dumpregs(dev, "After stop"); + + return ret; +} + +/**************************************************************************** + * Name: pwm_ioctl + * + * Description: + * Lower-half logic may support platform-specific ioctl commands + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * cmd - The ioctl command + * arg - The argument accompanying the ioctl command + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd, + unsigned long arg) +{ +#ifdef CONFIG_DEBUG_PWM_INFO + struct at32_pwmtimer_s *priv = (struct at32_pwmtimer_s *)dev; + + /* There are no platform-specific ioctl commands */ + + pwminfo("TIM%u\n", priv->timid); +#endif + return -ENOTTY; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_pwminitialize + * + * Description: + * Initialize one timer for use with the upper_level PWM driver. + * + * Input Parameters: + * timer - A number identifying the timer use. The number of valid timer + * IDs varies with the AT32 MCU and MCU family but is somewhere in + * the range of {1,..,17}. + * + * Returned Value: + * On success, a pointer to the AT32 lower half PWM driver is returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +struct pwm_lowerhalf_s *at32_pwminitialize(int timer) +{ + struct at32_pwmtimer_s *lower = NULL; + + pwminfo("TIM%u\n", timer); + + switch (timer) + { +#ifdef CONFIG_AT32_TIM1_PWM + case 1: + { + lower = &g_pwm1dev; + + /* Attach but disable the TIM1 update interrupt */ + +#ifdef CONFIG_PWM_PULSECOUNT + irq_attach(lower->irq, pwm_tim1interrupt, NULL); + up_disable_irq(lower->irq); +#endif + break; + } +#endif + +#ifdef CONFIG_AT32_TIM2_PWM + case 2: + { + lower = &g_pwm2dev; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM3_PWM + case 3: + { + lower = &g_pwm3dev; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM4_PWM + case 4: + { + lower = &g_pwm4dev; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM5_PWM + case 5: + { + lower = &g_pwm5dev; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM8_PWM + case 8: + { + lower = &g_pwm8dev; + + /* Attach but disable the TIM8 update interrupt */ + +#ifdef CONFIG_PWM_PULSECOUNT + irq_attach(lower->irq, pwm_tim8interrupt, NULL); + up_disable_irq(lower->irq); +#endif + break; + } +#endif + +#ifdef CONFIG_AT32_TIM9_PWM + case 9: + { + lower = &g_pwm9dev; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM10_PWM + case 10: + { + lower = &g_pwm10dev; + break; + } + +#endif + +#ifdef CONFIG_AT32_TIM11_PWM + case 11: + { + lower = &g_pwm11dev; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM12_PWM + case 12: + { + lower = &g_pwm12dev; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM13_PWM + case 13: + { + lower = &g_pwm13dev; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM14_PWM + case 14: + { + lower = &g_pwm14dev; + break; + } +#endif + +#ifdef CONFIG_AT32_TIM20_PWM + case 20: + { + lower = &g_pwm20dev; + + /* Attach but disable the TIM20 update interrupt */ + +#ifdef CONFIG_PWM_PULSECOUNT + irq_attach(lower->irq, pwm_tim20interrupt, NULL); + up_disable_irq(lower->irq); +#endif + break; + } +#endif + + default: + { + pwmerr("ERROR: No such timer configured %d\n", timer); + lower = NULL; + goto errout; + } + } + +errout: + return (struct pwm_lowerhalf_s *)lower; +} + +#endif /* CONFIG_AT32_PWM */ diff --git a/arch/arm/src/at32/at32_pwm.h b/arch/arm/src/at32/at32_pwm.h new file mode 100644 index 0000000000..02f0e9c525 --- /dev/null +++ b/arch/arm/src/at32/at32_pwm.h @@ -0,0 +1,1147 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_pwm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_PWM_H +#define __ARCH_ARM_SRC_AT32_AT32_PWM_H + +/* The AT32 does not have dedicated PWM hardware. Rather, pulsed output + * control is a capability of the AT32 timers. The logic in this file + * implements the lower half of the standard, NuttX PWM interface using the + * AT32 timers. That interface is described in include/nuttx/timers/pwm.h. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "chip.h" + +#ifdef CONFIG_AT32_PWM +# include +# include "hardware/at32_tim.h" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Timer devices may be used for different purposes. One special purpose is + * to generate modulated outputs for such things as motor control. + * If CONFIG_AT32_TIMn is defined then the CONFIG_AT32_TIMn_PWM must also + * be defined to indicate that timer "n" is intended to be used for pulsed + * output signal generation. + */ + +#ifndef CONFIG_AT32_TIM1 +# undef CONFIG_AT32_TIM1_PWM +#endif +#ifndef CONFIG_AT32_TIM2 +# undef CONFIG_AT32_TIM2_PWM +#endif +#ifndef CONFIG_AT32_TIM3 +# undef CONFIG_AT32_TIM3_PWM +#endif +#ifndef CONFIG_AT32_TIM4 +# undef CONFIG_AT32_TIM4_PWM +#endif +#ifndef CONFIG_AT32_TIM5 +# undef CONFIG_AT32_TIM5_PWM +#endif +#ifndef CONFIG_AT32_TIM8 +# undef CONFIG_AT32_TIM8_PWM +#endif +#ifndef CONFIG_AT32_TIM9 +# undef CONFIG_AT32_TIM9_PWM +#endif +#ifndef CONFIG_AT32_TIM10 +# undef CONFIG_AT32_TIM10_PWM +#endif +#ifndef CONFIG_AT32_TIM11 +# undef CONFIG_AT32_TIM11_PWM +#endif +#ifndef CONFIG_AT32_TIM12 +# undef CONFIG_AT32_TIM12_PWM +#endif +#ifndef CONFIG_AT32_TIM13 +# undef CONFIG_AT32_TIM13_PWM +#endif +#ifndef CONFIG_AT32_TIM14 +# undef CONFIG_AT32_TIM14_PWM +#endif +#ifndef CONFIG_AT32_TIM20 +# undef CONFIG_AT32_TIM20_PWM +#endif + +/* The basic timers (timer 6 and 7) are not capable of generating output + * pulses + */ + +#undef CONFIG_AT32_TIM6_PWM +#undef CONFIG_AT32_TIM7_PWM + +/* Check if PWM support for any channel is enabled. */ + +#ifdef CONFIG_AT32_PWM + +/* PWM driver channels configuration */ + +#ifdef CONFIG_AT32_PWM_MULTICHAN + +#ifdef CONFIG_AT32_TIM1_CHANNEL1 +# define PWM_TIM1_CHANNEL1 1 +#else +# define PWM_TIM1_CHANNEL1 0 +#endif +#ifdef CONFIG_AT32_TIM1_CHANNEL2 +# define PWM_TIM1_CHANNEL2 1 +#else +# define PWM_TIM1_CHANNEL2 0 +#endif +#ifdef CONFIG_AT32_TIM1_CHANNEL3 +# define PWM_TIM1_CHANNEL3 1 +#else +# define PWM_TIM1_CHANNEL3 0 +#endif +#ifdef CONFIG_AT32_TIM1_CHANNEL4 +# define PWM_TIM1_CHANNEL4 1 +#else +# define PWM_TIM1_CHANNEL4 0 +#endif +#ifdef CONFIG_AT32_TIM1_CHANNEL5 +# define PWM_TIM1_CHANNEL5 1 +#else +# define PWM_TIM1_CHANNEL5 0 +#endif +#ifdef CONFIG_AT32_TIM1_CHANNEL6 +# define PWM_TIM1_CHANNEL6 1 +#else +# define PWM_TIM1_CHANNEL6 0 +#endif +#define PWM_TIM1_NCHANNELS (PWM_TIM1_CHANNEL1 + PWM_TIM1_CHANNEL2 + \ + PWM_TIM1_CHANNEL3 + PWM_TIM1_CHANNEL4 + \ + PWM_TIM1_CHANNEL5 + PWM_TIM1_CHANNEL6) + +#ifdef CONFIG_AT32_TIM2_CHANNEL1 +# define PWM_TIM2_CHANNEL1 1 +#else +# define PWM_TIM2_CHANNEL1 0 +#endif +#ifdef CONFIG_AT32_TIM2_CHANNEL2 +# define PWM_TIM2_CHANNEL2 1 +#else +# define PWM_TIM2_CHANNEL2 0 +#endif +#ifdef CONFIG_AT32_TIM2_CHANNEL3 +# define PWM_TIM2_CHANNEL3 1 +#else +# define PWM_TIM2_CHANNEL3 0 +#endif +#ifdef CONFIG_AT32_TIM2_CHANNEL4 +# define PWM_TIM2_CHANNEL4 1 +#else +# define PWM_TIM2_CHANNEL4 0 +#endif +#define PWM_TIM2_NCHANNELS (PWM_TIM2_CHANNEL1 + PWM_TIM2_CHANNEL2 + \ + PWM_TIM2_CHANNEL3 + PWM_TIM2_CHANNEL4) + +#ifdef CONFIG_AT32_TIM3_CHANNEL1 +# define PWM_TIM3_CHANNEL1 1 +#else +# define PWM_TIM3_CHANNEL1 0 +#endif +#ifdef CONFIG_AT32_TIM3_CHANNEL2 +# define PWM_TIM3_CHANNEL2 1 +#else +# define PWM_TIM3_CHANNEL2 0 +#endif +#ifdef CONFIG_AT32_TIM3_CHANNEL3 +# define PWM_TIM3_CHANNEL3 1 +#else +# define PWM_TIM3_CHANNEL3 0 +#endif +#ifdef CONFIG_AT32_TIM3_CHANNEL4 +# define PWM_TIM3_CHANNEL4 1 +#else +# define PWM_TIM3_CHANNEL4 0 +#endif +#define PWM_TIM3_NCHANNELS (PWM_TIM3_CHANNEL1 + PWM_TIM3_CHANNEL2 + \ + PWM_TIM3_CHANNEL3 + PWM_TIM3_CHANNEL4) + +#ifdef CONFIG_AT32_TIM4_CHANNEL1 +# define PWM_TIM4_CHANNEL1 1 +#else +# define PWM_TIM4_CHANNEL1 0 +#endif +#ifdef CONFIG_AT32_TIM4_CHANNEL2 +# define PWM_TIM4_CHANNEL2 1 +#else +# define PWM_TIM4_CHANNEL2 0 +#endif +#ifdef CONFIG_AT32_TIM4_CHANNEL3 +# define PWM_TIM4_CHANNEL3 1 +#else +# define PWM_TIM4_CHANNEL3 0 +#endif +#ifdef CONFIG_AT32_TIM4_CHANNEL4 +# define PWM_TIM4_CHANNEL4 1 +#else +# define PWM_TIM4_CHANNEL4 0 +#endif +#define PWM_TIM4_NCHANNELS (PWM_TIM4_CHANNEL1 + PWM_TIM4_CHANNEL2 + \ + PWM_TIM4_CHANNEL3 + PWM_TIM4_CHANNEL4) + +#ifdef CONFIG_AT32_TIM5_CHANNEL1 +# define PWM_TIM5_CHANNEL1 1 +#else +# define PWM_TIM5_CHANNEL1 0 +#endif +#ifdef CONFIG_AT32_TIM5_CHANNEL2 +# define PWM_TIM5_CHANNEL2 1 +#else +# define PWM_TIM5_CHANNEL2 0 +#endif +#ifdef CONFIG_AT32_TIM5_CHANNEL3 +# define PWM_TIM5_CHANNEL3 1 +#else +# define PWM_TIM5_CHANNEL3 0 +#endif +#ifdef CONFIG_AT32_TIM5_CHANNEL4 +# define PWM_TIM5_CHANNEL4 1 +#else +# define PWM_TIM5_CHANNEL4 0 +#endif +#define PWM_TIM5_NCHANNELS (PWM_TIM5_CHANNEL1 + PWM_TIM5_CHANNEL2 + \ + PWM_TIM5_CHANNEL3 + PWM_TIM5_CHANNEL4) + +#ifdef CONFIG_AT32_TIM8_CHANNEL1 +# define PWM_TIM8_CHANNEL1 1 +#else +# define PWM_TIM8_CHANNEL1 0 +#endif +#ifdef CONFIG_AT32_TIM8_CHANNEL2 +# define PWM_TIM8_CHANNEL2 1 +#else +# define PWM_TIM8_CHANNEL2 0 +#endif +#ifdef CONFIG_AT32_TIM8_CHANNEL3 +# define PWM_TIM8_CHANNEL3 1 +#else +# define PWM_TIM8_CHANNEL3 0 +#endif +#ifdef CONFIG_AT32_TIM8_CHANNEL4 +# define PWM_TIM8_CHANNEL4 1 +#else +# define PWM_TIM8_CHANNEL4 0 +#endif +#ifdef CONFIG_AT32_TIM8_CHANNEL5 +# define PWM_TIM8_CHANNEL5 1 +#else +# define PWM_TIM8_CHANNEL5 0 +#endif +#ifdef CONFIG_AT32_TIM8_CHANNEL6 +# define PWM_TIM8_CHANNEL6 1 +#else +# define PWM_TIM8_CHANNEL6 0 +#endif +#define PWM_TIM8_NCHANNELS (PWM_TIM8_CHANNEL1 + PWM_TIM8_CHANNEL2 + \ + PWM_TIM8_CHANNEL3 + PWM_TIM8_CHANNEL4 + \ + PWM_TIM8_CHANNEL5 + PWM_TIM8_CHANNEL6) + +#ifdef CONFIG_AT32_TIM9_CHANNEL1 +# define PWM_TIM9_CHANNEL1 1 +#else +# define PWM_TIM9_CHANNEL1 0 +#endif +#ifdef CONFIG_AT32_TIM9_CHANNEL2 +# define PWM_TIM9_CHANNEL2 1 +#else +# define PWM_TIM9_CHANNEL2 0 +#endif +#define PWM_TIM9_NCHANNELS (PWM_TIM9_CHANNEL1 + PWM_TIM9_CHANNEL2) + +#ifdef CONFIG_AT32_TIM10_CHANNEL1 +# define PWM_TIM10_CHANNEL1 1 +#else +# define PWM_TIM10_CHANNEL1 0 +#endif +#define PWM_TIM10_NCHANNELS (PWM_TIM10_CHANNEL1) + +#ifdef CONFIG_AT32_TIM11_CHANNEL1 +# define PWM_TIM11_CHANNEL1 1 +#else +# define PWM_TIM11_CHANNEL1 0 +#endif +#define PWM_TIM11_NCHANNELS (PWM_TIM11_CHANNEL1) + +#ifdef CONFIG_AT32_TIM12_CHANNEL1 +# define PWM_TIM12_CHANNEL1 1 +#else +# define PWM_TIM12_CHANNEL1 0 +#endif +#ifdef CONFIG_AT32_TIM12_CHANNEL2 +# define PWM_TIM12_CHANNEL2 1 +#else +# define PWM_TIM12_CHANNEL2 0 +#endif +#define PWM_TIM12_NCHANNELS (PWM_TIM12_CHANNEL1 + PWM_TIM12_CHANNEL2) + +#ifdef CONFIG_AT32_TIM13_CHANNEL1 +# define PWM_TIM13_CHANNEL1 1 +#else +# define PWM_TIM13_CHANNEL1 0 +#endif +#define PWM_TIM13_NCHANNELS (PWM_TIM13_CHANNEL1) + +#ifdef CONFIG_AT32_TIM14_CHANNEL1 +# define PWM_TIM14_CHANNEL1 1 +#else +# define PWM_TIM14_CHANNEL1 0 +#endif +#define PWM_TIM14_NCHANNELS (PWM_TIM14_CHANNEL1) + +#ifdef CONFIG_AT32_TIM20_CHANNEL1 +# define PWM_TIM20_CHANNEL1 1 +#else +# define PWM_TIM20_CHANNEL1 0 +#endif +#ifdef CONFIG_AT32_TIM20_CHANNEL2 +# define PWM_TIM20_CHANNEL2 1 +#else +# define PWM_TIM20_CHANNEL2 0 +#endif +#ifdef CONFIG_AT32_TIM20_CHANNEL3 +# define PWM_TIM20_CHANNEL3 1 +#else +# define PWM_TIM20_CHANNEL3 0 +#endif +#ifdef CONFIG_AT32_TIM20_CHANNEL4 +# define PWM_TIM20_CHANNEL4 1 +#else +# define PWM_TIM20_CHANNEL4 0 +#endif +#ifdef CONFIG_AT32_TIM20_CHANNEL5 +# define PWM_TIM20_CHANNEL5 1 +#else +# define PWM_TIM20_CHANNEL5 0 +#endif +#ifdef CONFIG_AT32_TIM20_CHANNEL6 +# define PWM_TIM20_CHANNEL6 1 +#else +# define PWM_TIM20_CHANNEL6 0 +#endif +#define PWM_TIM20_NCHANNELS (PWM_TIM20_CHANNEL1 + PWM_TIM20_CHANNEL2 + \ + PWM_TIM20_CHANNEL3 + PWM_TIM20_CHANNEL4 + \ + PWM_TIM20_CHANNEL5 + PWM_TIM20_CHANNEL6) + +#else /* !CONFIG_PWM_MULTICHAN */ + +/* For each timer that is enabled for PWM usage, we need the following + * additional configuration settings: + * + * CONFIG_AT32_TIMx_CHANNEL - Specifies the timer output channel {1,..,4} + * PWM_TIMx_CHn - One of the values defined in chip/at32*_pinmap.h. In the + * case where there are multiple pin selections, the correct setting must be + * provided in the arch/board/board.h file. + * + * NOTE: The AT32 timers are each capable of generating different signals on + * each of the four channels with different duty cycles. That capability is + * not supported by this driver: Only one output channel per timer. + */ + +#ifdef CONFIG_AT32_TIM1_PWM +# if !defined(CONFIG_AT32_TIM1_CHANNEL) +# error "CONFIG_AT32_TIM1_CHANNEL must be provided" +# elif CONFIG_AT32_TIM1_CHANNEL == 1 +# define CONFIG_AT32_TIM1_CHANNEL1 1 +# define CONFIG_AT32_TIM1_CH1MODE CONFIG_AT32_TIM1_CHMODE +# elif CONFIG_AT32_TIM1_CHANNEL == 2 +# define CONFIG_AT32_TIM1_CHANNEL2 1 +# define CONFIG_AT32_TIM1_CH2MODE CONFIG_AT32_TIM1_CHMODE +# elif CONFIG_AT32_TIM1_CHANNEL == 3 +# define CONFIG_AT32_TIM1_CHANNEL3 1 +# define CONFIG_AT32_TIM1_CH3MODE CONFIG_AT32_TIM1_CHMODE +# elif CONFIG_AT32_TIM1_CHANNEL == 4 +# define CONFIG_AT32_TIM1_CHANNEL4 1 +# define CONFIG_AT32_TIM1_CH4MODE CONFIG_AT32_TIM1_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM1_CHANNEL" +# endif +# define PWM_TIM1_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM2_PWM +# if !defined(CONFIG_AT32_TIM2_CHANNEL) +# error "CONFIG_AT32_TIM2_CHANNEL must be provided" +# elif CONFIG_AT32_TIM2_CHANNEL == 1 +# define CONFIG_AT32_TIM2_CHANNEL1 1 +# define CONFIG_AT32_TIM2_CH1MODE CONFIG_AT32_TIM2_CHMODE +# elif CONFIG_AT32_TIM2_CHANNEL == 2 +# define CONFIG_AT32_TIM2_CHANNEL2 1 +# define CONFIG_AT32_TIM2_CH2MODE CONFIG_AT32_TIM2_CHMODE +# elif CONFIG_AT32_TIM2_CHANNEL == 3 +# define CONFIG_AT32_TIM2_CHANNEL3 1 +# define CONFIG_AT32_TIM2_CH3MODE CONFIG_AT32_TIM2_CHMODE +# elif CONFIG_AT32_TIM2_CHANNEL == 4 +# define CONFIG_AT32_TIM2_CHANNEL4 1 +# define CONFIG_AT32_TIM2_CH4MODE CONFIG_AT32_TIM2_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM2_CHANNEL" +# endif +# define PWM_TIM2_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM3_PWM +# if !defined(CONFIG_AT32_TIM3_CHANNEL) +# error "CONFIG_AT32_TIM3_CHANNEL must be provided" +# elif CONFIG_AT32_TIM3_CHANNEL == 1 +# define CONFIG_AT32_TIM3_CHANNEL1 1 +# define CONFIG_AT32_TIM3_CH1MODE CONFIG_AT32_TIM3_CHMODE +# elif CONFIG_AT32_TIM3_CHANNEL == 2 +# define CONFIG_AT32_TIM3_CHANNEL2 1 +# define CONFIG_AT32_TIM3_CH2MODE CONFIG_AT32_TIM3_CHMODE +# elif CONFIG_AT32_TIM3_CHANNEL == 3 +# define CONFIG_AT32_TIM3_CHANNEL3 1 +# define CONFIG_AT32_TIM3_CH3MODE CONFIG_AT32_TIM3_CHMODE +# elif CONFIG_AT32_TIM3_CHANNEL == 4 +# define CONFIG_AT32_TIM3_CHANNEL4 1 +# define CONFIG_AT32_TIM3_CH4MODE CONFIG_AT32_TIM3_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM3_CHANNEL" +# endif +# define PWM_TIM3_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM4_PWM +# if !defined(CONFIG_AT32_TIM4_CHANNEL) +# error "CONFIG_AT32_TIM4_CHANNEL must be provided" +# elif CONFIG_AT32_TIM4_CHANNEL == 1 +# define CONFIG_AT32_TIM4_CHANNEL1 1 +# define CONFIG_AT32_TIM4_CH1MODE CONFIG_AT32_TIM4_CHMODE +# elif CONFIG_AT32_TIM4_CHANNEL == 2 +# define CONFIG_AT32_TIM4_CHANNEL2 1 +# define CONFIG_AT32_TIM4_CH2MODE CONFIG_AT32_TIM4_CHMODE +# elif CONFIG_AT32_TIM4_CHANNEL == 3 +# define CONFIG_AT32_TIM4_CHANNEL3 1 +# define CONFIG_AT32_TIM4_CH3MODE CONFIG_AT32_TIM4_CHMODE +# elif CONFIG_AT32_TIM4_CHANNEL == 4 +# define CONFIG_AT32_TIM4_CHANNEL4 1 +# define CONFIG_AT32_TIM4_CH4MODE CONFIG_AT32_TIM4_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM4_CHANNEL" +# endif +# define PWM_TIM4_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM5_PWM +# if !defined(CONFIG_AT32_TIM5_CHANNEL) +# error "CONFIG_AT32_TIM5_CHANNEL must be provided" +# elif CONFIG_AT32_TIM5_CHANNEL == 1 +# define CONFIG_AT32_TIM5_CHANNEL1 1 +# define CONFIG_AT32_TIM5_CH1MODE CONFIG_AT32_TIM5_CHMODE +# elif CONFIG_AT32_TIM5_CHANNEL == 2 +# define CONFIG_AT32_TIM5_CHANNEL2 1 +# define CONFIG_AT32_TIM5_CH2MODE CONFIG_AT32_TIM5_CHMODE +# elif CONFIG_AT32_TIM5_CHANNEL == 3 +# define CONFIG_AT32_TIM5_CHANNEL3 1 +# define CONFIG_AT32_TIM5_CH3MODE CONFIG_AT32_TIM5_CHMODE +# elif CONFIG_AT32_TIM5_CHANNEL == 4 +# define CONFIG_AT32_TIM5_CHANNEL4 1 +# define CONFIG_AT32_TIM5_CH4MODE CONFIG_AT32_TIM5_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM5_CHANNEL" +# endif +# define PWM_TIM5_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM8_PWM +# if !defined(CONFIG_AT32_TIM8_CHANNEL) +# error "CONFIG_AT32_TIM8_CHANNEL must be provided" +# elif CONFIG_AT32_TIM8_CHANNEL == 1 +# define CONFIG_AT32_TIM8_CHANNEL1 1 +# define CONFIG_AT32_TIM8_CH1MODE CONFIG_AT32_TIM8_CHMODE +# elif CONFIG_AT32_TIM8_CHANNEL == 2 +# define CONFIG_AT32_TIM8_CHANNEL2 1 +# define CONFIG_AT32_TIM8_CH2MODE CONFIG_AT32_TIM8_CHMODE +# elif CONFIG_AT32_TIM8_CHANNEL == 3 +# define CONFIG_AT32_TIM8_CHANNEL3 1 +# define CONFIG_AT32_TIM8_CH3MODE CONFIG_AT32_TIM8_CHMODE +# elif CONFIG_AT32_TIM8_CHANNEL == 4 +# define CONFIG_AT32_TIM8_CHANNEL4 1 +# define CONFIG_AT32_TIM8_CH4MODE CONFIG_AT32_TIM8_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM8_CHANNEL" +# endif +# define PWM_TIM8_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM9_PWM +# if !defined(CONFIG_AT32_TIM9_CHANNEL) +# error "CONFIG_AT32_TIM9_CHANNEL must be provided" +# elif CONFIG_AT32_TIM9_CHANNEL == 1 +# define CONFIG_AT32_TIM9_CHANNEL1 1 +# define CONFIG_AT32_TIM9_CH1MODE CONFIG_AT32_TIM9_CHMODE +# elif CONFIG_AT32_TIM9_CHANNEL == 2 +# define CONFIG_AT32_TIM9_CHANNEL2 1 +# define CONFIG_AT32_TIM9_CH2MODE CONFIG_AT32_TIM9_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM9_CHANNEL" +# endif +# define PWM_TIM9_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM10_PWM +# if !defined(CONFIG_AT32_TIM10_CHANNEL) +# error "CONFIG_AT32_TIM10_CHANNEL must be provided" +# elif CONFIG_AT32_TIM10_CHANNEL == 1 +# define CONFIG_AT32_TIM10_CHANNEL1 1 +# define CONFIG_AT32_TIM10_CH1MODE CONFIG_AT32_TIM10_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM10_CHANNEL" +# endif +# define PWM_TIM10_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM11_PWM +# if !defined(CONFIG_AT32_TIM11_CHANNEL) +# error "CONFIG_AT32_TIM11_CHANNEL must be provided" +# elif CONFIG_AT32_TIM11_CHANNEL == 1 +# define CONFIG_AT32_TIM11_CHANNEL1 1 +# define CONFIG_AT32_TIM11_CH1MODE CONFIG_AT32_TIM11_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM11_CHANNEL" +# endif +# define PWM_TIM11_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM12_PWM +# if !defined(CONFIG_AT32_TIM12_CHANNEL) +# error "CONFIG_AT32_TIM12_CHANNEL must be provided" +# elif CONFIG_AT32_TIM12_CHANNEL == 1 +# define CONFIG_AT32_TIM12_CHANNEL1 1 +# define CONFIG_AT32_TIM12_CH1MODE CONFIG_AT32_TIM12_CHMODE +# elif CONFIG_AT32_TIM12_CHANNEL == 2 +# define CONFIG_AT32_TIM12_CHANNEL2 1 +# define CONFIG_AT32_TIM12_CH2MODE CONFIG_AT32_TIM12_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM12_CHANNEL" +# endif +# define PWM_TIM12_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM13_PWM +# if !defined(CONFIG_AT32_TIM13_CHANNEL) +# error "CONFIG_AT32_TIM13_CHANNEL must be provided" +# elif CONFIG_AT32_TIM13_CHANNEL == 1 +# define CONFIG_AT32_TIM13_CHANNEL1 1 +# define CONFIG_AT32_TIM13_CH1MODE CONFIG_AT32_TIM13_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM13_CHANNEL" +# endif +# define PWM_TIM13_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM14_PWM +# if !defined(CONFIG_AT32_TIM14_CHANNEL) +# error "CONFIG_AT32_TIM14_CHANNEL must be provided" +# elif CONFIG_AT32_TIM14_CHANNEL == 1 +# define CONFIG_AT32_TIM14_CHANNEL1 1 +# define CONFIG_AT32_TIM14_CH1MODE CONFIG_AT32_TIM14_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM14_CHANNEL" +# endif +# define PWM_TIM14_NCHANNELS 1 +#endif + +#ifdef CONFIG_AT32_TIM20_PWM +# if !defined(CONFIG_AT32_TIM20_CHANNEL) +# error "CONFIG_AT32_TIM20_CHANNEL must be provided" +# elif CONFIG_AT32_TIM20_CHANNEL == 1 +# define CONFIG_AT32_TIM20_CHANNEL1 1 +# define CONFIG_AT32_TIM20_CH1MODE CONFIG_AT32_TIM20_CHMODE +# elif CONFIG_AT32_TIM20_CHANNEL == 2 +# define CONFIG_AT32_TIM20_CHANNEL2 1 +# define CONFIG_AT32_TIM20_CH2MODE CONFIG_AT32_TIM20_CHMODE +# elif CONFIG_AT32_TIM20_CHANNEL == 3 +# define CONFIG_AT32_TIM20_CHANNEL3 1 +# define CONFIG_AT32_TIM20_CH3MODE CONFIG_AT32_TIM20_CHMODE +# elif CONFIG_AT32_TIM20_CHANNEL == 4 +# define CONFIG_AT32_TIM20_CHANNEL4 1 +# define CONFIG_AT32_TIM20_CH4MODE CONFIG_AT32_TIM20_CHMODE +# else +# error "Unsupported value of CONFIG_AT32_TIM20_CHANNEL" +# endif +# define PWM_TIM20_NCHANNELS 1 +#endif + +#endif /* CONFIG_AT32_PWM_MULTICHAN */ + +#ifdef CONFIG_AT32_TIM1_CH1OUT +# define PWM_TIM1_CH1CFG GPIO_TIM1_CH1OUT +#else +# define PWM_TIM1_CH1CFG 0 +#endif +#ifdef CONFIG_AT32_TIM1_CH1NOUT +# define PWM_TIM1_CH1NCFG GPIO_TIM1_CH1NOUT +#else +# define PWM_TIM1_CH1NCFG 0 +#endif +#ifdef CONFIG_AT32_TIM1_CH2OUT +# define PWM_TIM1_CH2CFG GPIO_TIM1_CH2OUT +#else +# define PWM_TIM1_CH2CFG 0 +#endif +#ifdef CONFIG_AT32_TIM1_CH2NOUT +# define PWM_TIM1_CH2NCFG GPIO_TIM1_CH2NOUT +#else +# define PWM_TIM1_CH2NCFG 0 +#endif +#ifdef CONFIG_AT32_TIM1_CH3OUT +# define PWM_TIM1_CH3CFG GPIO_TIM1_CH3OUT +#else +# define PWM_TIM1_CH3CFG 0 +#endif +#ifdef CONFIG_AT32_TIM1_CH3NOUT +# define PWM_TIM1_CH3NCFG GPIO_TIM1_CH3NOUT +#else +# define PWM_TIM1_CH3NCFG 0 +#endif +#ifdef CONFIG_AT32_TIM1_CH4OUT +# define PWM_TIM1_CH4CFG GPIO_TIM1_CH4OUT +#else +# define PWM_TIM1_CH4CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM2_CH1OUT +# define PWM_TIM2_CH1CFG GPIO_TIM2_CH1OUT +#else +# define PWM_TIM2_CH1CFG 0 +#endif +#ifdef CONFIG_AT32_TIM2_CH2OUT +# define PWM_TIM2_CH2CFG GPIO_TIM2_CH2OUT +#else +# define PWM_TIM2_CH2CFG 0 +#endif +#ifdef CONFIG_AT32_TIM2_CH3OUT +# define PWM_TIM2_CH3CFG GPIO_TIM2_CH3OUT +#else +# define PWM_TIM2_CH3CFG 0 +#endif +#ifdef CONFIG_AT32_TIM2_CH4OUT +# define PWM_TIM2_CH4CFG GPIO_TIM2_CH4OUT +#else +# define PWM_TIM2_CH4CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM3_CH1OUT +# define PWM_TIM3_CH1CFG GPIO_TIM3_CH1OUT +#else +# define PWM_TIM3_CH1CFG 0 +#endif +#ifdef CONFIG_AT32_TIM3_CH2OUT +# define PWM_TIM3_CH2CFG GPIO_TIM3_CH2OUT +#else +# define PWM_TIM3_CH2CFG 0 +#endif +#ifdef CONFIG_AT32_TIM3_CH3OUT +# define PWM_TIM3_CH3CFG GPIO_TIM3_CH3OUT +#else +# define PWM_TIM3_CH3CFG 0 +#endif +#ifdef CONFIG_AT32_TIM3_CH4OUT +# define PWM_TIM3_CH4CFG GPIO_TIM3_CH4OUT +#else +# define PWM_TIM3_CH4CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM4_CH1OUT +# define PWM_TIM4_CH1CFG GPIO_TIM4_CH1OUT +#else +# define PWM_TIM4_CH1CFG 0 +#endif +#ifdef CONFIG_AT32_TIM4_CH2OUT +# define PWM_TIM4_CH2CFG GPIO_TIM4_CH2OUT +#else +# define PWM_TIM4_CH2CFG 0 +#endif +#ifdef CONFIG_AT32_TIM4_CH3OUT +# define PWM_TIM4_CH3CFG GPIO_TIM4_CH3OUT +#else +# define PWM_TIM4_CH3CFG 0 +#endif +#ifdef CONFIG_AT32_TIM4_CH4OUT +# define PWM_TIM4_CH4CFG GPIO_TIM4_CH4OUT +#else +# define PWM_TIM4_CH4CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM5_CH1OUT +# define PWM_TIM5_CH1CFG GPIO_TIM5_CH1OUT +#else +# define PWM_TIM5_CH1CFG 0 +#endif +#ifdef CONFIG_AT32_TIM5_CH2OUT +# define PWM_TIM5_CH2CFG GPIO_TIM5_CH2OUT +#else +# define PWM_TIM5_CH2CFG 0 +#endif +#ifdef CONFIG_AT32_TIM5_CH3OUT +# define PWM_TIM5_CH3CFG GPIO_TIM5_CH3OUT +#else +# define PWM_TIM5_CH3CFG 0 +#endif +#ifdef CONFIG_AT32_TIM5_CH4OUT +# define PWM_TIM5_CH4CFG GPIO_TIM5_CH4OUT +#else +# define PWM_TIM5_CH4CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM8_CH1OUT +# define PWM_TIM8_CH1CFG GPIO_TIM8_CH1OUT +#else +# define PWM_TIM8_CH1CFG 0 +#endif +#ifdef CONFIG_AT32_TIM8_CH1NOUT +# define PWM_TIM8_CH1NCFG GPIO_TIM8_CH1NOUT +#else +# define PWM_TIM8_CH1NCFG 0 +#endif +#ifdef CONFIG_AT32_TIM8_CH2OUT +# define PWM_TIM8_CH2CFG GPIO_TIM8_CH2OUT +#else +# define PWM_TIM8_CH2CFG 0 +#endif +#ifdef CONFIG_AT32_TIM8_CH2NOUT +# define PWM_TIM8_CH2NCFG GPIO_TIM8_CH2NOUT +#else +# define PWM_TIM8_CH2NCFG 0 +#endif +#ifdef CONFIG_AT32_TIM8_CH3OUT +# define PWM_TIM8_CH3CFG GPIO_TIM8_CH3OUT +#else +# define PWM_TIM8_CH3CFG 0 +#endif +#ifdef CONFIG_AT32_TIM8_CH3NOUT +# define PWM_TIM8_CH3NCFG GPIO_TIM8_CH3NOUT +#else +# define PWM_TIM8_CH3NCFG 0 +#endif +#ifdef CONFIG_AT32_TIM8_CH4OUT +# define PWM_TIM8_CH4CFG GPIO_TIM8_CH4OUT +#else +# define PWM_TIM8_CH4CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM9_CH1OUT +# define PWM_TIM9_CH1CFG GPIO_TIM9_CH1OUT +#else +# define PWM_TIM9_CH1CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM9_CH2OUT +# define PWM_TIM9_CH2CFG GPIO_TIM9_CH2OUT +#else +# define PWM_TIM9_CH2CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM10_CH1OUT +# define PWM_TIM10_CH1CFG GPIO_TIM10_CH1OUT +#else +# define PWM_TIM10_CH1CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM11_CH1OUT +# define PWM_TIM11_CH1CFG GPIO_TIM11_CH1OUT +#else +# define PWM_TIM11_CH1CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM12_CH1OUT +# define PWM_TIM12_CH1CFG GPIO_TIM12_CH1OUT +#else +# define PWM_TIM12_CH1CFG 0 +#endif +#ifdef CONFIG_AT32_TIM12_CH2OUT +# define PWM_TIM12_CH2CFG GPIO_TIM12_CH2OUT +#else +# define PWM_TIM12_CH2CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM13_CH1OUT +# define PWM_TIM13_CH1CFG GPIO_TIM13_CH1OUT +#else +# define PWM_TIM13_CH1CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM14_CH1OUT +# define PWM_TIM14_CH1CFG GPIO_TIM14_CH1OUT +#else +# define PWM_TIM14_CH1CFG 0 +#endif + +#ifdef CONFIG_AT32_TIM20_CH1OUT +# define PWM_TIM20_CH1CFG GPIO_TIM20_CH1OUT +#else +# define PWM_TIM20_CH1CFG 0 +#endif +#ifdef CONFIG_AT32_TIM20_CH1NOUT +# define PWM_TIM20_CH1NCFG GPIO_TIM20_CH1NOUT +#else +# define PWM_TIM20_CH1NCFG 0 +#endif +#ifdef CONFIG_AT32_TIM20_CH2OUT +# define PWM_TIM20_CH2CFG GPIO_TIM20_CH2OUT +#else +# define PWM_TIM20_CH2CFG 0 +#endif +#ifdef CONFIG_AT32_TIM20_CH2NOUT +# define PWM_TIM20_CH2NCFG GPIO_TIM20_CH2NOUT +#else +# define PWM_TIM20_CH2NCFG 0 +#endif +#ifdef CONFIG_AT32_TIM20_CH3OUT +# define PWM_TIM20_CH3CFG GPIO_TIM20_CH3OUT +#else +# define PWM_TIM20_CH3CFG 0 +#endif +#ifdef CONFIG_AT32_TIM20_CH3NOUT +# define PWM_TIM20_CH3NCFG GPIO_TIM20_CH3NOUT +#else +# define PWM_TIM20_CH3NCFG 0 +#endif +#ifdef CONFIG_AT32_TIM20_CH4OUT +# define PWM_TIM20_CH4CFG GPIO_TIM20_CH4OUT +#else +# define PWM_TIM20_CH4CFG 0 +#endif + +/* Complementary outputs support */ + +#if defined(CONFIG_AT32_TIM1_CH1NOUT) || defined(CONFIG_AT32_TIM1_CH2NOUT) || \ + defined(CONFIG_AT32_TIM1_CH3NOUT) +# define HAVE_TIM1_COMPLEMENTARY +#endif +#if defined(CONFIG_AT32_TIM8_CH1NOUT) || defined(CONFIG_AT32_TIM8_CH2NOUT) || \ + defined(CONFIG_AT32_TIM8_CH3NOUT) +# define HAVE_TIM8_COMPLEMENTARY +#endif +#if defined(HAVE_TIM1_COMPLEMENTARY) || defined(HAVE_TIM8_COMPLEMENTARY) || \ + defined(HAVE_TIM20_COMPLEMENTARY) +# define HAVE_PWM_COMPLEMENTARY +#endif + +/* Low-level ops helpers ****************************************************/ + +#ifdef CONFIG_AT32_PWM_LL_OPS + +/* NOTE: + * low-level ops accept pwm_lowerhalf_s as first argument, but llops access + * can be found in at32_pwm_dev_s + */ + +#define PWM_SETUP(dev) \ + (dev)->ops->setup((struct pwm_lowerhalf_s *)dev) +#define PWM_SHUTDOWN(dev) \ + (dev)->ops->shutdown((struct pwm_lowerhalf_s *)dev) +#define PWM_CCR_UPDATE(dev, index, ccr) \ + (dev)->llops->ccr_update((struct pwm_lowerhalf_s *)dev, index, ccr) +#define PWM_MODE_UPDATE(dev, index, mode) \ + (dev)->llops->mode_update((struct pwm_lowerhalf_s *)dev, index, mode) +#define PWM_CCR_GET(dev, index) \ + (dev)->llops->ccr_get((struct pwm_lowerhalf_s *)dev, index) +#define PWM_ARR_UPDATE(dev, arr) \ + (dev)->llops->arr_update((struct pwm_lowerhalf_s *)dev, arr) +#define PWM_ARR_GET(dev) \ + (dev)->llops->arr_get((struct pwm_lowerhalf_s *)dev) +#define PWM_RCR_UPDATE(dev, rcr) \ + (dev)->llops->rcr_update((struct pwm_lowerhalf_s *)dev, rcr) +#define PWM_RCR_GET(dev) \ + (dev)->llops->rcr_get((struct pwm_lowerhalf_s *)dev) +#ifdef CONFIG_AT32_PWM_TRGO +# define PWM_TRGO_SET(dev, trgo) \ + (dev)->llops->trgo_set((struct pwm_lowerhalf_s *)dev, trgo) +#endif +#define PWM_OUTPUTS_ENABLE(dev, out, state) \ + (dev)->llops->outputs_enable((struct pwm_lowerhalf_s *)dev, out, state) +#define PWM_SOFT_UPDATE(dev) \ + (dev)->llops->soft_update((struct pwm_lowerhalf_s *)dev) +#define PWM_CONFIGURE(dev) \ + (dev)->llops->configure((struct pwm_lowerhalf_s *)dev) +#define PWM_SOFT_BREAK(dev, state) \ + (dev)->llops->soft_break((struct pwm_lowerhalf_s *)dev, state) +#define PWM_FREQ_UPDATE(dev, freq) \ + (dev)->llops->freq_update((struct pwm_lowerhalf_s *)dev, freq) +#define PWM_TIM_ENABLE(dev, state) \ + (dev)->llops->tim_enable((struct pwm_lowerhalf_s *)dev, state) +#ifdef CONFIG_DEBUG_PWM_INFO +# define PWM_DUMP_REGS(dev, msg) \ + (dev)->llops->dump_regs((struct pwm_lowerhalf_s *)dev, msg) +#else +# define PWM_DUMP_REGS(dev, msg) +#endif +#define PWM_DT_UPDATE(dev, dt) \ + (dev)->llops->dt_update((struct pwm_lowerhalf_s *)dev, dt) +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Timer mode */ + +enum at32_pwm_tim_mode_e +{ + AT32_TIMMODE_COUNTUP = 0, + AT32_TIMMODE_COUNTDOWN = 1, + AT32_TIMMODE_CENTER1 = 2, + AT32_TIMMODE_CENTER2 = 3, + AT32_TIMMODE_CENTER3 = 4, +}; + +/* Timer output polarity */ + +enum at32_pwm_pol_e +{ + AT32_POL_POS = 0, + AT32_POL_NEG = 1, +}; + +/* Timer output IDLE state */ + +enum at32_pwm_idle_e +{ + AT32_IDLE_INACTIVE = 0, + AT32_IDLE_ACTIVE = 1 +}; + +/* PWM channel mode */ + +enum at32_pwm_chanmode_e +{ + AT32_CHANMODE_FRZN = 0, /* CCRx matches has no effects on outputs */ + AT32_CHANMODE_CHACT = 1, /* OCxREF active on match */ + AT32_CHANMODE_CHINACT = 2, /* OCxREF inactive on match */ + AT32_CHANMODE_OCREFTOG = 3, /* OCxREF toggles when TIMy_CNT=TIMyCCRx */ + AT32_CHANMODE_OCREFLO = 4, /* OCxREF is forced low */ + AT32_CHANMODE_OCREFHI = 5, /* OCxREF is forced high */ + AT32_CHANMODE_PWM1 = 6, /* PWM mode 1 */ + AT32_CHANMODE_PWM2 = 7, /* PWM mode 2 */ +#ifdef HAVE_IP_TIMERS_V2 + AT32_CHANMODE_COMBINED1 = 8, /* Combined PWM mode 1 */ + AT32_CHANMODE_COMBINED2 = 9, /* Combined PWM mode 2 */ + AT32_CHANMODE_ASYMMETRIC1 = 10, /* Asymmetric PWM mode 1 */ + AT32_CHANMODE_ASYMMETRIC2 = 11, /* Asymmetric PWM mode 2 */ +#endif +}; + +/* PWM timer channel */ + +enum at32_pwm_chan_e +{ + AT32_PWM_CHAN1 = 1, + AT32_PWM_CHAN2 = 2, + AT32_PWM_CHAN3 = 3, + AT32_PWM_CHAN4 = 4, +#ifdef HAVE_IP_TIMERS_V2 + AT32_PWM_CHAN5 = 5, + AT32_PWM_CHAN6 = 6, +#endif +}; + +/* PWM timer channel output */ + +enum at32_pwm_output_e +{ + AT32_PWM_OUT1 = (1 << 0), + AT32_PWM_OUT1N = (1 << 1), + AT32_PWM_OUT2 = (1 << 2), + AT32_PWM_OUT2N = (1 << 3), + AT32_PWM_OUT3 = (1 << 4), + AT32_PWM_OUT3N = (1 << 5), + AT32_PWM_OUT4 = (1 << 6), + + /* 1 << 7 reserved - no complementary output for CH4 */ + +#ifdef HAVE_IP_TIMERS_V2 + /* Only available inside micro */ + + AT32_PWM_OUT5 = (1 << 8), + + /* 1 << 9 reserved - no complementary output for CH5 */ + + AT32_PWM_OUT6 = (1 << 10), + + /* 1 << 11 reserved - no complementary output for CH6 */ +#endif +}; + +#ifdef CONFIG_AT32_PWM_LL_OPS + +/* This structure provides the publicly visible representation of the + * "lower-half" PWM driver structure. + */ + +struct at32_pwm_dev_s +{ + /* The first field of this state structure must be a pointer to the PWM + * callback structure to be consistent with upper-half PWM driver. + */ + + const struct pwm_ops_s *ops; + + /* Publicly visible portion of the "lower-half" PWM driver structure */ + + const struct at32_pwm_ops_s *llops; + + /* Require cast-compatibility with private "lower-half" PWM structure */ +}; + +/* Low-level operations for PWM */ + +struct pwm_lowerhalf_s; +struct at32_pwm_ops_s +{ + /* Update CCR register */ + + int (*ccr_update)(struct pwm_lowerhalf_s *dev, + uint8_t index, uint32_t ccr); + + /* Update PWM mode */ + + int (*mode_update)(struct pwm_lowerhalf_s *dev, + uint8_t index, uint32_t mode); + + /* Get CCR register */ + + uint32_t (*ccr_get)(struct pwm_lowerhalf_s *dev, uint8_t index); + + /* Update ARR register */ + + int (*arr_update)(struct pwm_lowerhalf_s *dev, uint32_t arr); + + /* Get ARR register */ + + uint32_t (*arr_get)(struct pwm_lowerhalf_s *dev); + + /* Update RCR register */ + + int (*rcr_update)(struct pwm_lowerhalf_s *dev, uint16_t rcr); + + /* Get RCR register */ + + uint16_t (*rcr_get)(struct pwm_lowerhalf_s *dev); + +#ifdef CONFIG_AT32_PWM_TRGO + /* Set TRGO/TRGO2 register */ + + int (*trgo_set)(struct pwm_lowerhalf_s *dev, uint8_t trgo); +#endif + + /* Enable outputs */ + + int (*outputs_enable)(struct pwm_lowerhalf_s *dev, uint16_t outputs, + bool state); + + /* Software update */ + + int (*soft_update)(struct pwm_lowerhalf_s *dev); + + /* PWM configure */ + + int (*configure)(struct pwm_lowerhalf_s *dev); + + /* Software break */ + + int (*soft_break)(struct pwm_lowerhalf_s *dev, bool state); + + /* Update frequency */ + + int (*freq_update)(struct pwm_lowerhalf_s *dev, uint32_t frequency); + + /* Enable timer counter */ + + int (*tim_enable)(struct pwm_lowerhalf_s *dev, bool state); + +#ifdef CONFIG_DEBUG_PWM_INFO + /* Dump timer registers */ + + void (*dump_regs)(struct pwm_lowerhalf_s *dev, const char *msg); +#endif + +#ifdef HAVE_PWM_COMPLEMENTARY + /* Deadtime update */ + + int (*dt_update)(struct pwm_lowerhalf_s *dev, uint8_t dt); +#endif +}; + +#endif /* CONFIG_AT32_PWM_LL_OPS */ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_pwminitialize + * + * Description: + * Initialize one timer for use with the upper_level PWM driver. + * + * Input Parameters: + * timer - A number identifying the timer use. The number of valid timer + * IDs varies with the AT32 MCU and MCU family but is somewhere in + * the range of {1,..,17}. + * + * Returned Value: + * On success, a pointer to the AT32 lower half PWM driver is returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +struct pwm_lowerhalf_s *at32_pwminitialize(int timer); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_AT32_PWM */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_PWM_H */ diff --git a/arch/arm/src/at32/at32_pwr.c b/arch/arm/src/at32/at32_pwr.c new file mode 100644 index 0000000000..d75e9189dd --- /dev/null +++ b/arch/arm/src/at32/at32_pwr.c @@ -0,0 +1,345 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_pwr.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "arm_internal.h" +#include "at32_pwr.h" + +#if defined(CONFIG_AT32_PWR) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Wakeup Pin Definitions: See chip/at32_pwr.h */ + +#undef HAVE_PWR_WKUP2 +#undef HAVE_PWR_WKUP3 + +#if defined(CONFIG_AT32_AT32F43XXX) +# define HAVE_PWR_WKUP2 1 +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static uint16_t g_bkp_writable_counter = 0; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline uint32_t at32_pwr_getreg32(uint8_t offset) +{ + return getreg32(AT32_PWC_BASE + (uint32_t)offset); +} + +static inline void at32_pwr_putreg32(uint8_t offset, uint32_t value) +{ + putreg32(value, AT32_PWC_BASE + (uint32_t)offset); +} + +static inline void at32_pwr_modifyreg32(uint8_t offset, uint32_t clearbits, + uint32_t setbits) +{ + modifyreg32(AT32_PWC_BASE + (uint32_t)offset, clearbits, setbits); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_pwr_initbkp + * + * Description: + * Insures the referenced count access to the backup domain (RTC registers, + * RTC backup data registers and backup SRAM is consistent with the HW + * state without relying on a variable. + * + * NOTE: This function should only be called by SoC Start up code. + * + * Input Parameters: + * writable - True: enable ability to write to backup domain registers + * + * Returned Value: + * None + * + ****************************************************************************/ + +void at32_pwr_initbkp(bool writable) +{ + uint16_t regval; + + /* Make the HW not writable */ + + regval = at32_pwr_getreg32(AT32_PWC_CTRL_OFFSET); + regval &= ~PWC_CTRL_BPWEN; + at32_pwr_putreg32(AT32_PWC_CTRL_OFFSET, regval); + + /* Make the reference count agree */ + + g_bkp_writable_counter = 0; + at32_pwr_enablebkp(writable); +} + +/**************************************************************************** + * Name: at32_pwr_enablebkp + * + * Description: + * Enables access to the backup domain (RTC registers, RTC backup data + * registers and backup SRAM). + * + * NOTE: + * Reference counting is used in order to supported nested calls to this + * function. As a consequence, every call to at32_pwr_enablebkp(true) + * must be followed by a matching call to at32_pwr_enablebkp(false). + * + * Input Parameters: + * writable - True: enable ability to write to backup domain registers + * + * Returned Value: + * None + * + ****************************************************************************/ + +void at32_pwr_enablebkp(bool writable) +{ + irqstate_t flags; + uint16_t regval; + bool waswritable; + bool wait = false; + + flags = enter_critical_section(); + + /* Get the current state of the AT32 PWR control register */ + + regval = at32_pwr_getreg32(AT32_PWC_CTRL_OFFSET); + waswritable = ((regval & PWC_CTRL_BPWEN) != 0); + + if (writable) + { + DEBUGASSERT(g_bkp_writable_counter < UINT16_MAX); + g_bkp_writable_counter++; + } + else if (g_bkp_writable_counter > 0) + { + g_bkp_writable_counter--; + } + + /* Enable or disable the ability to write */ + + if (waswritable && g_bkp_writable_counter == 0) + { + /* Disable backup domain access */ + + regval &= ~PWC_CTRL_BPWEN; + at32_pwr_putreg32(AT32_PWC_CTRL_OFFSET, regval); + } + else if (!waswritable && g_bkp_writable_counter > 0) + { + /* Enable backup domain access */ + + regval |= PWC_CTRL_BPWEN; + at32_pwr_putreg32(AT32_PWC_CTRL_OFFSET, regval); + + wait = true; + } + + leave_critical_section(flags); + + if (wait) + { + /* Enable does not happen right away */ + + up_udelay(4); + } +} + +/**************************************************************************** + * Name: at32_pwr_enablewkup + * + * Description: + * Enables the WKUP pin. + * + * Input Parameters: + * wupin - Selects the WKUP pin to enable/disable + * wupon - state to set it to + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned on + * any failure. The only cause of failure is if the selected MCU does not + * support the requested wakeup pin. + * + ****************************************************************************/ + +int at32_pwr_enablewkup(enum at32_pwr_wupin_e wupin, bool wupon) +{ + uint16_t pinmask; + + /* Select the PWR_CSR bit associated with the requested wakeup pin */ + + switch (wupin) + { + case PWC_WUPIN_1: /* Wake-up pin 1 (all parts) */ + pinmask = PWC_CTRLSTS_SWPEN1; + break; + +#ifdef HAVE_PWR_WKUP2 + case PWC_WUPIN_2: /* Wake-up pin 2 */ + pinmask = PWC_CTRLSTS_SWPEN2; + break; +#endif + +#ifdef HAVE_PWR_WKUP3 + case PWC_WUPIN_3: /* Wake-up pin 3 */ + pinmask = PWR_CSR_EWUP3; + break; +#endif + + default: + return -EINVAL; + } + + /* Set/clear the the wakeup pin enable bit in the CSR. This must be done + * within a critical section because the CSR is shared with other functions + * that may be running concurrently on another thread. + */ + + if (wupon) + { + /* Enable the wakeup pin by setting the bit in the CSR. */ + + at32_pwr_modifyreg32(AT32_PWC_CTRLSTS_OFFSET, 0, pinmask); + } + else + { + /* Disable the wakeup pin by clearing the bit in the CSR. */ + + at32_pwr_modifyreg32(AT32_PWC_CTRLSTS_OFFSET, pinmask, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: at32_pwr_getsbf + * + * Description: + * Return the standby flag. + * + ****************************************************************************/ + +bool at32_pwr_getsbf(void) +{ + return (at32_pwr_getreg32(AT32_PWC_CTRLSTS_OFFSET) & PWC_CTRLSTS_SEF) != 0; +} + +/**************************************************************************** + * Name: at32_pwr_getwuf + * + * Description: + * Return the wakeup flag. + * + ****************************************************************************/ + +bool at32_pwr_getwuf(void) +{ + return (at32_pwr_getreg32(AT32_PWC_CTRLSTS_OFFSET) \ + & PWC_CTRLSTS_SWEF) != 0; +} + +/**************************************************************************** + * Name: at32_pwr_setpvd + * + * Description: + * Sets power voltage detector + * + * Input Parameters: + * pls - PVD level + * + * Returned Value: + * None + * + * Assumptions: + * At present, this function is called only from initialization logic. + * If used for any other purpose that protection to assure that its + * operation is atomic will be required. + * + ****************************************************************************/ + +void at32_pwr_setpvd(uint16_t pls) +{ + uint16_t regval; + + /* Set PLS */ + + regval = at32_pwr_getreg32(AT32_PWC_CTRL_OFFSET); + regval &= ~PWC_CTRL_PVMSEL_MASK; + regval |= (pls & PWC_CTRL_PVMSEL_MASK); + + /* Write value to register */ + + at32_pwr_putreg32(AT32_PWC_CTRL_OFFSET, regval); +} + +/**************************************************************************** + * Name: at32_pwr_enablepvd + * + * Description: + * Enable the Programmable Voltage Detector + * + ****************************************************************************/ + +void at32_pwr_enablepvd(void) +{ + /* Enable PVD by setting the PVDE bit in PWR_CR register. */ + + at32_pwr_modifyreg32(AT32_PWC_CTRL_OFFSET, 0, PWC_CTRL_PVMEN); +} + +/**************************************************************************** + * Name: at32_pwr_disablepvd + * + * Description: + * Disable the Programmable Voltage Detector + * + ****************************************************************************/ + +void at32_pwr_disablepvd(void) +{ + /* Disable PVD by clearing the PVDE bit in PWR_CR register. */ + + at32_pwr_modifyreg32(AT32_PWC_CTRL_OFFSET, PWC_CTRL_PVMEN, 0); +} + +#endif /* CONFIG_AT32_PWR */ diff --git a/arch/arm/src/at32/at32_pwr.h b/arch/arm/src/at32/at32_pwr.h new file mode 100644 index 0000000000..ed19cbcfe9 --- /dev/null +++ b/arch/arm/src/at32/at32_pwr.h @@ -0,0 +1,195 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_pwr.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_PWR_H +#define __ARCH_ARM_SRC_AT32_AT32_PWR_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "chip.h" +#include "hardware/at32_pwr.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Identify MCU-specific wakeup pin. + * Different AT32 parts support differing numbers of wakeup pins. + */ + +enum at32_pwr_wupin_e +{ + PWC_WUPIN_1 = 0, /* Wake-up pin 1 (all parts) */ + PWC_WUPIN_2, /* Wake-up pin 2 */ + PWC_WUPIN_3 /* Wake-up pin 3 */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_pwr_initbkp + * + * Description: + * Insures the referenced count access to the backup domain + * (RTC registers, RTC backup data registers and backup SRAM is consistent + * with the HW state without relying on a variable. + * + * NOTE: This function should only be called by SoC Start up code. + * + * Input Parameters: + * writable - set the initial state of the enable and the + * bkp_writable_counter + * + * Returned Value: + * None + * + ****************************************************************************/ + +void at32_pwr_initbkp(bool writable); + +/**************************************************************************** + * Name: at32_pwr_enablebkp + * + * Description: + * Enables access to the backup domain + * (RTC registers, RTC backup data registers and backup SRAM). + * + * NOTE: + * Reference counting is used in order to supported nested calls to this + * function. As a consequence, every call to at32_pwr_enablebkp(true) + * must be followed by a matching call to at32_pwr_enablebkp(false). + * + * Input Parameters: + * writable - True: enable ability to write to backup domain registers + * + * Returned Value: + * None + * + ****************************************************************************/ + +void at32_pwr_enablebkp(bool writable); + +/**************************************************************************** + * Name: at32_pwr_enablewkup + * + * Description: + * Enables the WKUP pin. + * + * Input Parameters: + * wupin - Selects the WKUP pin to enable/disable + * wupon - state to set it to + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned on + * any failure. The only cause of failure is if the selected MCU does not + * support the requested wakeup pin. + * + ****************************************************************************/ + +int at32_pwr_enablewkup(enum at32_pwr_wupin_e wupin, bool wupon); + +/**************************************************************************** + * Name: at32_pwr_getsbf + * + * Description: + * Return the standby flag. + * + ****************************************************************************/ + +bool at32_pwr_getsbf(void); + +/**************************************************************************** + * Name: at32_pwr_getwuf + * + * Description: + * Return the wakeup flag. + * + ****************************************************************************/ + +bool at32_pwr_getwuf(void); + +/**************************************************************************** + * Name: at32_pwr_setpvd + * + * Description: + * Sets power voltage detector for EnergyLite devices. + * + * Input Parameters: + * pls - PVD level + * + * Returned Value: + * None + * + * Assumptions: + * At present, this function is called only from initialization logic. + * + ****************************************************************************/ + +void at32_pwr_setpvd(uint16_t pls); + +/**************************************************************************** + * Name: at32_pwr_enablepvd + * + * Description: + * Enable the Programmable Voltage Detector + * + ****************************************************************************/ + +void at32_pwr_enablepvd(void); + +/**************************************************************************** + * Name: at32_pwr_disablepvd + * + * Description: + * Disable the Programmable Voltage Detector + * + ****************************************************************************/ + +void at32_pwr_disablepvd(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_PWR_H */ diff --git a/arch/arm/src/at32/at32_rcc.c b/arch/arm/src/at32/at32_rcc.c new file mode 100644 index 0000000000..e0f90472ed --- /dev/null +++ b/arch/arm/src/at32/at32_rcc.c @@ -0,0 +1,228 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_rcc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32_gpio.h" +#include "at32_rcc.h" +#include "at32_rtc.h" +#include "at32_flash.h" +#include "at32.h" +#include "at32_waste.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Allow up to 100 milliseconds for the high speed clock to become ready. + * that is a very long delay, but if the clock does not become ready we are + * hosed anyway. + */ + +#define HSERDY_TIMEOUT (100 * CONFIG_BOARD_LOOPSPERMSEC) + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/* Include chip-specific clocking initialization logic */ + +#if defined(CONFIG_AT32_AT32F43XX) +# include "at32f43xxx_rcc.c" +#else +# error "Unsupported AT32 chip" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +# define AT32_RCC_XXX AT32_CRM_BPDC +# define RCC_XXX_YYYRST CRM_BPDC_BPDRST + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rcc_resetbkp + * + * Description: + * The RTC needs to reset the Backup Domain to change RTCSEL and resetting + * the Backup Domain renders to disabling the LSE as consequence. + * In order to avoid resetting the Backup Domain when we already + * configured LSE we will reset the Backup Domain early (here). + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_AT32_RTC) && defined(CONFIG_AT32_PWR) +static inline void rcc_resetbkp(void) +{ + uint32_t regval; + + /* Check if the RTC is already configured */ + + at32_pwr_initbkp(false); + + regval = getreg32(RTC_MAGIC_REG); + if (regval != RTC_MAGIC && regval != RTC_MAGIC_TIME_SET) + { + at32_pwr_enablebkp(true); + + /* We might be changing RTCSEL - to ensure such changes work, we must + * reset the backup domain (having backed up the RTC_MAGIC token) + */ + + modifyreg32(AT32_RCC_XXX, 0, RCC_XXX_YYYRST); + modifyreg32(AT32_RCC_XXX, RCC_XXX_YYYRST, 0); + + at32_pwr_enablebkp(false); + } +} +#else +# define rcc_resetbkp() +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_clockconfig + * + * Description: + * Called to establish the clock settings based on the values in board.h. + * This function (by default) will reset most everything, enable the PLL, + * and enable peripheral clocking for all peripherals enabled in the NuttX + * configuration file. + * + * If CONFIG_ARCH_BOARD_AT32_CUSTOM_CLOCKCONFIG is defined, then clocking + * will be enabled by an externally provided, board-specific function + * called at32_board_clockconfig(). + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void at32_clockconfig(void) +{ + /* Make sure that we are starting in the reset state */ + + rcc_reset(); + + /* Reset backup domain if appropriate */ + + rcc_resetbkp(); + +#if defined(CONFIG_ARCH_BOARD_AT32_CUSTOM_CLOCKCONFIG) + + /* Invoke Board Custom Clock Configuration */ + + at32_board_clockconfig(); + +#else + + /* Invoke standard, fixed clock configuration based on definitions + * in board.h + */ + + at32_stdclockconfig(); + +#endif + + /* Enable peripheral clocking */ + + rcc_enableperipherals(); + +#ifdef CONFIG_AT32_SYSCFG_IOCOMPENSATION + /* Enable I/O Compensation */ + + at32_iocompensation(); +#endif +} + +/**************************************************************************** + * Name: at32_clockenable + * + * Description: + * Re-enable the clock and restore the clock settings based on settings + * in board.h. This function is only available to support low-power + * modes of operation: When re-awakening from deep-sleep modes, it is + * necessary to re-enable/re-start the PLL + * + * This functional performs a subset of the operations performed by + * at32_clockconfig(): It does not reset any devices, and it does not + * reset the currently enabled peripheral clocks. + * + * If CONFIG_ARCH_BOARD_AT32_CUSTOM_CLOCKCONFIG is defined, then clocking + * will be enabled by an externally provided, board-specific function + * called at32_board_clockconfig(). + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_PM +void at32_clockenable(void) +{ +#if defined(CONFIG_ARCH_BOARD_AT32_CUSTOM_CLOCKCONFIG) + + /* Invoke Board Custom Clock Configuration */ + + at32_board_clockconfig(); + +#else + + /* Invoke standard, fixed clock configuration based on definitions + * in board.h + */ + + at32_stdclockconfig(); + +#endif +} +#endif diff --git a/arch/arm/src/at32/at32_rcc.h b/arch/arm/src/at32/at32_rcc.h new file mode 100644 index 0000000000..a1639dc65d --- /dev/null +++ b/arch/arm/src/at32/at32_rcc.h @@ -0,0 +1,233 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_rcc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_RCC_H +#define __ARCH_ARM_SRC_AT32_AT32_RCC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "arm_internal.h" +#include "chip.h" + +#if defined(CONFIG_AT32_AT32F43XX) +# include "hardware/at32f43xxx_rcc.h" +#else +# error "Unsupported AT32 chip" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_mco1config + * + * Description: + * Selects the clock source to output on MCO1 pin (PA8). PA8 should be + * configured in alternate function mode. + * + * Input Parameters: + * source - One of the definitions for the RCC_CFGR_MCO1 definitions from + * chip/at32f4xxxx_rcc.h {RCC_CFGR_MCO1_HSI, RCC_CFGR_MCO1_LSE, + * RCC_CFGR_MCO1_HSE, RCC_CFGR_MCO1_PLL} + * div - One of the definitions for the RCC_CFGR_MCO1PRE definitions from + * chip/at32f4xxxx_rcc.h {RCC_CFGR_MCO1PRE_NONE, RCC_CFGR_MCO1PRE_DIV2, + * RCC_CFGR_MCO1PRE_DIV3, RCC_CFGR_MCO1PRE_DIV4, RCC_CFGR_MCO1PRE_DIV5} + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_AT32_AT32F43XX) +static inline void at32_mco1config(uint32_t source, uint32_t div) +{ + uint32_t regval; + + regval = getreg32(AT32_CRM_CFG); + regval &= ~(CRM_CFG_CLKOUT1_SEL_MASK | CRM_CFG_CLKOUT1DIV1_MASK); + regval |= (source | div); + putreg32(regval, AT32_CRM_CFG); +} +#endif + +/**************************************************************************** + * Name: at32_mco2config + * + * Description: + * Selects the clock source to output on MCO2 pin (PC9). PC9 should be + * configured in alternate function mode. + * + * Input Parameters: + * source - One of the definitions for the RCC_CFGR_MCO2 definitions from + * chip/at32f4xxxx_rcc.h {RCC_CFGR_MCO2_SYSCLK, RCC_CFGR_MCO2_PLLI2S, + * RCC_CFGR_MCO2_HSE, RCC_CFGR_MCO2_PLL} + * div - One of the definitions for the RCC_CFGR_MCO2PRE definitions from + * chip/at32f4xxxx_rcc.h {RCC_CFGR_MCO2PRE_NONE, RCC_CFGR_MCO2PRE_DIV2, + * RCC_CFGR_MCO2PRE_DIV3, RCC_CFGR_MCO2PRE_DIV4, RCC_CFGR_MCO2PRE_DIV5} + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_AT32_AT32F43XX) +static inline void at32_mco2config(uint32_t source, uint32_t div) +{ + uint32_t regval; + + regval = getreg32(AT32_CRM_CFG); + regval &= ~(CRM_CFG_CLKOUT2_SEL1_MASK | CRM_CFG_CLKOUT2DIV1_MASK); + regval |= (source | div); + putreg32(regval, AT32_CRM_CFG); +} +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_clockconfig + * + * Description: + * Called to establish the clock settings based on the values in board.h. + * This function (by default) will reset most everything, enable the PLL, + * and enable peripheral clocking for all periperipherals enabled in the + * NuttX configuration file. + * + * If CONFIG_ARCH_BOARD_AT32_CUSTOM_CLOCKCONFIG is defined, then clocking + * will be enabled by an externally provided, board-specific function + * called at32_board_clockconfig(). + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void at32_clockconfig(void); + +/**************************************************************************** + * Name: at32_board_clockconfig + * + * Description: + * Any AT32 board may replace the "standard" board clock configuration + * logic with its own, custom clock configuration logic. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_BOARD_AT32_CUSTOM_CLOCKCONFIG +void at32_board_clockconfig(void); +#endif + +/**************************************************************************** + * Name: at32_clockenable + * + * Description: + * Re-enable the clock and restore the clock settings based on settings in + * board.h. + * This function is only available to support low-power modes of operation: + * When re-awakening from deep-sleep modes, it is necessary to re-enable/ + * re-start the PLL + * + * This functional performs a subset of the operations performed by + * at32_clockconfig(): It does not reset any devices, and it does not + * reset the currently enabled peripheral clocks. + * + * If CONFIG_ARCH_BOARD_AT32_CUSTOM_CLOCKCONFIG is defined, then clocking + * will be enabled by an externally provided, board-specific function + * called at32_board_clockconfig(). + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_PM +void at32_clockenable(void); +#endif + +/**************************************************************************** + * Name: at32_rcc_enablelse + * + * Description: + * Enable the External Low-Speed (LSE) Oscillator. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void at32_rcc_enablelse(void); + +/**************************************************************************** + * Name: at32_rcc_enablelsi + * + * Description: + * Enable the Internal Low-Speed (LSI) RC Oscillator. + * + ****************************************************************************/ + +void at32_rcc_enablelsi(void); + +/**************************************************************************** + * Name: at32_rcc_disablelsi + * + * Description: + * Disable the Internal Low-Speed (LSI) RC Oscillator. + * + ****************************************************************************/ + +void at32_rcc_disablelsi(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_RCC_H */ diff --git a/arch/arm/src/at32/at32_rtc.c b/arch/arm/src/at32/at32_rtc.c new file mode 100644 index 0000000000..031b00b24b --- /dev/null +++ b/arch/arm/src/at32/at32_rtc.c @@ -0,0 +1,42 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_rtc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/* This file is only a thin shell that includes the correct RTC + * implementation for the selected AT32 family. The correct file cannot be + * selected by the make system because it needs the intelligence that only + * exists in chip.h that can associate an AT32 part number with an AT32 + * family. + */ + +#if defined(CONFIG_AT32_AT32F43XX) +# include "at32f43xxx_rtcc.c" +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ diff --git a/arch/arm/src/at32/at32_rtc.h b/arch/arm/src/at32/at32_rtc.h new file mode 100644 index 0000000000..bb38394a19 --- /dev/null +++ b/arch/arm/src/at32/at32_rtc.h @@ -0,0 +1,188 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_rtc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_RTC_H +#define __ARCH_ARM_SRC_AT32_AT32_RTC_H + +#include + +#include "chip.h" + +#if defined(CONFIG_AT32_AT32F43XX) +# include "hardware/at32_rtcc.h" +#endif + +/* Alarm function differs from part to part */ + +#if defined(CONFIG_AT32_AT32F43XX) +# include "at32f43xxx_alarm.h" +#else +# include "at32_alarm.h" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define AT32_RTC_PRESCALER_SECOND 32767 /* Default prescaler to get a + * second base */ +#define AT32_RTC_PRESCALER_MIN 1 /* Maximum speed of 16384 Hz */ + +#if !defined(CONFIG_AT32_RTC_MAGIC) +# define CONFIG_AT32_RTC_MAGIC (0xfacefeed) +#endif + +#if !defined(CONFIG_AT32_RTC_MAGIC_TIME_SET) +# define CONFIG_AT32_RTC_MAGIC_TIME_SET (0xf00dface) +#endif + +#if !defined(CONFIG_AT32_RTC_MAGIC_REG) +# define CONFIG_AT32_RTC_MAGIC_REG (0) +#endif + +#define RTC_MAGIC_REG AT32_RTC_BKR(CONFIG_AT32_RTC_MAGIC_REG) + +#define RTC_MAGIC CONFIG_AT32_RTC_MAGIC +#define RTC_MAGIC_TIME_SET CONFIG_AT32_RTC_MAGIC_TIME_SET + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_rtc_irqinitialize + * + * Description: + * Initialize IRQs for RTC, not possible during up_rtc_initialize because + * up_irqinitialize is called later. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int at32_rtc_irqinitialize(void); + +/**************************************************************************** + * Name: at32_rtc_getdatetime_with_subseconds + * + * Description: + * Get the current date and time from the date/time RTC. This interface + * is only supported by the date/time RTC hardware implementation. + * It is used to replace the system timer. It is only used by the RTOS + * during initialization to set up the system time when CONFIG_RTC and + * CONFIG_RTC_DATETIME are selected (and CONFIG_RTC_HIRES is not). + * + * NOTE: Some date/time RTC hardware is capability of sub-second accuracy. + * Thatsub-second accuracy is returned through 'nsec'. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * nsec - The location to return the subsecond time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_HAVE_RTC_SUBSECONDS +int at32_rtc_getdatetime_with_subseconds(struct tm *tp, long *nsec); +#endif + +/**************************************************************************** + * Name: at32_rtc_setdatetime + * + * Description: + * Set the RTC to the provided time. RTC implementations which provide + * up_rtc_getdatetime() (CONFIG_RTC_DATETIME is selected) should provide + * this function. + * + * Input Parameters: + * tp - the time to use + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_DATETIME +struct tm; +int at32_rtc_setdatetime(const struct tm *tp); +#endif + +/**************************************************************************** + * Name: at32_rtc_lowerhalf + * + * Description: + * Instantiate the RTC lower half driver for the AT32. General usage: + * + * #include + * #include "at32_rtc.h" + * + * struct rtc_lowerhalf_s *lower; + * lower = at32_rtc_lowerhalf(); + * rtc_initialize(0, lower); + * + * Input Parameters: + * None + * + * Returned Value: + * On success, a non-NULL RTC lower interface is returned. NULL is + * returned on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_DRIVER +struct rtc_lowerhalf_s; +struct rtc_lowerhalf_s *at32_rtc_lowerhalf(void); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_RTC_H */ diff --git a/arch/arm/src/at32/at32_rtc_lowerhalf.c b/arch/arm/src/at32/at32_rtc_lowerhalf.c new file mode 100644 index 0000000000..b23e186115 --- /dev/null +++ b/arch/arm/src/at32/at32_rtc_lowerhalf.c @@ -0,0 +1,915 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_rtc_lowerhalf.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32_rtc.h" + +#ifdef CONFIG_RTC_DRIVER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_AT32_AT32F43XX) +# define AT32_NALARMS 2 +#else +# define AT32_NALARMS 1 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +struct at32_cbinfo_s +{ + volatile rtc_alarm_callback_t cb; /* Callback when the alarm expires */ + volatile void *priv; /* Private argument to accompany callback */ +#if defined(CONFIG_AT32_AT32F43XX) + uint8_t id; /* Identifies the alarm */ +#endif +}; +#endif + +/* This is the private type for the RTC state. It must be cast compatible + * with struct rtc_lowerhalf_s. + */ + +struct at32_lowerhalf_s +{ + /* This is the contained reference to the read-only, lower-half + * operations vtable (which may lie in FLASH or ROM) + */ + + const struct rtc_ops_s *ops; + + /* Data following is private to this driver and not visible outside of + * this file. + */ + + mutex_t devlock; /* Threads can only exclusively access the RTC */ + +#ifdef CONFIG_RTC_ALARM + /* Alarm callback information */ + + struct at32_cbinfo_s cbinfo[AT32_NALARMS]; +#endif + +#ifdef CONFIG_RTC_PERIODIC + /* Periodic wakeup information */ + + struct lower_setperiodic_s periodic; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Prototypes for static methods in struct rtc_ops_s */ + +static int at32_rdtime(struct rtc_lowerhalf_s *lower, + struct rtc_time *rtctime); +static int at32_settime(struct rtc_lowerhalf_s *lower, + const struct rtc_time *rtctime); +static bool at32_havesettime(struct rtc_lowerhalf_s *lower); + +#ifdef CONFIG_RTC_ALARM +static int at32_setalarm(struct rtc_lowerhalf_s *lower, + const struct lower_setalarm_s *alarminfo); +static int at32_setrelative(struct rtc_lowerhalf_s *lower, + const struct lower_setrelative_s *alarminfo); +static int at32_cancelalarm(struct rtc_lowerhalf_s *lower, + int alarmid); +static int at32_rdalarm(struct rtc_lowerhalf_s *lower, + struct lower_rdalarm_s *alarminfo); +#endif + +#ifdef CONFIG_RTC_PERIODIC +static int at32_setperiodic(struct rtc_lowerhalf_s *lower, + const struct lower_setperiodic_s *alarminfo); +static int at32_cancelperiodic(struct rtc_lowerhalf_s *lower, int id); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* AT32 RTC driver operations */ + +static const struct rtc_ops_s g_rtc_ops = +{ + .rdtime = at32_rdtime, + .settime = at32_settime, + .havesettime = at32_havesettime, +#ifdef CONFIG_RTC_ALARM + .setalarm = at32_setalarm, + .setrelative = at32_setrelative, + .cancelalarm = at32_cancelalarm, + .rdalarm = at32_rdalarm, +#endif +#ifdef CONFIG_RTC_PERIODIC + .setperiodic = at32_setperiodic, + .cancelperiodic = at32_cancelperiodic, +#endif +}; + +/* AT32 RTC device state */ + +static struct at32_lowerhalf_s g_rtc_lowerhalf = +{ + .ops = &g_rtc_ops, + .devlock = NXMUTEX_INITIALIZER, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_alarm_callback + * + * Description: + * This is the function that is called from the RTC driver when the alarm + * goes off. It just invokes the upper half drivers callback. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +#if defined(CONFIG_AT32_AT32F43XX) +static void at32_alarm_callback(void *arg, unsigned int alarmid) +{ + struct at32_lowerhalf_s *lower; + struct at32_cbinfo_s *cbinfo; + rtc_alarm_callback_t cb; + void *priv; + + DEBUGASSERT(alarmid == RTC_ALARMA || alarmid == RTC_ALARMB); + + lower = (struct at32_lowerhalf_s *)arg; + cbinfo = &lower->cbinfo[alarmid]; + + /* Sample and clear the callback information to minimize the window in + * time in which race conditions can occur. + */ + + cb = (rtc_alarm_callback_t)cbinfo->cb; + priv = (void *)cbinfo->priv; + DEBUGASSERT(priv != NULL); + + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + /* Perform the callback */ + + if (cb != NULL) + { + cb(priv, alarmid); + } +} + +#else +static void at32_alarm_callback(void) +{ + struct at32_cbinfo_s *cbinfo = &g_rtc_lowerhalf.cbinfo[0]; + + /* Sample and clear the callback information to minimize the window in + * time in which race conditions can occur. + */ + + rtc_alarm_callback_t cb = (rtc_alarm_callback_t)cbinfo->cb; + void *arg = (void *)cbinfo->priv; + + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + /* Perform the callback */ + + if (cb != NULL) + { + cb(arg, 0); + } +} + +#endif /* CONFIG_AT32_AT32F43XX*/ +#endif /* CONFIG_RTC_ALARM */ + +/**************************************************************************** + * Name: at32_rdtime + * + * Description: + * Implements the rdtime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * rcttime - The location in which to return the current RTC time. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +static int at32_rdtime(struct rtc_lowerhalf_s *lower, + struct rtc_time *rtctime) +{ +#if defined(CONFIG_RTC_DATETIME) + /* This operation depends on the fact that struct rtc_time is cast + * compatible with struct tm. + */ + + return up_rtc_getdatetime((struct tm *)rtctime); + +#elif defined(CONFIG_RTC_HIRES) + struct timespec ts; + int ret; + + /* Get the higher resolution time */ + + ret = up_rtc_gettime(&ts); + if (ret < 0) + { + goto errout; + } + + /* Convert the one second epoch time to a struct tm. This operation + * depends on the fact that struct rtc_time and struct tm are cast + * compatible. + */ + + if (!gmtime_r(&ts.tv_sec, (struct tm *)rtctime)) + { + ret = -get_errno(); + goto errout; + } + + return OK; + +errout: + DEBUGASSERT(ret < 0); + return ret; + +#else + time_t timer; + + /* The resolution of time is only 1 second */ + + timer = up_rtc_time(); + + /* Convert the one second epoch time to a struct tm */ + + if (!gmtime_r(&timer, (struct tm *)rtctime)) + { + int errcode = get_errno(); + DEBUGASSERT(errcode > 0); + return -errcode; + } + + return OK; +#endif +} + +/**************************************************************************** + * Name: at32_settime + * + * Description: + * Implements the settime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * rcttime - The new time to set + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +static int at32_settime(struct rtc_lowerhalf_s *lower, + const struct rtc_time *rtctime) +{ +#ifdef CONFIG_RTC_DATETIME + /* This operation depends on the fact that struct rtc_time is cast + * compatible with struct tm. + */ + + return at32_rtc_setdatetime((const struct tm *)rtctime); + +#else + struct timespec ts; + + /* Convert the struct rtc_time to a time_t. Here we assume that struct + * rtc_time is cast compatible with struct tm. + */ + + ts.tv_sec = timegm((struct tm *)rtctime); + ts.tv_nsec = 0; + + /* Now set the time (to one second accuracy) */ + + return up_rtc_settime(&ts); +#endif +} + +/**************************************************************************** + * Name: at32_havesettime + * + * Description: + * Implements the havesettime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * + * Returned Value: + * Returns true if RTC date-time have been previously set. + * + ****************************************************************************/ + +static bool at32_havesettime(struct rtc_lowerhalf_s *lower) +{ + return getreg32(RTC_MAGIC_REG) == RTC_MAGIC_TIME_SET; +} + +/**************************************************************************** + * Name: at32_setalarm + * + * Description: + * Set a new alarm. This function implements the setalarm() method of the + * RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int at32_setalarm(struct rtc_lowerhalf_s *lower, + const struct lower_setalarm_s *alarminfo) +{ +#if defined(CONFIG_AT32_AT32F43XX) + struct at32_lowerhalf_s *priv; + struct at32_cbinfo_s *cbinfo; + struct alm_setalarm_s lowerinfo; + int ret; + + /* ID0-> Alarm A; ID1 -> Alarm B */ + + DEBUGASSERT(lower != NULL && alarminfo != NULL); + DEBUGASSERT(alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB); + priv = (struct at32_lowerhalf_s *)lower; + + ret = nxmutex_lock(&priv->devlock); + if (ret < 0) + { + return ret; + } + + ret = -EINVAL; + if (alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB) + { + /* Remember the callback information */ + + cbinfo = &priv->cbinfo[alarminfo->id]; + cbinfo->cb = alarminfo->cb; + cbinfo->priv = alarminfo->priv; + cbinfo->id = alarminfo->id; + + /* Set the alarm */ + + lowerinfo.as_id = alarminfo->id; + lowerinfo.as_cb = at32_alarm_callback; + lowerinfo.as_arg = priv; + memcpy(&lowerinfo.as_time, &alarminfo->time, sizeof(struct tm)); + + /* And set the alarm */ + + ret = at32_rtc_setalarm(&lowerinfo); + if (ret < 0) + { + cbinfo->cb = NULL; + cbinfo->priv = NULL; + } + } + + nxmutex_unlock(&priv->devlock); + return ret; + +#else + struct at32_lowerhalf_s *priv; + struct at32_cbinfo_s *cbinfo; + int ret; + + DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->id == 0); + priv = (struct at32_lowerhalf_s *)lower; + + ret = nxmutex_lock(&priv->devlock); + if (ret < 0) + { + return ret; + } + + ret = -EINVAL; + if (alarminfo->id == 0) + { + struct timespec ts; + + /* Convert the RTC time to a timespec (1 second accuracy) */ + + ts.tv_sec = timegm((struct tm *)&alarminfo->time); + ts.tv_nsec = 0; + + /* Remember the callback information */ + + cbinfo = &priv->cbinfo[0]; + cbinfo->cb = alarminfo->cb; + cbinfo->priv = alarminfo->priv; + + /* And set the alarm */ + + ret = at32_rtc_setalarm(&ts, at32_alarm_callback); + if (ret < 0) + { + cbinfo->cb = NULL; + cbinfo->priv = NULL; + } + } + + nxmutex_unlock(&priv->devlock); + return ret; +#endif +} +#endif + +/**************************************************************************** + * Name: at32_setrelative + * + * Description: + * Set a new alarm relative to the current time. This function implements + * the setrelative() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int at32_setrelative(struct rtc_lowerhalf_s *lower, + const struct lower_setrelative_s *alarminfo) +{ +#if defined(CONFIG_AT32_AT32F43XX) + struct lower_setalarm_s setalarm; + struct tm time; + time_t seconds; + int ret = -EINVAL; + + DEBUGASSERT(lower != NULL && alarminfo != NULL); + DEBUGASSERT(alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB); + + if ((alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB) && + alarminfo->reltime > 0) + { + /* Disable pre-emption while we do this so that we don't have to worry + * about being suspended and working on an old time. + */ + + sched_lock(); + + /* Get the current time in broken out format */ + + ret = up_rtc_getdatetime(&time); + if (ret >= 0) + { + /* Convert to seconds since the epoch */ + + seconds = timegm(&time); + + /* Add the seconds offset. Add one to the number of seconds + * because we are unsure of the phase of the timer. + */ + + seconds += (alarminfo->reltime + 1); + + /* And convert the time back to broken out format */ + + gmtime_r(&seconds, (struct tm *)&setalarm.time); + + /* The set the alarm using this absolute time */ + + setalarm.id = alarminfo->id; + setalarm.cb = alarminfo->cb; + setalarm.priv = alarminfo->priv; + + ret = at32_setalarm(lower, &setalarm); + } + + sched_unlock(); + } + + return ret; + +#else + struct at32_lowerhalf_s *priv; + struct at32_cbinfo_s *cbinfo; +#if defined(CONFIG_RTC_DATETIME) + struct tm time; +#endif + struct timespec ts; + int ret = -EINVAL; + + DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->id == 0); + priv = (struct at32_lowerhalf_s *)lower; + + if (alarminfo->id == 0 && alarminfo->reltime > 0) + { + /* Disable pre-emption while we do this so that we don't have to worry + * about being suspended and working on an old time. + */ + + sched_lock(); + + /* Get the current time in seconds */ + +#if defined(CONFIG_RTC_DATETIME) + /* Get the broken out time and convert to seconds */ + + ret = up_rtc_getdatetime(&time); + if (ret < 0) + { + sched_unlock(); + return ret; + } + + ts.tv_sec = timegm(&time); + ts.tv_nsec = 0; + +#elif defined(CONFIG_RTC_HIRES) + /* Get the higher resolution time */ + + ret = up_rtc_gettime(&ts); + if (ret < 0) + { + sched_unlock(); + return ret; + } +#else + /* The resolution of time is only 1 second */ + + ts.tv_sec = up_rtc_time(); + ts.tv_nsec = 0; +#endif + + /* Add the seconds offset. Add one to the number of seconds because + * we are unsure of the phase of the timer. + */ + + ts.tv_sec += (alarminfo->reltime + 1); + + /* Remember the callback information */ + + cbinfo = &priv->cbinfo[0]; + cbinfo->cb = alarminfo->cb; + cbinfo->priv = alarminfo->priv; + + /* And set the alarm */ + + ret = at32_rtc_setalarm(&ts, at32_alarm_callback); + if (ret < 0) + { + cbinfo->cb = NULL; + cbinfo->priv = NULL; + } + + sched_unlock(); + } + + return ret; +#endif +} +#endif + +/**************************************************************************** + * Name: at32_cancelalarm + * + * Description: + * Cancel the current alarm. This function implements the cancelalarm() + * method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int at32_cancelalarm(struct rtc_lowerhalf_s *lower, int alarmid) +{ +#if defined(CONFIG_AT32_AT32F43XX) + struct at32_lowerhalf_s *priv; + struct at32_cbinfo_s *cbinfo; + int ret; + + DEBUGASSERT(lower != NULL); + DEBUGASSERT(alarmid == RTC_ALARMA || alarmid == RTC_ALARMB); + priv = (struct at32_lowerhalf_s *)lower; + + ret = nxmutex_lock(&priv->devlock); + if (ret < 0) + { + return ret; + } + + /* ID0-> Alarm A; ID1 -> Alarm B */ + + ret = -EINVAL; + if (alarmid == RTC_ALARMA || alarmid == RTC_ALARMB) + { + /* Nullify callback information to reduce window for race conditions */ + + cbinfo = &priv->cbinfo[alarmid]; + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + /* Then cancel the alarm */ + + ret = at32_rtc_cancelalarm((enum alm_id_e)alarmid); + } + + nxmutex_unlock(&priv->devlock); + return ret; + +#else + struct at32_lowerhalf_s *priv; + struct at32_cbinfo_s *cbinfo; + + DEBUGASSERT(lower != NULL); + DEBUGASSERT(alarmid == 0); + priv = (struct at32_lowerhalf_s *)lower; + + /* Nullify callback information to reduce window for race conditions */ + + cbinfo = &priv->cbinfo[0]; + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + /* Then cancel the alarm */ + + return at32_rtc_cancelalarm(); +#endif +} +#endif + +/**************************************************************************** + * Name: at32_rdalarm + * + * Description: + * Query the RTC alarm. + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to query the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int at32_rdalarm(struct rtc_lowerhalf_s *lower, + struct lower_rdalarm_s *alarminfo) +{ + struct alm_rdalarm_s lowerinfo; + int ret = -EINVAL; + + DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->time != NULL); + DEBUGASSERT(alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB); + + if (alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB) + { + /* Disable pre-emption while we do this so that we don't have to worry + * about being suspended and working on an old time. + */ + + sched_lock(); + + lowerinfo.ar_id = alarminfo->id; + lowerinfo.ar_time = alarminfo->time; + + ret = at32_rtc_rdalarm(&lowerinfo); + + sched_unlock(); + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: at32_periodic_callback + * + * Description: + * This is the function that is called from the RTC driver when the + * periodic wakeup goes off. It just invokes the upper half drivers + * callback. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +static int at32_periodic_callback(void) +{ + struct at32_lowerhalf_s *lower; + struct lower_setperiodic_s *cbinfo; + rtc_wakeup_callback_t cb; + void *priv; + + lower = (struct at32_lowerhalf_s *)&g_rtc_lowerhalf; + + cbinfo = &lower->periodic; + cb = (rtc_wakeup_callback_t)cbinfo->cb; + priv = (void *)cbinfo->priv; + + /* Perform the callback */ + + if (cb != NULL) + { + cb(priv, 0); + } + + return OK; +} +#endif /* CONFIG_RTC_PERIODIC */ + +/**************************************************************************** + * Name: at32_setperiodic + * + * Description: + * Set a new periodic wakeup relative to the current time, with a given + * period. This function implements the setperiodic() method of the RTC + * driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the wakeup activity + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +static int at32_setperiodic(struct rtc_lowerhalf_s *lower, + const struct lower_setperiodic_s *alarminfo) +{ + struct at32_lowerhalf_s *priv; + int ret; + + DEBUGASSERT(lower != NULL && alarminfo != NULL); + priv = (struct at32_lowerhalf_s *)lower; + + ret = nxmutex_lock(&priv->devlock); + if (ret < 0) + { + return ret; + } + + memcpy(&priv->periodic, alarminfo, sizeof(struct lower_setperiodic_s)); + ret = at32_rtc_setperiodic(&alarminfo->period, at32_periodic_callback); + + nxmutex_unlock(&priv->devlock); + return ret; +} +#endif + +/**************************************************************************** + * Name: at32_cancelperiodic + * + * Description: + * Cancel the current periodic wakeup activity. This function implements + * the cancelperiodic() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +static int at32_cancelperiodic(struct rtc_lowerhalf_s *lower, int id) +{ + struct at32_lowerhalf_s *priv; + int ret; + + DEBUGASSERT(lower != NULL); + priv = (struct at32_lowerhalf_s *)lower; + + DEBUGASSERT(id == 0); + + ret = nxmutex_lock(&priv->devlock); + if (ret < 0) + { + return ret; + } + + ret = at32_rtc_cancelperiodic(); + + nxmutex_unlock(&priv->devlock); + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_rtc_lowerhalf + * + * Description: + * Instantiate the RTC lower half driver for the AT32. General usage: + * + * #include + * #include "at32_rtc.h> + * + * struct rtc_lowerhalf_s *lower; + * lower = at32_rtc_lowerhalf(); + * rtc_initialize(0, lower); + * + * Input Parameters: + * None + * + * Returned Value: + * On success, a non-NULL RTC lower interface is returned. NULL is + * returned on any failure. + * + ****************************************************************************/ + +struct rtc_lowerhalf_s *at32_rtc_lowerhalf(void) +{ + return (struct rtc_lowerhalf_s *)&g_rtc_lowerhalf; +} + +#endif /* CONFIG_RTC_DRIVER */ diff --git a/arch/arm/src/at32/at32_sdio.c b/arch/arm/src/at32/at32_sdio.c new file mode 100644 index 0000000000..62df884a30 --- /dev/null +++ b/arch/arm/src/at32/at32_sdio.c @@ -0,0 +1,3177 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_sdio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "chip.h" +#include "arm_internal.h" +#include "at32.h" +#include "at32_dma.h" +#include "at32_sdio.h" + +#ifdef CONFIG_AT32_SDIO + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Required system configuration options: + * + * CONFIG_ARCH_DMA - Enable architecture-specific DMA subsystem + * initialization. Required if CONFIG_AT32_SDIO_DMA is enabled. + * CONFIG_AT32_DMA2 - Enable AT32 DMA2 support. Required if + * CONFIG_AT32_SDIO_DMA is enabled + * CONFIG_SCHED_WORKQUEUE -- Callback support requires work queue support. + * + * Driver-specific configuration options: + * + * CONFIG_SDIO_MUXBUS - Setting this configuration enables some locking + * APIs to manage concurrent accesses on the SDIO bus. This is not + * needed for the simple case of a single SD card, for example. + * CONFIG_AT32_SDIO_DMA - Enable SDIO. This is a marginally optional. + * For most usages, SDIO will cause data overruns if used without DMA. + * NOTE the above system DMA configuration options. + * CONFIG_AT32_SDIO_WIDTH_D1_ONLY - This may be selected to force the + * driver operate with only a single data line (the default is to use + * all 4 SD data lines). + * CONFIG_SDM_DMAPRIO - SDIO DMA priority. This can be selected if + * CONFIG_AT32_SDIO_DMA is enabled. + * CONFIG_SDIO_XFRDEBUG - Enables some very low-level debug output + * This also requires CONFIG_DEBUG_FS and CONFIG_DEBUG_INFO + */ + +#if !defined(CONFIG_AT32_SDIO_DMA) +# warning "Large Non-DMA transfer may result in RX overrun failures" +#else +# ifndef CONFIG_AT32_DMA2 +# error "CONFIG_AT32_SDIO_DMA support requires CONFIG_AT32_DMA2" +# endif +# ifndef CONFIG_SDIO_DMA +# error CONFIG_SDIO_DMA must be defined with CONFIG_AT32_SDIO_DMA +# endif +#endif + +#ifndef CONFIG_AT32_SDIO_DMA +# warning "Large Non-DMA transfer may result in RX overrun failures" +#endif + +#ifndef CONFIG_SCHED_WORKQUEUE +# error "Callback support requires CONFIG_SCHED_WORKQUEUE" +#endif + +#ifdef CONFIG_AT32_SDIO_DMA +# ifndef CONFIG_AT32_SDIO_DMAPRIO +# if defined(CONFIG_AT32_AT32F43XX) +# define CONFIG_AT32_SDIO_DMAPRIO DMA_CCR_PRIMED +# else +# error "Unknown AT32 DMA" +# endif +# endif +# if defined(CONFIG_AT32_AT32F43XX) +# if (CONFIG_AT32_SDIO_DMAPRIO & ~DMA_CCR_PL_MASK) != 0 +# error "Illegal value for CONFIG_AT32_SDIO_DMAPRIO" +# endif +# else +# error "Unknown AT32 DMA" +# endif +#else +# undef CONFIG_AT32_SDIO_DMAPRIO +#endif + +#ifndef CONFIG_DEBUG_MEMCARD_INFO +# undef CONFIG_SDIO_XFRDEBUG +#endif + +/* Enable the SDIO pull-up resistors if needed */ + +#ifdef CONFIG_AT32_SDIO_PULLUP +# define SDIO_PULLUP_ENABLE GPIO_PULLUP +#else +# define SDIO_PULLUP_ENABLE 0 +#endif + +/* Friendly CLKCR bit re-definitions ****************************************/ + +#define SDIO_CLKCR_RISINGEDGE (0) +#define SDIO_CLKCR_FALLINGEDGE SDIO_CLKCR_NEGEDGE + +/* Use the default of the rising edge but allow a configuration, + * that does not have the errata, to override the edge the SDIO + * command and data is changed on. + */ + +#if !defined(SDIO_CLKCR_EDGE) +# define SDIO_CLKCR_EDGE SDIO_CLKCR_RISINGEDGE +#endif + +/* Mode dependent settings. These depend on clock divisor settings that must + * be defined in the board-specific board.h header file: SDIO_INIT_CLKDIV, + * SDIO_MMCXFR_CLKDIV, and SDIO_SDXFR_CLKDIV. + */ + +#if (SDIO_INIT_CLKDIV > 0xff) +#define AT32_CLCKCR_INIT ((SDIO_INIT_CLKDIV & 0xff) | SDIO_CLKCR_EDGE | \ + SDIO_CLKCR_WIDBUS_D1 | ((SDIO_INIT_CLKDIV >> 8) << SDIO_CLKCR_CLKDIV89_SHIFT)) +#else +#define AT32_CLCKCR_INIT (SDIO_INIT_CLKDIV | SDIO_CLKCR_EDGE | \ + SDIO_CLKCR_WIDBUS_D1) +#endif + +#define SDIO_CLKCR_MMCXFR (SDIO_MMCXFR_CLKDIV | SDIO_CLKCR_EDGE | \ + SDIO_CLKCR_WIDBUS_D1) +#define SDIO_CLCKR_SDXFR (SDIO_SDXFR_CLKDIV | SDIO_CLKCR_EDGE | \ + SDIO_CLKCR_WIDBUS_D1) +#define SDIO_CLCKR_SDWIDEXFR (SDIO_SDXFR_CLKDIV | SDIO_CLKCR_EDGE | \ + SDIO_CLKCR_WIDBUS_D4) + +/* Timing */ + +#define SDIO_CMDTIMEOUT (100000) +#define SDIO_LONGTIMEOUT (0x7fffffff) + +/* DTIMER setting */ + +/* Assuming Max timeout in bypass 48 Mhz */ + +#define IP_CLCK_FREQ UINT32_C(48000000) +#define SDIO_DTIMER_DATATIMEOUT_MS 250 + +/* DMA channel/stream configuration register settings. The following + * must be selected. The DMA driver will select the remaining fields. + * + * - 32-bit DMA + * - Memory increment + * - Direction (memory-to-peripheral, peripheral-to-memory) + * - Memory burst size (F4 only) + */ + +/* AT32 F1 channel configuration register (CCR) settings */ + +#if defined(CONFIG_AT32_AT32F43XX) +# define SDIO_RXDMA32_CONFIG (CONFIG_AT32_SDIO_DMAPRIO | DMA_CCR_MSIZE_32BITS | \ + DMA_CCR_PSIZE_32BITS | DMA_CCR_MINC) +# define SDIO_TXDMA32_CONFIG (CONFIG_AT32_SDIO_DMAPRIO | DMA_CCR_MSIZE_32BITS | \ + DMA_CCR_PSIZE_32BITS | DMA_CCR_MINC | DMA_CCR_DIR) +#else +# error "Unknown AT32 DMA" +#endif + +/* SDIO DMA Channel/Stream selection. For the case of the AT32 F4, there + * are multiple DMA stream options that must be dis-ambiguated in the board.h + * file. + */ + +#if defined(CONFIG_AT32_AT32F43XX) +# define SDIO_DMACHAN DMAMUX_SDIO +#else +# error "Unknown AT32 DMA" +#endif + +/* FIFO sizes */ + +#define SDIO_HALFFIFO_WORDS (8) +#define SDIO_HALFFIFO_BYTES (8*4) + +/* Data transfer interrupt mask bits */ + +#define SDIO_RECV_MASK (SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE | \ + SDIO_MASK_DATAENDIE | SDIO_MASK_RXOVERRIE | \ + SDIO_MASK_RXFIFOHFIE | SDIO_MASK_STBITERRIE) +#define SDIO_SEND_MASK (SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE | \ + SDIO_MASK_DATAENDIE | SDIO_MASK_TXUNDERRIE | \ + SDIO_MASK_TXFIFOHEIE | SDIO_MASK_STBITERRIE) +#define SDIO_DMARECV_MASK (SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE | \ + SDIO_MASK_DATAENDIE | SDIO_MASK_RXOVERRIE | \ + SDIO_MASK_STBITERRIE) +#define SDIO_DMASEND_MASK (SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE | \ + SDIO_MASK_DATAENDIE | SDIO_MASK_TXUNDERRIE | \ + SDIO_MASK_STBITERRIE) + +/* Event waiting interrupt mask bits */ + +#define SDIO_CMDDONE_STA (SDIO_STA_CMDSENT) +#define SDIO_RESPDONE_STA (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL | \ + SDIO_STA_CMDREND) +#define SDIO_XFRDONE_STA (0) + +#define SDIO_CMDDONE_MASK (SDIO_MASK_CMDSENTIE) +#define SDIO_RESPDONE_MASK (SDIO_MASK_CCRCFAILIE | SDIO_MASK_CTIMEOUTIE | \ + SDIO_MASK_CMDRENDIE) +#define SDIO_XFRDONE_MASK (0) + +#define SDIO_CMDDONE_ICR (SDIO_ICR_CMDSENTC | SDIO_ICR_DBCKENDC) +#define SDIO_RESPDONE_ICR (SDIO_ICR_CTIMEOUTC | SDIO_ICR_CCRCFAILC | \ + SDIO_ICR_CMDRENDC | SDIO_ICR_DBCKENDC) +#define SDIO_XFRDONE_ICR (SDIO_ICR_DATAENDC | SDIO_ICR_DCRCFAILC | \ + SDIO_ICR_DTIMEOUTC | SDIO_ICR_RXOVERRC | \ + SDIO_ICR_TXUNDERRC | SDIO_ICR_STBITERRC | \ + SDIO_ICR_DBCKENDC) + +#define SDIO_WAITALL_ICR (SDIO_CMDDONE_ICR | SDIO_RESPDONE_ICR | \ + SDIO_XFRDONE_ICR | SDIO_ICR_DBCKENDC) + +/* Let's wait until we have both SDIO transfer complete and DMA complete. */ + +#define SDIO_XFRDONE_FLAG (1) +#define SDIO_DMADONE_FLAG (2) +#define SDIO_ALLDONE (3) + +/* Register logging support */ + +#ifdef CONFIG_SDIO_XFRDEBUG +# ifdef CONFIG_AT32_SDIO_DMA +# define SAMPLENDX_BEFORE_SETUP 0 +# define SAMPLENDX_BEFORE_ENABLE 1 +# define SAMPLENDX_AFTER_SETUP 2 +# define SAMPLENDX_END_TRANSFER 3 +# define SAMPLENDX_DMA_CALLBACK 4 +# define DEBUG_NSAMPLES 5 +# else +# define SAMPLENDX_BEFORE_SETUP 0 +# define SAMPLENDX_AFTER_SETUP 1 +# define SAMPLENDX_END_TRANSFER 2 +# define DEBUG_NSAMPLES 3 +# endif +#endif + +#define AT32_SDIO_USE_DEFAULT_BLOCKSIZE ((uint8_t)-1) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure defines the state of the AT32 SDIO interface */ + +struct at32_dev_s +{ + struct sdio_dev_s dev; /* Standard, base SDIO interface */ + + /* AT32-specific extensions */ + + /* Event support */ + + sem_t waitsem; /* Implements event waiting */ + sdio_eventset_t waitevents; /* Set of events to be waited for */ + uint32_t waitmask; /* Interrupt enables for event waiting */ + volatile sdio_eventset_t wkupevent; /* The event that caused the wakeup */ + struct wdog_s waitwdog; /* Watchdog that handles event timeouts */ + + /* Callback support */ + + sdio_statset_t cdstatus; /* Card status */ + sdio_eventset_t cbevents; /* Set of events to be cause callbacks */ + worker_t callback; /* Registered callback function */ + void *cbarg; /* Registered callback argument */ + struct work_s cbwork; /* Callback work queue structure */ + + /* Interrupt mode data transfer support */ + + uint32_t *buffer; /* Address of current R/W buffer */ + size_t remaining; /* Number of bytes remaining in the transfer */ + uint32_t xfrmask; /* Interrupt enables for data transfer */ + +#ifdef CONFIG_AT32_SDIO_CARD + /* Interrupt at SDIO_D1 pin, only for SDIO cards */ + + uint32_t sdiointmask; /* AT32 SDIO register mask */ + int (*do_sdio_card)(void *); /* SDIO card ISR */ + void *do_sdio_arg; /* arg for SDIO card ISR */ +#endif + + /* Fixed transfer block size support */ + +#ifdef CONFIG_SDIO_BLOCKSETUP + uint8_t block_size; +#endif + + /* DMA data transfer support */ + + bool widebus; /* Required for DMA support */ +#ifdef CONFIG_AT32_SDIO_DMA + volatile uint8_t xfrflags; /* Used to synchronize SDIO and + * DMA completion events */ + bool dmamode; /* true: DMA mode transfer */ + DMA_HANDLE dma; /* Handle for DMA channel */ +#endif +}; + +/* Register logging support */ + +#ifdef CONFIG_SDIO_XFRDEBUG +struct at32_sdioregs_s +{ + uint8_t power; + uint16_t clkcr; + uint16_t dctrl; + uint32_t dtimer; + uint32_t dlen; + uint32_t dcount; + uint32_t sta; + uint32_t mask; + uint32_t fifocnt; +}; + +struct at32_sampleregs_s +{ + struct at32_sdioregs_s sdio; +#if defined(CONFIG_DEBUG_DMA_INFO) && defined(CONFIG_AT32_SDIO_DMA) + struct at32_dmaregs_s dma; +#endif +}; +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Low-level helpers ********************************************************/ + +static inline void at32_setclkcr(uint32_t clkcr); +static void at32_configwaitints(struct at32_dev_s *priv, uint32_t waitmask, + sdio_eventset_t waitevents, sdio_eventset_t wkupevents); +static void at32_configxfrints(struct at32_dev_s *priv, uint32_t xfrmask); +static void at32_setpwrctrl(uint32_t pwrctrl); + +/* DMA Helpers **************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void at32_sampleinit(void); +static void at32_sdiosample(struct at32_sdioregs_s *regs); +static void at32_sample(struct at32_dev_s *priv, int index); +static void at32_sdiodump(struct at32_sdioregs_s *regs, const char *msg); +static void at32_dumpsample(struct at32_dev_s *priv, + struct at32_sampleregs_s *regs, const char *msg); +static void at32_dumpsamples(struct at32_dev_s *priv); +#else +# define at32_sampleinit() +# define at32_sample(priv,index) +# define at32_dumpsamples(priv) +#endif + +#ifdef CONFIG_AT32_SDIO_DMA +static void at32_dmacallback(DMA_HANDLE handle, uint8_t status, void *arg); +#endif + +/* Data Transfer Helpers ****************************************************/ + +static uint8_t at32_log2(uint16_t value); +static void at32_dataconfig(uint32_t timeout, uint32_t dlen, + uint32_t dctrl); +static void at32_datadisable(void); +static void at32_sendfifo(struct at32_dev_s *priv); +static void at32_recvfifo(struct at32_dev_s *priv); +static void at32_eventtimeout(wdparm_t arg); +static void at32_endwait(struct at32_dev_s *priv, + sdio_eventset_t wkupevent); +static void at32_endtransfer(struct at32_dev_s *priv, + sdio_eventset_t wkupevent); + +/* Interrupt Handling *******************************************************/ + +static int at32_interrupt(int irq, void *context, void *arg); +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE +static int at32_rdyinterrupt(int irq, void *context, void *arg); +#endif + +/* SDIO interface methods ***************************************************/ + +/* Mutual exclusion */ + +#ifdef CONFIG_SDIO_MUXBUS +static int at32_lock(struct sdio_dev_s *dev, bool lock); +#endif + +/* Initialization/setup */ + +static void at32_reset(struct sdio_dev_s *dev); +static sdio_capset_t at32_capabilities(struct sdio_dev_s *dev); +static sdio_statset_t at32_status(struct sdio_dev_s *dev); +static void at32_widebus(struct sdio_dev_s *dev, bool enable); +static void at32_clock(struct sdio_dev_s *dev, + enum sdio_clock_e rate); +static int at32_attach(struct sdio_dev_s *dev); + +/* Command/Status/Data Transfer */ + +static int at32_sendcmd(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t arg); +#ifdef CONFIG_SDIO_BLOCKSETUP +static void at32_blocksetup(struct sdio_dev_s *dev, + unsigned int blocklen, unsigned int nblocks); +#endif +static int at32_recvsetup(struct sdio_dev_s *dev, uint8_t *buffer, + size_t nbytes); +static int at32_sendsetup(struct sdio_dev_s *dev, + const uint8_t *buffer, size_t nbytes); +static int at32_cancel(struct sdio_dev_s *dev); + +static int at32_waitresponse(struct sdio_dev_s *dev, uint32_t cmd); +static int at32_recvshortcrc(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t *rshort); +static int at32_recvlong(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t rlong[4]); +static int at32_recvshort(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t *rshort); + +/* EVENT handler */ + +static void at32_waitenable(struct sdio_dev_s *dev, + sdio_eventset_t eventset, uint32_t timeout); +static sdio_eventset_t at32_eventwait(struct sdio_dev_s *dev); +static void at32_callbackenable(struct sdio_dev_s *dev, + sdio_eventset_t eventset); +static int at32_registercallback(struct sdio_dev_s *dev, + worker_t callback, void *arg); + +/* DMA */ + +#ifdef CONFIG_AT32_SDIO_DMA +#ifdef CONFIG_ARCH_HAVE_SDIO_PREFLIGHT +static int at32_dmapreflight(struct sdio_dev_s *dev, + const uint8_t *buffer, size_t buflen); +#endif +static int at32_dmarecvsetup(struct sdio_dev_s *dev, + uint8_t *buffer, size_t buflen); +static int at32_dmasendsetup(struct sdio_dev_s *dev, + const uint8_t *buffer, size_t buflen); +#endif + +/* Initialization/uninitialization/reset ************************************/ + +static void at32_callback(void *arg); +static void at32_default(void); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +struct at32_dev_s g_sdiodev = +{ + .dev = + { +#ifdef CONFIG_SDIO_MUXBUS + .lock = at32_lock, +#endif + .reset = at32_reset, + .capabilities = at32_capabilities, + .status = at32_status, + .widebus = at32_widebus, + .clock = at32_clock, + .attach = at32_attach, + .sendcmd = at32_sendcmd, +#ifdef CONFIG_SDIO_BLOCKSETUP + .blocksetup = at32_blocksetup, +#endif + .recvsetup = at32_recvsetup, + .sendsetup = at32_sendsetup, + .cancel = at32_cancel, + .waitresponse = at32_waitresponse, + .recv_r1 = at32_recvshortcrc, + .recv_r2 = at32_recvlong, + .recv_r3 = at32_recvshort, + .recv_r4 = at32_recvshort, + .recv_r5 = at32_recvshortcrc, + .recv_r6 = at32_recvshortcrc, + .recv_r7 = at32_recvshort, + .waitenable = at32_waitenable, + .eventwait = at32_eventwait, + .callbackenable = at32_callbackenable, + .registercallback = at32_registercallback, +#ifdef CONFIG_SDIO_DMA +#ifdef CONFIG_AT32_SDIO_DMA +#ifdef CONFIG_ARCH_HAVE_SDIO_PREFLIGHT + .dmapreflight = at32_dmapreflight, +#endif + .dmarecvsetup = at32_dmarecvsetup, + .dmasendsetup = at32_dmasendsetup, +#else +#ifdef CONFIG_ARCH_HAVE_SDIO_PREFLIGHT + .dmapreflight = NULL, +#endif + .dmarecvsetup = at32_recvsetup, + .dmasendsetup = at32_sendsetup, +#endif +#endif + }, + .waitsem = SEM_INITIALIZER(0), +}; + +/* Register logging support */ + +#ifdef CONFIG_SDIO_XFRDEBUG +static struct at32_sampleregs_s g_sampleregs[DEBUG_NSAMPLES]; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_setclkcr + * + * Description: + * Modify oft-changed bits in the CLKCR register. Only the following bit- + * fields are changed: + * + * CLKDIV, PWRSAV, BYPASS, WIDBUS, NEGEDGE, and HWFC_EN + * + * Input Parameters: + * clkcr - A new CLKCR setting for the above mentions bits (other bits + * are ignored. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void at32_setclkcr(uint32_t clkcr) +{ + uint32_t regval = getreg32(AT32_SDIO_CLKCR); + + /* Clear CLKDIV, PWRSAV, BYPASS, WIDBUS, NEGEDGE, HWFC_EN bits */ + + regval &= ~(SDIO_CLKCR_CLKDIV89_MASK | SDIO_CLKCR_CLKDIV_MASK | \ + SDIO_CLKCR_PWRSAV | SDIO_CLKCR_BYPASS | \ + SDIO_CLKCR_WIDBUS_MASK | SDIO_CLKCR_NEGEDGE | \ + SDIO_CLKCR_HWFC_EN | SDIO_CLKCR_CLKEN); + + /* Replace with user provided settings */ + + clkcr &= (SDIO_CLKCR_CLKDIV89_MASK | SDIO_CLKCR_CLKDIV_MASK | \ + SDIO_CLKCR_PWRSAV | SDIO_CLKCR_BYPASS | \ + SDIO_CLKCR_WIDBUS_MASK | SDIO_CLKCR_NEGEDGE | \ + SDIO_CLKCR_HWFC_EN | SDIO_CLKCR_CLKEN); + + regval |= clkcr; + putreg32(regval, AT32_SDIO_CLKCR); + + mcinfo("CLKCR: %08" PRIx32 " PWR: %08" PRIx32 "\n", + getreg32(AT32_SDIO_CLKCR), getreg32(AT32_SDIO_POWER)); +} + +/**************************************************************************** + * Name: at32_configwaitints + * + * Description: + * Enable/disable SDIO interrupts needed to support the wait function + * + * Input Parameters: + * priv - A reference to the SDIO device state structure + * waitmask - The set of bits in the SDIO MASK register to set + * waitevents - Waited for events + * wkupevent - Wake-up events + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_configwaitints(struct at32_dev_s *priv, uint32_t waitmask, + sdio_eventset_t waitevents, + sdio_eventset_t wkupevent) +{ + irqstate_t flags; +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE + int pinset; +#endif + + /* Save all of the data and set the new interrupt mask in one, atomic + * operation. + */ + + flags = enter_critical_section(); + +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE + if ((waitevents & SDIOWAIT_WRCOMPLETE) != 0) + { + pinset = GPIO_SDIO_D0 & (GPIO_PORT_MASK | GPIO_PIN_MASK); + pinset |= (GPIO_INPUT | GPIO_FLOAT | GPIO_EXTI); + + /* Arm the SDIO_D0 Ready and install Isr */ + + at32_gpiosetevent(pinset, true, false, false, + at32_rdyinterrupt, priv); + } + + /* Disarm SDIO_D0 ready and return it to SDIO D0 */ + + if ((wkupevent & SDIOWAIT_WRCOMPLETE) != 0) + { + at32_gpiosetevent(GPIO_SDIO_D0, false, false, false, + NULL, NULL); + } +#endif + + priv->waitevents = waitevents; + priv->wkupevent = wkupevent; + priv->waitmask = waitmask; +#ifdef CONFIG_AT32_SDIO_DMA + priv->xfrflags = 0; +#endif + +#ifdef CONFIG_AT32_SDIO_CARD + putreg32(priv->xfrmask | priv->waitmask | priv->sdiointmask, + AT32_SDIO_MASK); +#else + putreg32(priv->xfrmask | priv->waitmask, AT32_SDIO_MASK); +#endif + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: at32_configxfrints + * + * Description: + * Enable SDIO interrupts needed to support the data transfer event + * + * Input Parameters: + * priv - A reference to the SDIO device state structure + * xfrmask - The set of bits in the SDIO MASK register to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_configxfrints(struct at32_dev_s *priv, uint32_t xfrmask) +{ + irqstate_t flags; + + flags = enter_critical_section(); + priv->xfrmask = xfrmask; +#ifdef CONFIG_AT32_SDIO_CARD + putreg32(priv->xfrmask | priv->waitmask | priv->sdiointmask, + AT32_SDIO_MASK); +#else + putreg32(priv->xfrmask | priv->waitmask, AT32_SDIO_MASK); +#endif + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: at32_setpwrctrl + * + * Description: + * Change the PWRCTRL field of the SDIO POWER register to turn the SDIO + * ON or OFF + * + * Input Parameters: + * clkcr - A new PWRCTRL setting + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_setpwrctrl(uint32_t pwrctrl) +{ + uint32_t regval; + + regval = getreg32(AT32_SDIO_POWER); + regval &= ~SDIO_POWER_PWRCTRL_MASK; + regval |= pwrctrl; + putreg32(regval, AT32_SDIO_POWER); +} + +/**************************************************************************** + * Name: at32_sampleinit + * + * Description: + * Setup prior to collecting DMA samples + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void at32_sampleinit(void) +{ + memset(g_sampleregs, 0xff, + DEBUG_NSAMPLES * sizeof(struct at32_sampleregs_s)); +} +#endif + +/**************************************************************************** + * Name: at32_sdiosample + * + * Description: + * Sample SDIO registers + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void at32_sdiosample(struct at32_sdioregs_s *regs) +{ + regs->power = (uint8_t)getreg32(AT32_SDIO_POWER); + regs->clkcr = (uint16_t)getreg32(AT32_SDIO_CLKCR); + regs->dctrl = (uint16_t)getreg32(AT32_SDIO_DCTRL); + regs->dtimer = getreg32(AT32_SDIO_DTIMER); + regs->dlen = getreg32(AT32_SDIO_DLEN); + regs->dcount = getreg32(AT32_SDIO_DCOUNT); + regs->sta = getreg32(AT32_SDIO_STA); + regs->mask = getreg32(AT32_SDIO_MASK); + regs->fifocnt = getreg32(AT32_SDIO_FIFOCNT); +} +#endif + +/**************************************************************************** + * Name: at32_sample + * + * Description: + * Sample SDIO/DMA registers + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void at32_sample(struct at32_dev_s *priv, int index) +{ + struct at32_sampleregs_s *regs = &g_sampleregs[index]; + +#if defined(CONFIG_DEBUG_DMA_INFO) && defined(CONFIG_AT32_SDIO_DMA) + if (priv->dmamode) + { + at32_dmasample(priv->dma, ®s->dma); + } +#endif + + at32_sdiosample(®s->sdio); +} +#endif + +/**************************************************************************** + * Name: at32_sdiodump + * + * Description: + * Dump one register sample + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void at32_sdiodump(struct at32_sdioregs_s *regs, const char *msg) +{ + mcinfo("SDIO Registers: %s\n", msg); + mcinfo(" POWER[%08x]: %08x\n", AT32_SDIO_POWER, regs->power); + mcinfo(" CLKCR[%08x]: %08x\n", AT32_SDIO_CLKCR, regs->clkcr); + mcinfo(" DCTRL[%08x]: %08x\n", AT32_SDIO_DCTRL, regs->dctrl); + mcinfo(" DTIMER[%08x]: %08x\n", AT32_SDIO_DTIMER, regs->dtimer); + mcinfo(" DLEN[%08x]: %08x\n", AT32_SDIO_DLEN, regs->dlen); + mcinfo(" DCOUNT[%08x]: %08x\n", AT32_SDIO_DCOUNT, regs->dcount); + mcinfo(" STA[%08x]: %08x\n", AT32_SDIO_STA, regs->sta); + mcinfo(" MASK[%08x]: %08x\n", AT32_SDIO_MASK, regs->mask); + mcinfo("FIFOCNT[%08x]: %08x\n", AT32_SDIO_FIFOCNT, regs->fifocnt); +} +#endif + +/**************************************************************************** + * Name: at32_dumpsample + * + * Description: + * Dump one register sample + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void at32_dumpsample(struct at32_dev_s *priv, + struct at32_sampleregs_s *regs, + const char *msg) +{ +#if defined(CONFIG_DEBUG_DMA_INFO) && defined(CONFIG_AT32_SDIO_DMA) + if (priv->dmamode) + { + at32_dmadump(priv->dma, ®s->dma, msg); + } +#endif + + at32_sdiodump(®s->sdio, msg); +} +#endif + +/**************************************************************************** + * Name: at32_dumpsamples + * + * Description: + * Dump all sampled register data + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void at32_dumpsamples(struct at32_dev_s *priv) +{ + at32_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_SETUP], + "Before setup"); + +#if defined(CONFIG_DEBUG_DMA_INFO) && defined(CONFIG_AT32_SDIO_DMA) + if (priv->dmamode) + { + at32_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_ENABLE], + "Before DMA enable"); + } +#endif + + at32_dumpsample(priv, &g_sampleregs[SAMPLENDX_AFTER_SETUP], + "After setup"); + at32_dumpsample(priv, &g_sampleregs[SAMPLENDX_END_TRANSFER], + "End of transfer"); + +#if defined(CONFIG_DEBUG_DMA_INFO) && defined(CONFIG_AT32_SDIO_DMA) + if (priv->dmamode) + { + at32_dumpsample(priv, &g_sampleregs[SAMPLENDX_DMA_CALLBACK], + "DMA Callback"); + } +#endif +} +#endif + +/**************************************************************************** + * Name: at32_dmacallback + * + * Description: + * Called when SDIO DMA completes + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SDIO_DMA +static void at32_dmacallback(DMA_HANDLE handle, uint8_t status, void *arg) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)arg; + DEBUGASSERT(priv->dmamode); + sdio_eventset_t result; + + /* In the normal case, SDIO appears to handle the End-Of-Transfer interrupt + * first with the End-Of-DMA event occurring significantly later. On + * transfer errors, however, the DMA error will occur before the End-of- + * Transfer. + */ + + at32_sample((struct at32_dev_s *)arg, SAMPLENDX_DMA_CALLBACK); + + /* Get the result of the DMA transfer */ + + if ((status & DMA_STATUS_ERROR) != 0) + { + mcerr("ERROR: DMA error %02x, remaining: %d\n", + status, priv->remaining); + result = SDIOWAIT_ERROR; + } + else + { + result = SDIOWAIT_TRANSFERDONE; + } + + /* Then terminate the transfer if this completes all of the steps in the + * transfer OR if a DMA error occurred. In the non-error case, we should + * already have the SDIO transfer done interrupt. If not, the transfer + * will appropriately time out. + */ + + priv->xfrflags |= SDIO_DMADONE_FLAG; + if (priv->xfrflags == SDIO_ALLDONE || result == SDIOWAIT_ERROR) + { + at32_endtransfer(priv, result); + } +} +#endif + +/**************************************************************************** + * Name: at32_log2 + * + * Description: + * Take (approximate) log base 2 of the provided number (Only works if the + * provided number is a power of 2). + * + ****************************************************************************/ + +static uint8_t at32_log2(uint16_t value) +{ + uint8_t log2 = 0; + + /* 0000 0000 0000 0001 -> return 0, + * 0000 0000 0000 001x -> return 1, + * 0000 0000 0000 01xx -> return 2, + * 0000 0000 0000 1xxx -> return 3, + * ... + * 1xxx xxxx xxxx xxxx -> return 15, + */ + + DEBUGASSERT(value > 0); + while (value != 1) + { + value >>= 1; + log2++; + } + + return log2; +} + +/**************************************************************************** + * Name: at32_dataconfig + * + * Description: + * Configure the SDIO data path for the next data transfer + * + ****************************************************************************/ + +static void at32_dataconfig(uint32_t timeout, uint32_t dlen, uint32_t dctrl) +{ + uint32_t clkdiv; + uint32_t regval; + uint32_t sdio_clk = AT32_SYSCLK_FREQUENCY; + + /* Enable data path using a timeout scaled to the SD_CLOCK (the card + * clock). + */ + + regval = getreg32(AT32_SDIO_CLKCR); + + clkdiv = (regval & SDIO_CLKCR_CLKDIV_MASK) >> SDIO_CLKCR_CLKDIV_SHIFT; + clkdiv |= ((regval & SDIO_CLKCR_CLKDIV89_MASK) >> 8); + + if ((regval & SDIO_CLKCR_BYPASS) == 0) + { + sdio_clk = sdio_clk / (2 + clkdiv); + } + + /* Convert Timeout in Ms to SD_CLK counts */ + + timeout = timeout * (sdio_clk / 1000); + + putreg32(timeout, AT32_SDIO_DTIMER); /* Set DTIMER */ + putreg32(dlen, AT32_SDIO_DLEN); /* Set DLEN */ + + /* Configure DCTRL DTDIR, DTMODE, and DBLOCKSIZE fields and set the DTEN + * field + */ + + regval = getreg32(AT32_SDIO_DCTRL); + regval &= ~(SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTMODE | + SDIO_DCTRL_DBLOCKSIZE_MASK); + dctrl &= (SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTMODE | + SDIO_DCTRL_DBLOCKSIZE_MASK); + +#ifdef CONFIG_AT32_SDIO_CARD + regval |= (dctrl | SDIO_DCTRL_DTEN | SDIO_DCTRL_SDIOEN); +#else + regval |= (dctrl | SDIO_DCTRL_DTEN); +#endif + + putreg32(regval, AT32_SDIO_DCTRL); +} + +/**************************************************************************** + * Name: at32_datadisable + * + * Description: + * Disable the SDIO data path setup by at32_dataconfig() and + * disable DMA. + * + ****************************************************************************/ + +static void at32_datadisable(void) +{ + uint32_t regval; + + /* Disable the data path */ + + /* Reset DTIMER */ + + putreg32(UINT32_MAX, AT32_SDIO_DTIMER); + + /* Reset DLEN */ + + putreg32(0, AT32_SDIO_DLEN); + + /* Reset DCTRL DTEN, DTDIR, DTMODE, DMAEN, and DBLOCKSIZE fields */ + + regval = getreg32(AT32_SDIO_DCTRL); + regval &= ~(SDIO_DCTRL_DTEN | SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTMODE | + SDIO_DCTRL_DMAEN | SDIO_DCTRL_DBLOCKSIZE_MASK); + putreg32(regval, AT32_SDIO_DCTRL); +} + +/**************************************************************************** + * Name: at32_sendfifo + * + * Description: + * Send SDIO data in interrupt mode + * + * Input Parameters: + * priv - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_sendfifo(struct at32_dev_s *priv) +{ + union + { + uint32_t w; + uint8_t b[4]; + } data; + + /* Loop while there is more data to be sent and the RX FIFO is not full */ + + while (priv->remaining > 0 && + (getreg32(AT32_SDIO_STA) & SDIO_STA_TXFIFOF) == 0) + { + /* Is there a full word remaining in the user buffer? */ + + if (priv->remaining >= sizeof(uint32_t)) + { + /* Yes, transfer the word to the TX FIFO */ + + data.w = *priv->buffer++; + priv->remaining -= sizeof(uint32_t); + } + else + { + /* No.. transfer just the bytes remaining in the user buffer, + * padding with zero as necessary to extend to a full word. + */ + + uint8_t *ptr = (uint8_t *)priv->remaining; + int i; + + data.w = 0; + for (i = 0; i < (int)priv->remaining; i++) + { + data.b[i] = *ptr++; + } + + /* Now the transfer is finished */ + + priv->remaining = 0; + } + + /* Put the word in the FIFO */ + + putreg32(data.w, AT32_SDIO_FIFO); + } +} + +/**************************************************************************** + * Name: at32_recvfifo + * + * Description: + * Receive SDIO data in interrupt mode + * + * Input Parameters: + * priv - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_recvfifo(struct at32_dev_s *priv) +{ + union + { + uint32_t w; + uint8_t b[4]; + } data; + + /* Loop while there is space to store the data and there is more + * data available in the RX FIFO. + */ + + while (priv->remaining > 0 && + (getreg32(AT32_SDIO_STA) & SDIO_STA_RXDAVL) != 0) + { + /* Read the next word from the RX FIFO */ + + data.w = getreg32(AT32_SDIO_FIFO); + if (priv->remaining >= sizeof(uint32_t)) + { + /* Transfer the whole word to the user buffer */ + + *priv->buffer++ = data.w; + priv->remaining -= sizeof(uint32_t); + } + else + { + /* Transfer any trailing fractional word */ + + uint8_t *ptr = (uint8_t *)priv->buffer; + int i; + + for (i = 0; i < (int)priv->remaining; i++) + { + *ptr++ = data.b[i]; + } + + /* Now the transfer is finished */ + + priv->remaining = 0; + } + } +} + +/**************************************************************************** + * Name: at32_eventtimeout + * + * Description: + * The watchdog timeout setup when the event wait start has expired without + * any other waited-for event occurring. + * + * Input Parameters: + * arg - The argument + * + * Returned Value: + * None + * + * Assumptions: + * Always called from the interrupt level with interrupts disabled. + * + ****************************************************************************/ + +static void at32_eventtimeout(wdparm_t arg) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)arg; + + /* There is always race conditions with timer expirations. */ + + DEBUGASSERT((priv->waitevents & SDIOWAIT_TIMEOUT) != 0 || + priv->wkupevent != 0); + + mcinfo("sta: %08" PRIx32 " enabled irq: %08" PRIx32 "\n", + getreg32(AT32_SDIO_STA), + getreg32(AT32_SDIO_MASK)); + + /* Is a data transfer complete event expected? */ + + if ((priv->waitevents & SDIOWAIT_TIMEOUT) != 0) + { + /* Yes.. wake up any waiting threads */ + +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE + at32_endwait(priv, SDIOWAIT_TIMEOUT | + (priv->waitevents & SDIOWAIT_WRCOMPLETE)); +#else + at32_endwait(priv, SDIOWAIT_TIMEOUT); +#endif + mcerr("Timeout: remaining: %d\n", priv->remaining); + } +} + +/**************************************************************************** + * Name: at32_endwait + * + * Description: + * Wake up a waiting thread if the waited-for event has occurred. + * + * Input Parameters: + * priv - An instance of the SDIO device interface + * wkupevent - The event that caused the wait to end + * + * Returned Value: + * None + * + * Assumptions: + * Always called from the interrupt level with interrupts disabled. + * + ****************************************************************************/ + +static void at32_endwait(struct at32_dev_s *priv, + sdio_eventset_t wkupevent) +{ + /* Cancel the watchdog timeout */ + + wd_cancel(&priv->waitwdog); + + /* Disable event-related interrupts */ + + at32_configwaitints(priv, 0, 0, wkupevent); + + /* Wake up the waiting thread */ + + nxsem_post(&priv->waitsem); +} + +/**************************************************************************** + * Name: at32_endtransfer + * + * Description: + * Terminate a transfer with the provided status. This function is called + * only from the SDIO interrupt handler when end-of-transfer conditions + * are detected. + * + * Input Parameters: + * priv - An instance of the SDIO device interface + * wkupevent - The event that caused the transfer to end + * + * Returned Value: + * None + * + * Assumptions: + * Always called from the interrupt level with interrupts disabled. + * + ****************************************************************************/ + +static void at32_endtransfer(struct at32_dev_s *priv, + sdio_eventset_t wkupevent) +{ + /* Disable all transfer related interrupts */ + + at32_configxfrints(priv, 0); + + /* Clearing pending interrupt status on all transfer related interrupts */ + + putreg32(SDIO_XFRDONE_ICR, AT32_SDIO_ICR); + + /* If this was a DMA transfer, make sure that DMA is stopped */ + +#ifdef CONFIG_AT32_SDIO_DMA + if (priv->dmamode) + { + /* DMA debug instrumentation */ + + at32_sample(priv, SAMPLENDX_END_TRANSFER); + + /* Make sure that the DMA is stopped (it will be stopped automatically + * on normal transfers, but not necessarily when the transfer + * terminates on an error condition). + */ + + at32_dmastop(priv->dma); + } +#endif + + /* Mark the transfer finished */ + + priv->remaining = 0; + + /* Is a thread wait for these data transfer complete events? */ + + if ((priv->waitevents & wkupevent) != 0) + { + /* Yes.. wake up any waiting threads */ + + at32_endwait(priv, wkupevent); + } +} + +/**************************************************************************** + * Name: at32_rdyinterrupt + * + * Description: + * SDIO ready interrupt handler + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE +static int at32_rdyinterrupt(int irq, void *context, void *arg) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)arg; + + /* Avoid noise, check the state */ + + if (at32_gpioread(GPIO_SDIO_D0)) + { + at32_endwait(priv, SDIOWAIT_WRCOMPLETE); + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: at32_interrupt + * + * Description: + * SDIO interrupt handler + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int at32_interrupt(int irq, void *context, void *arg) +{ + struct at32_dev_s *priv = &g_sdiodev; + uint32_t enabled; + uint32_t pending; + + /* Loop while there are pending interrupts. Check the SDIO status + * register. Mask out all bits that don't correspond to enabled + * interrupts. (This depends on the fact that bits are ordered + * the same in both the STA and MASK register). If there are non-zero + * bits remaining, then we have work to do here. + */ + + while ((enabled = getreg32(AT32_SDIO_STA) & + getreg32(AT32_SDIO_MASK)) != 0) + { + /* Handle in progress, interrupt driven data transfers ****************/ + + pending = enabled & priv->xfrmask; + if (pending != 0) + { +#ifdef CONFIG_AT32_SDIO_DMA + if (!priv->dmamode) +#endif + { + /* Is the RX FIFO half full or more? Is so then we must be + * processing a receive transaction. + */ + + if ((pending & SDIO_STA_RXFIFOHF) != 0) + { + /* Receive data from the RX FIFO */ + + at32_recvfifo(priv); + } + + /* Otherwise, Is the transmit FIFO half empty or less? If so + * we must be processing a send transaction. NOTE: We can't + * be processing both! + */ + + else if ((pending & SDIO_STA_TXFIFOHE) != 0) + { + /* Send data via the TX FIFO */ + + at32_sendfifo(priv); + } + } + + /* Handle data end events */ + + if ((pending & SDIO_STA_DATAEND) != 0) + { + /* Handle any data remaining the RX FIFO. If the RX FIFO is + * less than half full at the end of the transfer, then no + * half-full interrupt will be received. + */ + + /* Was this transfer performed in DMA mode? */ + +#ifdef CONFIG_AT32_SDIO_DMA + if (priv->dmamode) + { + /* Yes.. Terminate the transfers only if the DMA has also + * finished. + */ + + priv->xfrflags |= SDIO_XFRDONE_FLAG; + if (priv->xfrflags == SDIO_ALLDONE) + { + at32_endtransfer(priv, SDIOWAIT_TRANSFERDONE); + } + + /* Otherwise, just disable further transfer interrupts and + * wait for the DMA complete event. + */ + + else + { + at32_configxfrints(priv, 0); + } + } + else +#endif + { + /* Receive data from the RX FIFO */ + + at32_recvfifo(priv); + + /* Then terminate the transfer */ + + at32_endtransfer(priv, SDIOWAIT_TRANSFERDONE); + } + } + + /* Handle data block send/receive CRC failure */ + + else if ((pending & SDIO_STA_DCRCFAIL) != 0) + { + /* Terminate the transfer with an error */ + + mcerr("ERROR: Data block CRC failure, remaining: %d\n", + priv->remaining); + at32_endtransfer(priv, + SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR); + } + + /* Handle data timeout error */ + + else if ((pending & SDIO_STA_DTIMEOUT) != 0) + { + /* Terminate the transfer with an error */ + + mcerr("ERROR: Data timeout, remaining: %d\n", + priv->remaining); + at32_endtransfer(priv, + SDIOWAIT_TRANSFERDONE | SDIOWAIT_TIMEOUT); + } + + /* Handle RX FIFO overrun error */ + + else if ((pending & SDIO_STA_RXOVERR) != 0) + { + /* Terminate the transfer with an error */ + + mcerr("ERROR: RX FIFO overrun, remaining: %d\n", + priv->remaining); + at32_endtransfer(priv, + SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR); + } + + /* Handle TX FIFO underrun error */ + + else if ((pending & SDIO_STA_TXUNDERR) != 0) + { + /* Terminate the transfer with an error */ + + mcerr("ERROR: TX FIFO underrun, remaining: %d\n", + priv->remaining); + at32_endtransfer(priv, + SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR); + } + + /* Handle start bit error */ + + else if ((pending & SDIO_STA_STBITERR) != 0) + { + /* Terminate the transfer with an error */ + + mcerr("ERROR: Start bit, remaining: %d\n", + priv->remaining); + at32_endtransfer(priv, + SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR); + } + } + + /* Handle wait events *************************************************/ + + pending = enabled & priv->waitmask; + if (pending != 0) + { + /* Is this a response completion event? */ + + if ((pending & SDIO_RESPDONE_STA) != 0) + { + /* Yes.. Is their a thread waiting for response done? */ + + if ((priv->waitevents & SDIOWAIT_RESPONSEDONE) != 0) + { + /* Yes.. wake the thread up */ + + putreg32(SDIO_RESPDONE_ICR | SDIO_CMDDONE_ICR, + AT32_SDIO_ICR); + at32_endwait(priv, SDIOWAIT_RESPONSEDONE); + } + } + + /* Is this a command completion event? */ + + if ((pending & SDIO_CMDDONE_STA) != 0) + { + /* Yes.. Is their a thread waiting for command done? */ + + if ((priv->waitevents & SDIOWAIT_RESPONSEDONE) != 0) + { + /* Yes.. wake the thread up */ + + putreg32(SDIO_CMDDONE_ICR, AT32_SDIO_ICR); + at32_endwait(priv, SDIOWAIT_CMDDONE); + } + } + } + +#ifdef CONFIG_AT32_SDIO_CARD + /* Handle SDIO card interrupt */ + + pending = enabled & priv->sdiointmask; + if (pending != 0) + { + putreg32(SDIO_STA_SDIOIT, AT32_SDIO_ICR); + + /* Perform callback */ + + if (priv->do_sdio_card) + { + priv->do_sdio_card(priv->do_sdio_arg); + } + } +#endif + } + + return OK; +} + +/**************************************************************************** + * Name: at32_lock + * + * Description: + * Locks the bus. Function calls low-level multiplexed bus routines to + * resolve bus requests and acknowledgment issues. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * lock - TRUE to lock, FALSE to unlock. + * + * Returned Value: + * OK on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_MUXBUS +static int at32_lock(struct sdio_dev_s *dev, bool lock) +{ + /* Single SDIO instance so there is only one possibility. The multiplex + * bus is part of board support package. + */ + + at32_muxbus_sdio_lock(lock); + return OK; +} +#endif + +/**************************************************************************** + * Name: at32_reset + * + * Description: + * Reset the SDIO controller. Undo all setup and initialization. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_reset(struct sdio_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + irqstate_t flags; + + /* Disable clocking */ + + flags = enter_critical_section(); + putreg32(0, SDIO_CLKCR_CLKEN_BB); + at32_setpwrctrl(SDIO_POWER_PWRCTRL_OFF); + + /* Put SDIO registers in their default, reset state */ + + at32_default(); + + /* Reset data */ + + priv->waitevents = 0; /* Set of events to be waited for */ + priv->waitmask = 0; /* Interrupt enables for event waiting */ + priv->wkupevent = 0; /* The event that caused the wakeup */ +#ifdef CONFIG_AT32_SDIO_DMA + priv->xfrflags = 0; /* Used to synchronize SDIO and DMA completion events */ +#endif + + wd_cancel(&priv->waitwdog); /* Cancel any timeouts */ + + /* Interrupt mode data transfer support */ + + priv->buffer = 0; /* Address of current R/W buffer */ + priv->remaining = 0; /* Number of bytes remaining in the transfer */ + priv->xfrmask = 0; /* Interrupt enables for data transfer */ + +#ifdef CONFIG_AT32_SDIO_CARD + priv->sdiointmask = 0; /* SDIO card in-band interrupt mask */ +#endif + + /* DMA data transfer support */ + + priv->widebus = false; /* Required for DMA support */ +#ifdef CONFIG_AT32_SDIO_DMA + priv->dmamode = false; /* true: DMA mode transfer */ +#endif + + /* Configure the SDIO peripheral */ + + at32_setclkcr(AT32_CLCKCR_INIT | SDIO_CLKCR_CLKEN); + at32_setpwrctrl(SDIO_POWER_PWRCTRL_ON); + leave_critical_section(flags); + + mcinfo("CLCKR: %08" PRIx32 " POWER: %08" PRIx32 "\n", + getreg32(AT32_SDIO_CLKCR), getreg32(AT32_SDIO_POWER)); +} + +/**************************************************************************** + * Name: at32_capabilities + * + * Description: + * Get capabilities (and limitations) of the SDIO driver (optional) + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Returns a bitset of status values (see SDIO_CAPS_* defines) + * + ****************************************************************************/ + +static sdio_capset_t at32_capabilities(struct sdio_dev_s *dev) +{ + sdio_capset_t caps = 0; + +#ifdef CONFIG_AT32_SDIO_WIDTH_D1_ONLY + caps |= SDIO_CAPS_1BIT_ONLY; +#endif +#ifdef CONFIG_AT32_SDIO_DMA + caps |= SDIO_CAPS_DMASUPPORTED; +#endif + + return caps; +} + +/**************************************************************************** + * Name: at32_status + * + * Description: + * Get SDIO status. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Returns a bitset of status values (see at32_status_* defines) + * + ****************************************************************************/ + +static sdio_statset_t at32_status(struct sdio_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + return priv->cdstatus; +} + +/**************************************************************************** + * Name: at32_widebus + * + * Description: + * Called after change in Bus width has been selected (via ACMD6). Most + * controllers will need to perform some special operations to work + * correctly in the new bus mode. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * wide - true: wide bus (4-bit) bus mode enabled + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_widebus(struct sdio_dev_s *dev, bool wide) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + priv->widebus = wide; +} + +/**************************************************************************** + * Name: at32_clock + * + * Description: + * Enable/disable SDIO clocking + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * rate - Specifies the clocking to use (see enum sdio_clock_e) + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate) +{ + uint32_t clckr; + + switch (rate) + { + /* Disable clocking (with default ID mode divisor) */ + + default: + case CLOCK_SDIO_DISABLED: + clckr = AT32_CLCKCR_INIT; + break; + + /* Enable in initial ID mode clocking (<400KHz) */ + + case CLOCK_IDMODE: + clckr = (AT32_CLCKCR_INIT | SDIO_CLKCR_CLKEN); + break; + + /* Enable in MMC normal operation clocking */ + + case CLOCK_MMC_TRANSFER: + clckr = (SDIO_CLKCR_MMCXFR | SDIO_CLKCR_CLKEN); + break; + + /* SD normal operation clocking (wide 4-bit mode) */ + + case CLOCK_SD_TRANSFER_4BIT: +#ifndef CONFIG_AT32_SDIO_WIDTH_D1_ONLY + clckr = (SDIO_CLCKR_SDWIDEXFR | SDIO_CLKCR_CLKEN); + break; +#endif + + /* SD normal operation clocking (narrow 1-bit mode) */ + + case CLOCK_SD_TRANSFER_1BIT: + clckr = (SDIO_CLCKR_SDXFR | SDIO_CLKCR_CLKEN); + break; + } + + /* Set the new clock frequency along with the clock enable/disable bit */ + + at32_setclkcr(clckr); +} + +/**************************************************************************** + * Name: at32_attach + * + * Description: + * Attach and prepare interrupts + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * OK on success; A negated errno on failure. + * + ****************************************************************************/ + +static int at32_attach(struct sdio_dev_s *dev) +{ + int ret; + + /* Attach the SDIO interrupt handler */ + + ret = irq_attach(AT32_IRQ_SDIO, at32_interrupt, NULL); + if (ret == OK) + { + /* Disable all interrupts at the SDIO controller and clear static + * interrupt flags + */ + + putreg32(SDIO_MASK_RESET, AT32_SDIO_MASK); + putreg32(SDIO_ICR_STATICFLAGS, AT32_SDIO_ICR); + + /* Enable SDIO interrupts at the NVIC. They can now be enabled at + * the SDIO controller as needed. + */ + + up_enable_irq(AT32_IRQ_SDIO); + } + + return ret; +} + +/**************************************************************************** + * Name: at32_sendcmd + * + * Description: + * Send the SDIO command + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * cmd - The command to send (32-bits, encoded) + * arg - 32-bit argument required with some commands + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int at32_sendcmd(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t arg) +{ + uint32_t regval; + uint32_t cmdidx; + + /* Set the SDIO Argument value */ + + putreg32(arg, AT32_SDIO_ARG); + + /* Clear CMDINDEX, WAITRESP, WAITINT, WAITPEND, and CPSMEN bits */ + + regval = getreg32(AT32_SDIO_CMD); + regval &= ~(SDIO_CMD_CMDINDEX_MASK | SDIO_CMD_WAITRESP_MASK | + SDIO_CMD_WAITINT | SDIO_CMD_WAITPEND | SDIO_CMD_CPSMEN); + + /* Set WAITRESP bits */ + + switch (cmd & MMCSD_RESPONSE_MASK) + { + case MMCSD_NO_RESPONSE: + regval |= SDIO_CMD_NORESPONSE; + break; + + case MMCSD_R1_RESPONSE: + case MMCSD_R1B_RESPONSE: + case MMCSD_R3_RESPONSE: + case MMCSD_R4_RESPONSE: + case MMCSD_R5_RESPONSE: + case MMCSD_R6_RESPONSE: + case MMCSD_R7_RESPONSE: + regval |= SDIO_CMD_SHORTRESPONSE; + break; + + case MMCSD_R2_RESPONSE: + regval |= SDIO_CMD_LONGRESPONSE; + break; + } + + /* Set CPSMEN and the command index */ + + cmdidx = (cmd & MMCSD_CMDIDX_MASK) >> MMCSD_CMDIDX_SHIFT; + regval |= cmdidx | SDIO_CMD_CPSMEN; + + mcinfo("cmd: %08" PRIx32 " arg: %08" PRIx32 " regval: %08" PRIx32 + " enabled irq: %08" PRIx32 "\n", + cmd, arg, regval, getreg32(AT32_SDIO_MASK)); + + /* Write the SDIO CMD */ + + putreg32(SDIO_RESPDONE_ICR | SDIO_CMDDONE_ICR, AT32_SDIO_ICR); + putreg32(regval, AT32_SDIO_CMD); + return OK; +} + +/**************************************************************************** + * Name: at32_blocksetup + * + * Description: + * Configure block size and the number of blocks for next transfer + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * blocklen - The selected block size. + * nblocklen - The number of blocks to transfer + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_BLOCKSETUP +static void at32_blocksetup(struct sdio_dev_s *dev, + unsigned int blocklen, unsigned int nblocks) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + /* Configure block size for next transfer */ + + priv->block_size = at32_log2(blocklen); +} +#endif + +/**************************************************************************** + * Name: at32_recvsetup + * + * Description: + * Setup hardware in preparation for data transfer from the card in non-DMA + * (interrupt driven mode). This method will do whatever controller setup + * is necessary. This would be called for SD memory just BEFORE sending + * CMD13 (SEND_STATUS), CMD17 (READ_SINGLE_BLOCK), CMD18 + * (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), etc. Normally, + * SDIO_WAITEVENT will be called to receive the indication that the + * transfer is complete. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - Address of the buffer in which to receive the data + * nbytes - The number of bytes in the transfer + * + * Returned Value: + * Number of bytes sent on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32_recvsetup(struct sdio_dev_s *dev, uint8_t *buffer, + size_t nbytes) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + uint32_t dblocksize; + + DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0); + DEBUGASSERT(((uint32_t)buffer & 3) == 0); + + /* Reset the DPSM configuration */ + + at32_datadisable(); + at32_sampleinit(); + at32_sample(priv, SAMPLENDX_BEFORE_SETUP); + + /* Save the destination buffer information for use by the interrupt + * handler. + */ + + priv->buffer = (uint32_t *)buffer; + priv->remaining = nbytes; +#ifdef CONFIG_AT32_SDIO_DMA + priv->dmamode = false; +#endif + + /* Then set up the SDIO data path */ + +#ifdef CONFIG_SDIO_BLOCKSETUP + if (priv->block_size != AT32_SDIO_USE_DEFAULT_BLOCKSIZE) + { + dblocksize = priv->block_size << SDIO_DCTRL_DBLOCKSIZE_SHIFT; + } + else +#endif + { + dblocksize = at32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT; + } + + at32_dataconfig(SDIO_DTIMER_DATATIMEOUT_MS, nbytes, + dblocksize | SDIO_DCTRL_DTDIR); + + /* And enable interrupts */ + + at32_configxfrints(priv, SDIO_RECV_MASK); + at32_sample(priv, SAMPLENDX_AFTER_SETUP); + return OK; +} + +/**************************************************************************** + * Name: at32_sendsetup + * + * Description: + * Setup hardware in preparation for data transfer from the card. This + * method will do whatever controller setup is necessary. This would be + * called for SD memory just AFTER sending CMD24 (WRITE_BLOCK), CMD25 + * (WRITE_MULTIPLE_BLOCK), ... and before SDIO_SENDDATA is called. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - Address of the buffer containing the data to send + * nbytes - The number of bytes in the transfer + * + * Returned Value: + * Number of bytes sent on success; a negated errno on failure + * + ****************************************************************************/ + +static int at32_sendsetup(struct sdio_dev_s *dev, + const uint8_t *buffer, size_t nbytes) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + uint32_t dblocksize; + + DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0); + DEBUGASSERT(((uint32_t)buffer & 3) == 0); + + /* Reset the DPSM configuration */ + + at32_datadisable(); + at32_sampleinit(); + at32_sample(priv, SAMPLENDX_BEFORE_SETUP); + + /* Save the source buffer information for use by the interrupt handler */ + + priv->buffer = (uint32_t *)buffer; + priv->remaining = nbytes; +#ifdef CONFIG_AT32_SDIO_DMA + priv->dmamode = false; +#endif + + /* Then set up the SDIO data path */ + +#ifdef CONFIG_SDIO_BLOCKSETUP + if (priv->block_size != AT32_SDIO_USE_DEFAULT_BLOCKSIZE) + { + dblocksize = priv->block_size << SDIO_DCTRL_DBLOCKSIZE_SHIFT; + } + else +#endif + { + dblocksize = at32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT; + } + + at32_dataconfig(SDIO_DTIMER_DATATIMEOUT_MS, nbytes, dblocksize); + + /* Enable TX interrupts */ + + at32_configxfrints(priv, SDIO_SEND_MASK); + at32_sample(priv, SAMPLENDX_AFTER_SETUP); + return OK; +} + +/**************************************************************************** + * Name: at32_cancel + * + * Description: + * Cancel the data transfer setup of SDIO_RECVSETUP, SDIO_SENDSETUP, + * SDIO_DMARECVSETUP or SDIO_DMASENDSETUP. This must be called to cancel + * the data transfer setup if, for some reason, you cannot perform the + * transfer. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * OK is success; a negated errno on failure + * + ****************************************************************************/ + +static int at32_cancel(struct sdio_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + /* Disable all transfer- and event- related interrupts */ + + at32_configxfrints(priv, 0); + at32_configwaitints(priv, 0, 0, 0); + + /* Clearing pending interrupt status on all transfer- and event- related + * interrupts + */ + + putreg32(SDIO_WAITALL_ICR, AT32_SDIO_ICR); + + /* Cancel any watchdog timeout */ + + wd_cancel(&priv->waitwdog); + + /* If this was a DMA transfer, make sure that DMA is stopped */ + +#ifdef CONFIG_AT32_SDIO_DMA + if (priv->dmamode) + { + /* Make sure that the DMA is stopped (it will be stopped automatically + * on normal transfers, but not necessarily when the transfer + * terminates on an error condition. + */ + + at32_dmastop(priv->dma); + } +#endif + + /* Mark no transfer in progress */ + + priv->remaining = 0; + return OK; +} + +/**************************************************************************** + * Name: at32_waitresponse + * + * Description: + * Poll-wait for the response to the last command to be ready. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * cmd - The command that was sent. See 32-bit command definitions above. + * + * Returned Value: + * OK is success; a negated errno on failure + * + ****************************************************************************/ + +static int at32_waitresponse(struct sdio_dev_s *dev, uint32_t cmd) +{ + int32_t timeout; + uint32_t events; + + switch (cmd & MMCSD_RESPONSE_MASK) + { + case MMCSD_NO_RESPONSE: + events = SDIO_CMDDONE_STA; + timeout = SDIO_CMDTIMEOUT; + break; + + case MMCSD_R1_RESPONSE: + case MMCSD_R1B_RESPONSE: + case MMCSD_R2_RESPONSE: + case MMCSD_R4_RESPONSE: + case MMCSD_R5_RESPONSE: + case MMCSD_R6_RESPONSE: + events = SDIO_RESPDONE_STA; + timeout = SDIO_LONGTIMEOUT; + break; + + case MMCSD_R3_RESPONSE: + case MMCSD_R7_RESPONSE: + events = SDIO_RESPDONE_STA; + timeout = SDIO_CMDTIMEOUT; + break; + + default: + return -EINVAL; + } + + /* Then wait for the response (or timeout) */ + + while ((getreg32(AT32_SDIO_STA) & events) == 0) + { + if (--timeout <= 0) + { + mcerr("ERROR: Timeout cmd: %08" PRIx32 " events: %08" PRIx32 + " STA: %08" PRIx32 "\n", + cmd, events, getreg32(AT32_SDIO_STA)); + + return -ETIMEDOUT; + } + } + + putreg32(SDIO_CMDDONE_ICR, AT32_SDIO_ICR); + return OK; +} + +/**************************************************************************** + * Name: at32_recv* + * + * Description: + * Receive response to SDIO command. Only the critical payload is + * returned -- that is 32 bits for 48 bit status and 128 bits for 136 bit + * status. The driver implementation should verify the correctness of + * the remaining, non-returned bits (CRCs, CMD index, etc.). + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * Rx - Buffer in which to receive the response + * + * Returned Value: + * Number of bytes sent on success; a negated errno on failure. Here a + * failure means only a faiure to obtain the requested response (due to + * transport problem -- timeout, CRC, etc.). The implementation only + * assures that the response is returned intacta and does not check errors + * within the response itself. + * + ****************************************************************************/ + +static int at32_recvshortcrc(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t *rshort) +{ +#ifdef CONFIG_DEBUG_MEMCARD_INFO + uint32_t respcmd; +#endif + uint32_t regval; + int ret = OK; + + /* R1 Command response (48-bit) + * 47 0 Start bit + * 46 0 Transmission bit (0=from card) + * 45:40 bit5 - bit0 Command index (0-63) + * 39:8 bit31 - bit0 32-bit card status + * 7:1 bit6 - bit0 CRC7 + * 0 1 End bit + * + * R1b Identical to R1 with the additional busy signaling via the data + * line. + * + * R6 Published RCA Response (48-bit, SD card only) + * 47 0 Start bit + * 46 0 Transmission bit (0=from card) + * 45:40 bit5 - bit0 Command index (0-63) + * 39:8 bit31 - bit0 32-bit Argument Field, consisting of: + * [31:16] New published RCA of card + * [15:0] Card status bits {23,22,19,12:0} + * 7:1 bit6 - bit0 CRC7 + * 0 1 End bit + */ + +#ifdef CONFIG_DEBUG_MEMCARD_INFO + if (!rshort) + { + mcerr("ERROR: rshort=NULL\n"); + ret = -EINVAL; + } + + /* Check that this is the correct response to this command */ + + else if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1B_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R5_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R6_RESPONSE) + { + mcerr("ERROR: Wrong response CMD=%08x\n", cmd); + ret = -EINVAL; + } + else +#endif + { + /* Check if a timeout or CRC error occurred */ + + regval = getreg32(AT32_SDIO_STA); + if ((regval & SDIO_STA_CTIMEOUT) != 0) + { + mcerr("ERROR: Command timeout: %08" PRIx32 "\n", regval); + ret = -ETIMEDOUT; + } + else if ((regval & SDIO_STA_CCRCFAIL) != 0) + { + mcerr("ERROR: CRC failure: %08" PRIx32 "\n", regval); + ret = -EIO; + } +#ifdef CONFIG_DEBUG_MEMCARD_INFO + else + { + /* Check response received is of desired command */ + + respcmd = getreg32(AT32_SDIO_RESPCMD); + if ((uint8_t)(respcmd & SDIO_RESPCMD_MASK) != + (cmd & MMCSD_CMDIDX_MASK)) + { + mcerr("ERROR: RESCMD=%02" PRIx32 " CMD=%08" PRIx32 "\n", + respcmd, cmd); + ret = -EINVAL; + } + } +#endif + } + + /* Clear all pending message completion events and return the R1/R6 + * response. + */ + + putreg32(SDIO_RESPDONE_ICR | SDIO_CMDDONE_ICR, AT32_SDIO_ICR); + *rshort = getreg32(AT32_SDIO_RESP1); + return ret; +} + +static int at32_recvlong(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t rlong[4]) +{ + uint32_t regval; + int ret = OK; + + /* R2 CID, CSD register (136-bit) + * 135 0 Start bit + * 134 0 Transmission bit (0=from card) + * 133:128 bit5 - bit0 Reserved + * 127:1 bit127 - bit1 127-bit CID or CSD register + * (including internal CRC) + * 0 1 End bit + */ + +#ifdef CONFIG_DEBUG_MEMCARD_INFO + /* Check that R1 is the correct response to this command */ + + if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R2_RESPONSE) + { + mcerr("ERROR: Wrong response CMD=%08x\n", cmd); + ret = -EINVAL; + } + else +#endif + { + /* Check if a timeout or CRC error occurred */ + + regval = getreg32(AT32_SDIO_STA); + if (regval & SDIO_STA_CTIMEOUT) + { + mcerr("ERROR: Timeout STA: %08" PRIx32 "\n", regval); + ret = -ETIMEDOUT; + } + else if (regval & SDIO_STA_CCRCFAIL) + { + mcerr("ERROR: CRC fail STA: %08" PRIx32 "\n", regval); + ret = -EIO; + } + } + + /* Return the long response */ + + putreg32(SDIO_RESPDONE_ICR | SDIO_CMDDONE_ICR, AT32_SDIO_ICR); + if (rlong) + { + rlong[0] = getreg32(AT32_SDIO_RESP1); + rlong[1] = getreg32(AT32_SDIO_RESP2); + rlong[2] = getreg32(AT32_SDIO_RESP3); + rlong[3] = getreg32(AT32_SDIO_RESP4); + } + + return ret; +} + +static int at32_recvshort(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t *rshort) +{ + uint32_t regval; + int ret = OK; + + /* R3 OCR (48-bit) + * 47 0 Start bit + * 46 0 Transmission bit (0=from card) + * 45:40 bit5 - bit0 Reserved + * 39:8 bit31 - bit0 32-bit OCR register + * 7:1 bit6 - bit0 Reserved + * 0 1 End bit + */ + + /* Check that this is the correct response to this command */ + +#ifdef CONFIG_DEBUG_MEMCARD_INFO + if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R3_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R4_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R7_RESPONSE) + { + mcerr("ERROR: Wrong response CMD=%08x\n", cmd); + ret = -EINVAL; + } + else +#endif + { + /* Check if a timeout occurred (Apparently a CRC error can terminate + * a good response) + */ + + regval = getreg32(AT32_SDIO_STA); + if (regval & SDIO_STA_CTIMEOUT) + { + mcerr("ERROR: Timeout STA: %08" PRIx32 "\n", regval); + ret = -ETIMEDOUT; + } + } + + putreg32(SDIO_RESPDONE_ICR | SDIO_CMDDONE_ICR, AT32_SDIO_ICR); + if (rshort) + { + *rshort = getreg32(AT32_SDIO_RESP1); + } + + return ret; +} + +/**************************************************************************** + * Name: at32_waitenable + * + * Description: + * Enable/disable of a set of SDIO wait events. This is part of the + * the SDIO_WAITEVENT sequence. The set of to-be-waited-for events is + * configured before calling at32_eventwait. This is done in this way + * to help the driver to eliminate race conditions between the command + * setup and the subsequent events. + * + * The enabled events persist until either (1) SDIO_WAITENABLE is called + * again specifying a different set of wait events, or (2) SDIO_EVENTWAIT + * returns. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * eventset - A bitset of events to enable or disable (see SDIOWAIT_* + * definitions). 0=disable; 1=enable. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_waitenable(struct sdio_dev_s *dev, + sdio_eventset_t eventset, uint32_t timeout) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + uint32_t waitmask; + + DEBUGASSERT(priv != NULL); + + /* Disable event-related interrupts */ + + at32_configwaitints(priv, 0, 0, 0); + + /* Select the interrupt mask that will give us the appropriate wakeup + * interrupts. + */ + +#if defined(CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE) + if ((eventset & SDIOWAIT_WRCOMPLETE) != 0) + { + /* eventset carries this */ + + waitmask = 0; + } + else +#endif + { + waitmask = 0; + if ((eventset & SDIOWAIT_CMDDONE) != 0) + { + waitmask |= SDIO_CMDDONE_MASK; + } + + if ((eventset & SDIOWAIT_RESPONSEDONE) != 0) + { + waitmask |= SDIO_RESPDONE_MASK; + } + + if ((eventset & SDIOWAIT_TRANSFERDONE) != 0) + { + waitmask |= SDIO_XFRDONE_MASK; + } + + /* Enable event-related interrupts */ + + putreg32(SDIO_WAITALL_ICR, AT32_SDIO_ICR); + } + + at32_configwaitints(priv, waitmask, eventset, 0); + + /* Check if the timeout event is specified in the event set */ + + if ((priv->waitevents & SDIOWAIT_TIMEOUT) != 0) + { + int delay; + int ret; + + /* Yes.. Handle a cornercase: The user request a timeout event but + * with timeout == 0? + */ + + if (!timeout) + { + priv->wkupevent = SDIOWAIT_TIMEOUT; + return; + } + + /* Start the watchdog timer */ + + delay = MSEC2TICK(timeout); + ret = wd_start(&priv->waitwdog, delay, + at32_eventtimeout, (wdparm_t)priv); + if (ret < 0) + { + mcerr("ERROR: wd_start failed: %d\n", ret); + } + } +} + +/**************************************************************************** + * Name: at32_eventwait + * + * Description: + * Wait for one of the enabled events to occur (or a timeout). Note that + * all events enabled by SDIO_WAITEVENTS are disabled when at32_eventwait + * returns. SDIO_WAITEVENTS must be called again before at32_eventwait + * can be used again. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * timeout - Maximum time in milliseconds to wait. Zero means immediate + * timeout with no wait. The timeout value is ignored if + * SDIOWAIT_TIMEOUT is not included in the waited-for eventset. + * + * Returned Value: + * Event set containing the event(s) that ended the wait. Should always + * be non-zero. All events are disabled after the wait concludes. + * + ****************************************************************************/ + +static sdio_eventset_t at32_eventwait(struct sdio_dev_s *dev) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + sdio_eventset_t wkupevent = 0; + irqstate_t flags; + int ret; + + /* There is a race condition here... the event may have completed before + * we get here. In this case waitevents will be zero, but wkupevents will + * be non-zero (and, hopefully, the semaphore count will also be non-zero. + */ + + flags = enter_critical_section(); + +#if defined(CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE) + /* A card ejected while in SDIOWAIT_WRCOMPLETE can lead to a + * condition where there is no waitevents set and no wkupevent + */ + + if (priv->waitevents == 0 && priv->wkupevent == 0) + { + wkupevent = SDIOWAIT_ERROR; + goto errout_with_waitints; + } + +#else + DEBUGASSERT(priv->waitevents != 0 || priv->wkupevent != 0); +#endif + +#if defined(CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE) + if ((priv->waitevents & SDIOWAIT_WRCOMPLETE) != 0) + { + /* Atomically read pin to see if ready (true) and determine if ISR + * fired. If Pin is ready and if ISR did NOT fire end the wait here. + */ + + if (at32_gpioread(GPIO_SDIO_D0) && + (priv->wkupevent & SDIOWAIT_WRCOMPLETE) == 0) + { + at32_endwait(priv, SDIOWAIT_WRCOMPLETE); + } + } +#endif + + /* Loop until the event (or the timeout occurs). Race conditions are + * avoided by calling at32_waitenable prior to triggering the logic that + * will cause the wait to terminate. Under certain race conditions, the + * waited-for may have already occurred before this function was called! + */ + + for (; ; ) + { + /* Wait for an event in event set to occur. If this the event has + * already occurred, then the semaphore will already have been + * incremented and there will be no wait. + */ + + ret = nxsem_wait_uninterruptible(&priv->waitsem); + if (ret < 0) + { + /* Task canceled. Cancel the wdog (assuming it was started) and + * return an SDIO error. + */ + + wd_cancel(&priv->waitwdog); + wkupevent = SDIOWAIT_ERROR; + goto errout_with_waitints; + } + + wkupevent = priv->wkupevent; + + /* Check if the event has occurred. When the event has occurred, then + * evenset will be set to 0 and wkupevent will be set to a nonzero + * value. + */ + + if (wkupevent != 0) + { + /* Yes... break out of the loop with wkupevent non-zero */ + + break; + } + } + + /* Disable event-related interrupts */ + +errout_with_waitints: + at32_configwaitints(priv, 0, 0, 0); +#ifdef CONFIG_AT32_SDIO_DMA + priv->xfrflags = 0; +#endif + + leave_critical_section(flags); + at32_dumpsamples(priv); + return wkupevent; +} + +/**************************************************************************** + * Name: at32_callbackenable + * + * Description: + * Enable/disable of a set of SDIO callback events. This is part of the + * the SDIO callback sequence. The set of events is configured to enabled + * callbacks to the function provided in at32_registercallback. + * + * Events are automatically disabled once the callback is performed and no + * further callback events will occur until they are again enabled by + * calling this method. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * eventset - A bitset of events to enable or disable (see SDIOMEDIA_* + * definitions). 0=disable; 1=enable. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void at32_callbackenable(struct sdio_dev_s *dev, + sdio_eventset_t eventset) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + mcinfo("eventset: %02x\n", eventset); + DEBUGASSERT(priv != NULL); + + priv->cbevents = eventset; + at32_callback(priv); +} + +/**************************************************************************** + * Name: at32_registercallback + * + * Description: + * Register a callback that that will be invoked on any media status + * change. Callbacks should not be made from interrupt handlers, rather + * interrupt level events should be handled by calling back on the work + * thread. + * + * When this method is called, all callbacks should be disabled until they + * are enabled via a call to SDIO_CALLBACKENABLE + * + * Input Parameters: + * dev - Device-specific state data + * callback - The function to call on the media change + * arg - A caller provided value to return with the callback + * + * Returned Value: + * 0 on success; negated errno on failure. + * + ****************************************************************************/ + +static int at32_registercallback(struct sdio_dev_s *dev, + worker_t callback, void *arg) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + /* Disable callbacks and register this callback and is argument */ + + mcinfo("Register %p(%p)\n", callback, arg); + DEBUGASSERT(priv != NULL); + + priv->cbevents = 0; + priv->cbarg = arg; + priv->callback = callback; + return OK; +} + +/**************************************************************************** + * Name: at32_dmapreflight + * + * Description: + * Preflight an SDIO DMA operation. If the buffer is not well-formed for + * SDIO DMA transfer (alignment, size, etc.) returns an error. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - The memory to DMA to/from + * buflen - The size of the DMA transfer in bytes + * + * Returned Value: + * OK on success; a negated errno on failure + ****************************************************************************/ + +#if defined(CONFIG_AT32_SDIO_DMA) && defined(CONFIG_ARCH_HAVE_SDIO_PREFLIGHT) +static int at32_dmapreflight(struct sdio_dev_s *dev, + const uint8_t *buffer, size_t buflen) +{ +#if !defined(CONFIG_AT32_AT32F4XXX) + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); + + /* Wide bus operation is required for DMA */ + + if (!priv->widebus) + { + return -EINVAL; + } +#endif + + /* DMA must be possible to the buffer */ + + if (!at32_dmacapable((uintptr_t)buffer, (buflen + 3) >> 2, + SDIO_RXDMA32_CONFIG)) + { + return -EFAULT; + } + + return 0; +} +#endif + +/**************************************************************************** + * Name: at32_dmarecvsetup + * + * Description: + * Setup to perform a read DMA. If the processor supports a data cache, + * then this method will also make sure that the contents of the DMA memory + * and the data cache are coherent. For read transfers this may mean + * invalidating the data cache. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - The memory to DMA from + * buflen - The size of the DMA transfer in bytes + * + * Returned Value: + * OK on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SDIO_DMA +static int at32_dmarecvsetup(struct sdio_dev_s *dev, + uint8_t *buffer, size_t buflen) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + uint32_t dblocksize; + + DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); +#ifdef CONFIG_ARCH_HAVE_SDIO_PREFLIGHT + DEBUGASSERT(at32_dmapreflight(dev, buffer, buflen) == 0); +#endif + + /* Reset the DPSM configuration */ + + at32_datadisable(); + + /* Initialize register sampling */ + + at32_sampleinit(); + at32_sample(priv, SAMPLENDX_BEFORE_SETUP); + + /* Save the destination buffer information for use by the interrupt + * handler. + */ + + priv->buffer = (uint32_t *)buffer; + priv->remaining = buflen; + priv->dmamode = true; + + /* Then set up the SDIO data path */ + +#ifdef CONFIG_SDIO_BLOCKSETUP + if (priv->block_size != AT32_SDIO_USE_DEFAULT_BLOCKSIZE) + { + dblocksize = priv->block_size << SDIO_DCTRL_DBLOCKSIZE_SHIFT; + } + else +#endif + { + dblocksize = at32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT; + } + + at32_dataconfig(SDIO_DTIMER_DATATIMEOUT_MS, buflen, + dblocksize | SDIO_DCTRL_DTDIR); + + /* Configure the RX DMA */ + + at32_configxfrints(priv, SDIO_DMARECV_MASK); + + putreg32(1, SDIO_DCTRL_DMAEN_BB); + at32_dmasetup(priv->dma, AT32_SDIO_FIFO, (uint32_t)buffer, + (buflen + 3) >> 2, SDIO_RXDMA32_CONFIG); + + /* Start the DMA */ + + at32_sample(priv, SAMPLENDX_BEFORE_ENABLE); + at32_dmastart(priv->dma, at32_dmacallback, priv, false); + at32_sample(priv, SAMPLENDX_AFTER_SETUP); + + return OK; +} +#endif + +/**************************************************************************** + * Name: at32_dmasendsetup + * + * Description: + * Setup to perform a write DMA. If the processor supports a data cache, + * then this method will also make sure that the contents of the DMA memory + * and the data cache are coherent. For write transfers, this may mean + * flushing the data cache. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - The memory to DMA into + * buflen - The size of the DMA transfer in bytes + * + * Returned Value: + * OK on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SDIO_DMA +static int at32_dmasendsetup(struct sdio_dev_s *dev, + const uint8_t *buffer, size_t buflen) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + uint32_t dblocksize; + + DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); +#ifdef CONFIG_ARCH_HAVE_SDIO_PREFLIGHT + DEBUGASSERT(at32_dmapreflight(dev, buffer, buflen) == 0); +#endif + + /* Reset the DPSM configuration */ + + at32_datadisable(); + + /* Initialize register sampling */ + + at32_sampleinit(); + at32_sample(priv, SAMPLENDX_BEFORE_SETUP); + + /* Save the source buffer information for use by the interrupt handler */ + + priv->buffer = (uint32_t *)buffer; + priv->remaining = buflen; + priv->dmamode = true; + + /* Then set up the SDIO data path */ + +#ifdef CONFIG_SDIO_BLOCKSETUP + if (priv->block_size != AT32_SDIO_USE_DEFAULT_BLOCKSIZE) + { + dblocksize = priv->block_size << SDIO_DCTRL_DBLOCKSIZE_SHIFT; + } + else +#endif + { + dblocksize = at32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT; + } + + at32_dataconfig(SDIO_DTIMER_DATATIMEOUT_MS, buflen, dblocksize); + + /* Configure the TX DMA */ + + at32_dmasetup(priv->dma, AT32_SDIO_FIFO, (uint32_t)buffer, + (buflen + 3) >> 2, SDIO_TXDMA32_CONFIG); + + at32_sample(priv, SAMPLENDX_BEFORE_ENABLE); + putreg32(1, SDIO_DCTRL_DMAEN_BB); + + /* Start the DMA */ + + at32_dmastart(priv->dma, at32_dmacallback, priv, false); + at32_sample(priv, SAMPLENDX_AFTER_SETUP); + + /* Enable TX interrupts */ + + at32_configxfrints(priv, SDIO_DMASEND_MASK); + + return OK; +} +#endif + +/**************************************************************************** + * Name: at32_callback + * + * Description: + * Perform callback. + * + * Assumptions: + * This function does not execute in the context of an interrupt handler. + * It may be invoked on any user thread or scheduled on the work thread + * from an interrupt handler. + * + ****************************************************************************/ + +static void at32_callback(void *arg) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)arg; + + /* Is a callback registered? */ + + DEBUGASSERT(priv != NULL); + mcinfo("Callback %p(%p) cbevents: %02x cdstatus: %02x\n", + priv->callback, priv->cbarg, priv->cbevents, priv->cdstatus); + + if (priv->callback) + { + /* Yes.. Check for enabled callback events */ + + if ((priv->cdstatus & SDIO_STATUS_PRESENT) != 0) + { + /* Media is present. Is the media inserted event enabled? */ + + if ((priv->cbevents & SDIOMEDIA_INSERTED) == 0) + { + /* No... return without performing the callback */ + + return; + } + } + else + { + /* Media is not present. Is the media eject event enabled? */ + + if ((priv->cbevents & SDIOMEDIA_EJECTED) == 0) + { + /* No... return without performing the callback */ + + return; + } + } + + /* Perform the callback, disabling further callbacks. Of course, the + * the callback can (and probably should) re-enable callbacks. + */ + + priv->cbevents = 0; + + /* Callbacks cannot be performed in the context of an interrupt + * handler. If we are in an interrupt handler, then queue the + * callback to be performed later on the work thread. + */ + + if (up_interrupt_context()) + { + /* Yes.. queue it */ + + mcinfo("Queuing callback to %p(%p)\n", + priv->callback, priv->cbarg); + work_queue(HPWORK, &priv->cbwork, priv->callback, + priv->cbarg, 0); + } + else + { + /* No.. then just call the callback here */ + + mcinfo("Callback to %p(%p)\n", priv->callback, priv->cbarg); + priv->callback(priv->cbarg); + } + } +} + +/**************************************************************************** + * Name: at32_default + * + * Description: + * Restore SDIO registers to their default, reset values + * + ****************************************************************************/ + +static void at32_default(void) +{ + putreg32(SDIO_POWER_RESET, AT32_SDIO_POWER); + putreg32(SDIO_CLKCR_RESET, AT32_SDIO_CLKCR); + putreg32(SDIO_ARG_RESET, AT32_SDIO_ARG); + putreg32(SDIO_CMD_RESET, AT32_SDIO_CMD); + putreg32(SDIO_DTIMER_RESET, AT32_SDIO_DTIMER); + putreg32(SDIO_DLEN_RESET, AT32_SDIO_DLEN); + putreg32(SDIO_DCTRL_RESET, AT32_SDIO_DCTRL); + putreg32(SDIO_ICR_RESET, AT32_SDIO_ICR); + putreg32(SDIO_MASK_RESET, AT32_SDIO_MASK); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sdio_initialize + * + * Description: + * Initialize SDIO for operation. + * + * Input Parameters: + * slotno - Not used. + * + * Returned Value: + * A reference to an SDIO interface structure. NULL is returned on + * failures. + * + ****************************************************************************/ + +struct sdio_dev_s *sdio_initialize(int slotno) +{ + /* There is only one slot */ + + struct at32_dev_s *priv = &g_sdiodev; + + /* Allocate a DMA channel */ + +#ifdef CONFIG_AT32_SDIO_DMA + priv->dma = at32_dmachannel(SDIO_DMACHAN); + DEBUGASSERT(priv->dma); +#endif + + /* Configure GPIOs for 4-bit, wide-bus operation (the chip is capable of + * 8-bit wide bus operation but D4-D7 are not configured). + * + * If bus is multiplexed then there is a custom bus configuration utility + * in the scope of the board support package. + */ + +#ifndef CONFIG_SDIO_MUXBUS + at32_configgpio(GPIO_SDIO_D0 | SDIO_PULLUP_ENABLE); +#ifndef CONFIG_AT32_SDIO_WIDTH_D1_ONLY + at32_configgpio(GPIO_SDIO_D1 | SDIO_PULLUP_ENABLE); + at32_configgpio(GPIO_SDIO_D2 | SDIO_PULLUP_ENABLE); + at32_configgpio(GPIO_SDIO_D3 | SDIO_PULLUP_ENABLE); +#endif + at32_configgpio(GPIO_SDIO_CK | SDIO_PULLUP_ENABLE); + at32_configgpio(GPIO_SDIO_CMD | SDIO_PULLUP_ENABLE); +#endif + + /* Reset the card and assure that it is in the initial, unconfigured + * state. + */ + + at32_reset(&priv->dev); + return &g_sdiodev.dev; +} + +/**************************************************************************** + * Name: sdio_mediachange + * + * Description: + * Called by board-specific logic -- possibly from an interrupt handler -- + * in order to signal to the driver that a card has been inserted or + * removed from the slot + * + * Input Parameters: + * dev - An instance of the SDIO driver device state structure. + * cardinslot - true is a card has been detected in the slot; false if a + * card has been removed from the slot. Only transitions + * (inserted->removed or removed->inserted should be reported) + * + * Returned Value: + * None + * + ****************************************************************************/ + +void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + sdio_statset_t cdstatus; + irqstate_t flags; + + /* Update card status */ + + flags = enter_critical_section(); + cdstatus = priv->cdstatus; + if (cardinslot) + { + priv->cdstatus |= SDIO_STATUS_PRESENT; + } + else + { + priv->cdstatus &= ~SDIO_STATUS_PRESENT; + } + + leave_critical_section(flags); + + mcinfo("cdstatus OLD: %02x NEW: %02x\n", cdstatus, priv->cdstatus); + + /* Perform any requested callback if the status has changed */ + + if (cdstatus != priv->cdstatus) + { + at32_callback(priv); + } +} + +/**************************************************************************** + * Name: sdio_wrprotect + * + * Description: + * Called by board-specific logic to report if the card in the slot is + * mechanically write protected. + * + * Input Parameters: + * dev - An instance of the SDIO driver device state structure. + * wrprotect - true is a card is writeprotected. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + irqstate_t flags; + + /* Update card status */ + + flags = enter_critical_section(); + if (wrprotect) + { + priv->cdstatus |= SDIO_STATUS_WRPROTECTED; + } + else + { + priv->cdstatus &= ~SDIO_STATUS_WRPROTECTED; + } + + mcinfo("cdstatus: %02x\n", priv->cdstatus); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: sdio_set_sdio_card_isr + * + * Description: + * SDIO card generates interrupt via SDIO_DATA_1 pin. + * Called by board-specific logic to register an ISR for SDIO card. + * + * Input Parameters: + * func - callback function. + * arg - arg to be passed to the function. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SDIO_CARD +void sdio_set_sdio_card_isr(struct sdio_dev_s *dev, + int (*func)(void *), void *arg) +{ + struct at32_dev_s *priv = (struct at32_dev_s *)dev; + + priv->do_sdio_card = func; + + if (func != NULL) + { + priv->sdiointmask = SDIO_STA_SDIOIT; + priv->do_sdio_arg = arg; + } + else + { + priv->sdiointmask = 0; + } + + putreg32(priv->xfrmask | priv->waitmask | priv->sdiointmask, + AT32_SDIO_MASK); +} +#endif + +#endif /* CONFIG_AT32_SDIO */ diff --git a/arch/arm/src/at32/at32_sdio.h b/arch/arm/src/at32/at32_sdio.h new file mode 100644 index 0000000000..c19283985f --- /dev/null +++ b/arch/arm/src/at32/at32_sdio.h @@ -0,0 +1,134 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_sdio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_SDIO_H +#define __ARCH_ARM_SRC_AT32_AT32_SDIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "chip.h" +#include "hardware/at32_sdio.h" + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: sdio_initialize + * + * Description: + * Initialize SDIO for operation. + * + * Input Parameters: + * slotno - Not used. + * + * Returned Value: + * A reference to an SDIO interface structure. NULL is returned on + * failures. + * + ****************************************************************************/ + +struct sdio_dev_s; /* See include/nuttx/sdio.h */ +struct sdio_dev_s *sdio_initialize(int slotno); + +/**************************************************************************** + * Name: sdio_mediachange + * + * Description: + * Called by board-specific logic -- possibly from an interrupt handler -- + * in order to signal to the driver that a card has been inserted or + * removed from the slot + * + * Input Parameters: + * dev - An instance of the SDIO driver device state structure. + * cardinslot - true is a card has been detected in the slot; false if a + * card has been removed from the slot. Only transitions + * (inserted->removed or removed->inserted should be reported) + * + * Returned Value: + * None + * + ****************************************************************************/ + +void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot); + +/**************************************************************************** + * Name: sdio_wrprotect + * + * Description: + * Called by board-specific logic to report if the card in the slot is + * mechanically write protected. + * + * Input Parameters: + * dev - An instance of the SDIO driver device state structure. + * wrprotect - true is a card is writeprotected. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect); + +/**************************************************************************** + * Name: sdio_set_sdio_card_isr + * + * Description: + * SDIO card generates interrupt via SDIO_DATA_1 pin. + * Called by board-specific logic to register an ISR for SDIO card. + * + * Input Parameters: + * func - callback function. + * arg - arg to be passed to the function. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SDIO_CARD +void sdio_set_sdio_card_isr(struct sdio_dev_s *dev, + int (*func)(void *), void *arg); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_SDIO_H */ diff --git a/arch/arm/src/at32/at32_serial.c b/arch/arm/src/at32/at32_serial.c new file mode 100644 index 0000000000..c126bd7710 --- /dev/null +++ b/arch/arm/src/at32/at32_serial.c @@ -0,0 +1,3049 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_serial.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_SERIAL_TERMIOS +# include +#endif + +#include + +#include "chip.h" +#include "at32_uart.h" +#include "at32_dma.h" +#include "at32_rcc.h" +#include "arm_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Some sanity checks *******************************************************/ + +/* DMA configuration */ + +/* If DMA is enabled on any USART, then very that other pre-requisites + * have also been selected. + */ + +#ifdef SERIAL_HAVE_RXDMA + +/* The DMA buffer size when using RX DMA to emulate a FIFO. + * + * When streaming data, the generic serial layer will be called + * every time the FIFO receives half this number of bytes. + */ +# if !defined(CONFIG_AT32_SERIAL_RXDMA_BUFFER_SIZE) +# define CONFIG_AT32_SERIAL_RXDMA_BUFFER_SIZE 32 +# endif +# define RXDMA_MUTIPLE 4 +# define RXDMA_MUTIPLE_MASK (RXDMA_MUTIPLE -1) +# define RXDMA_BUFFER_SIZE ((CONFIG_AT32_SERIAL_RXDMA_BUFFER_SIZE \ + + RXDMA_MUTIPLE_MASK) \ + & ~RXDMA_MUTIPLE_MASK) + +/* DMA priority */ + +# ifndef CONFIG_USART_RXDMAPRIO +# if defined(CONFIG_AT32_HAVE_IP_DMA_V1) +# define CONFIG_USART_RXDMAPRIO DMA_CCR_PRIMED +# else +# error "Unknown AT32 DMA" +# endif +# endif +# if defined(CONFIG_AT32_HAVE_IP_DMA_V1) +# if (CONFIG_USART_RXDMAPRIO & ~DMA_CCR_PL_MASK) != 0 +# error "Illegal value for CONFIG_USART_RXDMAPRIO" +# endif +# else +# error "Unknown AT32 DMA" +# endif + +/* DMA control word */ + +# define SERIAL_RXDMA_CONTROL_WORD \ + (DMA_CCR_CIRC | \ + DMA_CCR_MINC | \ + DMA_CCR_PSIZE_8BITS | \ + DMA_CCR_MSIZE_8BITS | \ + CONFIG_USART_RXDMAPRIO) + +#endif /* SERIAL_HAVE_RXDMA */ + +#ifdef SERIAL_HAVE_TXDMA + +/* DMA priority */ + +# ifndef CONFIG_USART_TXDMAPRIO +# if defined(CONFIG_AT32_HAVE_IP_DMA_V1) +# define CONFIG_USART_TXDMAPRIO DMA_CCR_PRIMED +# else +# error "Unknown AT32 DMA" +# endif +# endif +# if defined(CONFIG_AT32_HAVE_IP_DMA_V1) +# if (CONFIG_USART_TXDMAPRIO & ~DMA_CCR_PL_MASK) != 0 +# error "Illegal value for CONFIG_USART_TXDMAPRIO" +# endif +# else +# error "Unknown AT32 DMA" +# endif + +/* DMA control word */ + +# if defined(CONFIG_AT32_HAVE_IP_DMA_V1) +# define SERIAL_TXDMA_CONTROL_WORD \ + (DMA_CCR_DIR | \ + DMA_CCR_MINC | \ + DMA_CCR_PSIZE_8BITS | \ + DMA_CCR_MSIZE_8BITS | \ + CONFIG_USART_TXDMAPRIO) +# else +# error "Unknown AT32 DMA" +# endif + +/* DMA ISR status */ + +# if defined(CONFIG_AT32_HAVE_IP_DMA_V1) +# define DMA_ISR_HTIF_BIT DMA_CHAN_HTIF_BIT +# define DMA_ISR_TCIF_BIT DMA_CHAN_TCIF_BIT +# else +# error "Unknown AT32 DMA" +# endif + +#endif /* SERIAL_HAVE_TXDMA */ + +/* Power management definitions */ + +#if defined(CONFIG_PM) && !defined(CONFIG_AT32_PM_SERIAL_ACTIVITY) +# define CONFIG_AT32_PM_SERIAL_ACTIVITY 10 +#endif + +/* Since RX DMA or TX DMA or both may be enabled for a given U[S]ART. + * We need runtime detection in up_dma_setup and up_dma_shutdown + * We use the default struct default init value of 0 which maps to + * AT32_DMA_MAP(DMA1,DMA_STREAM0,DMA_CHAN0) which is not a U[S]ART. + */ + +#define INVALID_SERIAL_DMA_CHANNEL 0 + +/* Keep track if a Break was set + * + * Note: + * + * 1) This value is set in the priv->ie but never written to the control + * register. It must not collide with USART_CR1_USED_INTS or + * USART_CTRL3_ERRIEN + * 2) USART_CTRL3_ERRIEN is also carried in the up_dev_s ie member. + * + * See up_restoreusartint where the masking is done. + */ + +#ifdef CONFIG_AT32_SERIALBRK_BSDCOMPAT +# define USART_CR1_IE_BREAK_INPROGRESS_SHFTS 15 +# define USART_CR1_IE_BREAK_INPROGRESS (1 << USART_CR1_IE_BREAK_INPROGRESS_SHFTS) +#endif + +#ifdef USE_SERIALDRIVER +#ifdef HAVE_SERIALDRIVER + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct up_dev_s +{ + struct uart_dev_s dev; /* Generic UART device */ + uint16_t ie; /* Saved interrupt mask bits value */ + uint16_t sr; /* Saved status bits */ + + /* Has been initialized and HW is setup. */ + + bool initialized; + + /* If termios are supported, then the following fields may vary at + * runtime. + */ + +#ifdef CONFIG_SERIAL_TERMIOS + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (7 or 8) */ + bool stopbits2; /* True: Configure with 2 stop bits instead of 1 */ +#ifdef CONFIG_SERIAL_IFLOWCONTROL + bool iflow; /* input flow control (RTS) enabled */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + bool oflow; /* output flow control (CTS) enabled */ +#endif + uint32_t baud; /* Configured baud */ +#else + const uint8_t parity; /* 0=none, 1=odd, 2=even */ + const uint8_t bits; /* Number of bits (7 or 8) */ + const bool stopbits2; /* True: Configure with 2 stop bits instead of 1 */ +#ifdef CONFIG_SERIAL_IFLOWCONTROL + const bool iflow; /* input flow control (RTS) enabled */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + const bool oflow; /* output flow control (CTS) enabled */ +#endif + const uint32_t baud; /* Configured baud */ +#endif + + const uint8_t irq; /* IRQ associated with this USART */ + const uint32_t apbclock; /* PCLK 1 or 2 frequency */ + const uint32_t usartbase; /* Base address of USART registers */ + const uint32_t tx_gpio; /* U[S]ART TX GPIO pin configuration */ + const uint32_t rx_gpio; /* U[S]ART RX GPIO pin configuration */ +#ifdef CONFIG_SERIAL_IFLOWCONTROL + const uint32_t rts_gpio; /* U[S]ART RTS GPIO pin configuration */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + const uint32_t cts_gpio; /* U[S]ART CTS GPIO pin configuration */ +#endif + + /* TX DMA state */ + +#ifdef SERIAL_HAVE_TXDMA + const unsigned int txdma_channel; /* DMA channel assigned */ + DMA_HANDLE txdma; /* currently-open trasnmit DMA stream */ +#endif + +#ifdef SERIAL_HAVE_RXDMA + const unsigned int rxdma_channel; /* DMA channel assigned */ +#endif + + /* RX DMA state */ + +#ifdef SERIAL_HAVE_RXDMA + DMA_HANDLE rxdma; /* currently-open receive DMA stream */ + bool rxenable; /* DMA-based reception en/disable */ + uint32_t rxdmanext; /* Next byte in the DMA buffer to be read */ + char *const rxfifo; /* Receive DMA buffer */ +#endif + +#ifdef HAVE_RS485 + const uint32_t rs485_dir_gpio; /* U[S]ART RS-485 DIR GPIO pin cfg */ + const bool rs485_dir_polarity; /* U[S]ART RS-485 DIR TXEN polarity */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void up_set_format(struct uart_dev_s *dev); +static int up_setup(struct uart_dev_s *dev); +static void up_shutdown(struct uart_dev_s *dev); +static int up_attach(struct uart_dev_s *dev); +static void up_detach(struct uart_dev_s *dev); +static int up_interrupt(int irq, void *context, void *arg); +static int up_ioctl(struct file *filep, int cmd, unsigned long arg); +#if defined(SERIAL_HAVE_TXDMA_OPS) || defined(SERIAL_HAVE_NODMA_OPS) +static int up_receive(struct uart_dev_s *dev, unsigned int *status); +static void up_rxint(struct uart_dev_s *dev, bool enable); +static bool up_rxavailable(struct uart_dev_s *dev); +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool up_rxflowcontrol(struct uart_dev_s *dev, unsigned int nbuffered, + bool upper); +#endif +static void up_send(struct uart_dev_s *dev, int ch); +#if defined(SERIAL_HAVE_RXDMA_OPS) || defined(SERIAL_HAVE_NODMA_OPS) || \ + defined(CONFIG_AT32_SERIALBRK_BSDCOMPAT) +static void up_txint(struct uart_dev_s *dev, bool enable); +#endif +static bool up_txready(struct uart_dev_s *dev); + +#ifdef SERIAL_HAVE_TXDMA +static void up_dma_send(struct uart_dev_s *dev); +static void up_dma_txint(struct uart_dev_s *dev, bool enable); +static void up_dma_txavailable(struct uart_dev_s *dev); +static void up_dma_txcallback(DMA_HANDLE handle, uint8_t status, void *arg); +#endif + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int up_dma_setup(struct uart_dev_s *dev); +static void up_dma_shutdown(struct uart_dev_s *dev); +#endif + +#ifdef SERIAL_HAVE_RXDMA +static int up_dma_receive(struct uart_dev_s *dev, unsigned int *status); +static void up_dma_rxint(struct uart_dev_s *dev, bool enable); +static bool up_dma_rxavailable(struct uart_dev_s *dev); + +static void up_dma_rxcallback(DMA_HANDLE handle, uint8_t status, void *arg); +#endif + +#ifdef CONFIG_PM +static void up_pm_notify(struct pm_callback_s *cb, int dowmin, + enum pm_state_e pmstate); +static int up_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef SERIAL_HAVE_NODMA_OPS +static const struct uart_ops_s g_uart_ops = +{ + .setup = up_setup, + .shutdown = up_shutdown, + .attach = up_attach, + .detach = up_detach, + .ioctl = up_ioctl, + .receive = up_receive, + .rxint = up_rxint, + .rxavailable = up_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = up_rxflowcontrol, +#endif + .send = up_send, + .txint = up_txint, + .txready = up_txready, + .txempty = up_txready, +}; +#endif + +#ifdef SERIAL_HAVE_RXTXDMA_OPS +static const struct uart_ops_s g_uart_rxtxdma_ops = +{ + .setup = up_dma_setup, + .shutdown = up_dma_shutdown, + .attach = up_attach, + .detach = up_detach, + .ioctl = up_ioctl, + .receive = up_dma_receive, + .rxint = up_dma_rxint, + .rxavailable = up_dma_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = up_rxflowcontrol, +#endif + .send = up_send, + .txint = up_dma_txint, + .txready = up_txready, + .txempty = up_txready, + .dmatxavail = up_dma_txavailable, + .dmasend = up_dma_send, +}; +#endif + +#ifdef SERIAL_HAVE_RXDMA_OPS +static const struct uart_ops_s g_uart_rxdma_ops = +{ + .setup = up_dma_setup, + .shutdown = up_dma_shutdown, + .attach = up_attach, + .detach = up_detach, + .ioctl = up_ioctl, + .receive = up_dma_receive, + .rxint = up_dma_rxint, + .rxavailable = up_dma_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = up_rxflowcontrol, +#endif + .send = up_send, + .txint = up_txint, + .txready = up_txready, + .txempty = up_txready, +}; +#endif + +#ifdef SERIAL_HAVE_TXDMA_OPS +static const struct uart_ops_s g_uart_txdma_ops = +{ + .setup = up_dma_setup, + .shutdown = up_dma_shutdown, + .attach = up_attach, + .detach = up_detach, + .ioctl = up_ioctl, + .receive = up_receive, + .rxint = up_rxint, + .rxavailable = up_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = up_rxflowcontrol, +#endif + .send = up_send, + .txint = up_dma_txint, + .txready = up_txready, + .txempty = up_txready, + .dmatxavail = up_dma_txavailable, + .dmasend = up_dma_send, +}; +#endif + +/* I/O buffers */ + +#ifdef CONFIG_AT32_USART1_SERIALDRIVER +static char g_usart1rxbuffer[CONFIG_USART1_RXBUFSIZE]; +static char g_usart1txbuffer[CONFIG_USART1_TXBUFSIZE]; +# ifdef CONFIG_USART1_RXDMA +static char g_usart1rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_AT32_USART2_SERIALDRIVER +static char g_usart2rxbuffer[CONFIG_USART2_RXBUFSIZE]; +static char g_usart2txbuffer[CONFIG_USART2_TXBUFSIZE]; +# ifdef CONFIG_USART2_RXDMA +static char g_usart2rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_AT32_USART3_SERIALDRIVER +static char g_usart3rxbuffer[CONFIG_USART3_RXBUFSIZE]; +static char g_usart3txbuffer[CONFIG_USART3_TXBUFSIZE]; +# ifdef CONFIG_USART3_RXDMA +static char g_usart3rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_AT32_UART4_SERIALDRIVER +static char g_uart4rxbuffer[CONFIG_UART4_RXBUFSIZE]; +static char g_uart4txbuffer[CONFIG_UART4_TXBUFSIZE]; +# ifdef CONFIG_UART4_RXDMA +static char g_uart4rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_AT32_UART5_SERIALDRIVER +static char g_uart5rxbuffer[CONFIG_UART5_RXBUFSIZE]; +static char g_uart5txbuffer[CONFIG_UART5_TXBUFSIZE]; +# ifdef CONFIG_UART5_RXDMA +static char g_uart5rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_AT32_USART6_SERIALDRIVER +static char g_usart6rxbuffer[CONFIG_USART6_RXBUFSIZE]; +static char g_usart6txbuffer[CONFIG_USART6_TXBUFSIZE]; +# ifdef CONFIG_USART6_RXDMA +static char g_usart6rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_AT32_UART7_SERIALDRIVER +static char g_uart7rxbuffer[CONFIG_UART7_RXBUFSIZE]; +static char g_uart7txbuffer[CONFIG_UART7_TXBUFSIZE]; +# ifdef CONFIG_UART7_RXDMA +static char g_uart7rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +#ifdef CONFIG_AT32_UART8_SERIALDRIVER +static char g_uart8rxbuffer[CONFIG_UART8_RXBUFSIZE]; +static char g_uart8txbuffer[CONFIG_UART8_TXBUFSIZE]; +# ifdef CONFIG_UART8_RXDMA +static char g_uart8rxfifo[RXDMA_BUFFER_SIZE]; +# endif +#endif + +/* This describes the state of the AT32 USART1 ports. */ + +#ifdef CONFIG_AT32_USART1_SERIALDRIVER +static struct up_dev_s g_usart1priv = +{ + .dev = + { +#if CONSOLE_UART == 1 + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_USART1_RXBUFSIZE, + .buffer = g_usart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART1_TXBUFSIZE, + .buffer = g_usart1txbuffer, + }, +#if defined(CONFIG_USART1_RXDMA) && defined(CONFIG_USART1_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_USART1_RXDMA) && !defined(CONFIG_USART1_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_USART1_RXDMA) && defined(CONFIG_USART1_TXDMA) + .ops = &g_uart_txdma_ops, +#else + .ops = &g_uart_ops, +#endif + .priv = &g_usart1priv, + }, + + .irq = AT32_IRQ_USART1, + .parity = CONFIG_USART1_PARITY, + .bits = CONFIG_USART1_BITS, + .stopbits2 = CONFIG_USART1_2STOP, + .baud = CONFIG_USART1_BAUD, + + .apbclock = AT32_PCLK2_FREQUENCY, + + .usartbase = AT32_USART1_BASE, + .tx_gpio = GPIO_USART1_TX, + .rx_gpio = GPIO_USART1_RX, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_USART1_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_USART1_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_USART1_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_USART1_RTS, +#endif +#ifdef CONFIG_USART1_TXDMA + .txdma_channel = DMAMUX_USART1_TX, +#endif +#ifdef CONFIG_USART1_RXDMA + .rxdma_channel = DMAMUX_USART1_RX, + .rxfifo = g_usart1rxfifo, +#endif + +#ifdef CONFIG_USART1_RS485 + .rs485_dir_gpio = GPIO_USART1_RS485_DIR, +# if (CONFIG_USART1_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif +}; +#endif + +/* This describes the state of the AT32 USART2 port. */ + +#ifdef CONFIG_AT32_USART2_SERIALDRIVER +static struct up_dev_s g_usart2priv = +{ + .dev = + { +#if CONSOLE_UART == 2 + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_USART2_RXBUFSIZE, + .buffer = g_usart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART2_TXBUFSIZE, + .buffer = g_usart2txbuffer, + }, +#if defined(CONFIG_USART2_RXDMA) && defined(CONFIG_USART2_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_USART2_RXDMA) && !defined(CONFIG_USART2_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_USART2_RXDMA) && defined(CONFIG_USART2_TXDMA) + .ops = &g_uart_txdma_ops, +#else + .ops = &g_uart_ops, +#endif + .priv = &g_usart2priv, + }, + + .irq = AT32_IRQ_USART2, + .parity = CONFIG_USART2_PARITY, + .bits = CONFIG_USART2_BITS, + .stopbits2 = CONFIG_USART2_2STOP, + .baud = CONFIG_USART2_BAUD, + .apbclock = AT32_PCLK1_FREQUENCY, + .usartbase = AT32_USART2_BASE, + .tx_gpio = GPIO_USART2_TX, + .rx_gpio = GPIO_USART2_RX, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_USART2_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_USART2_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_USART2_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_USART2_RTS, +#endif +#ifdef CONFIG_USART2_TXDMA + .txdma_channel = DMAMUX_USART2_TX, +#endif +#ifdef CONFIG_USART2_RXDMA + .rxdma_channel = DMAMUX_USART2_RX, + .rxfifo = g_usart2rxfifo, +#endif + +#ifdef CONFIG_USART2_RS485 + .rs485_dir_gpio = GPIO_USART2_RS485_DIR, +# if (CONFIG_USART2_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif +}; +#endif + +/* This describes the state of the AT32 USART3 port. */ + +#ifdef CONFIG_AT32_USART3_SERIALDRIVER +static struct up_dev_s g_usart3priv = +{ + .dev = + { +#if CONSOLE_UART == 3 + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_USART3_RXBUFSIZE, + .buffer = g_usart3rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART3_TXBUFSIZE, + .buffer = g_usart3txbuffer, + }, +#if defined(CONFIG_USART3_RXDMA) && defined(CONFIG_USART3_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_USART3_RXDMA) && !defined(CONFIG_USART3_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_USART3_RXDMA) && defined(CONFIG_USART3_TXDMA) + .ops = &g_uart_txdma_ops, +#else + .ops = &g_uart_ops, +#endif + .priv = &g_usart3priv, + }, + + .irq = AT32_IRQ_USART3, + .parity = CONFIG_USART3_PARITY, + .bits = CONFIG_USART3_BITS, + .stopbits2 = CONFIG_USART3_2STOP, + .baud = CONFIG_USART3_BAUD, + .apbclock = AT32_PCLK1_FREQUENCY, + .usartbase = AT32_USART3_BASE, + .tx_gpio = GPIO_USART3_TX, + .rx_gpio = GPIO_USART3_RX, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_USART3_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_USART3_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_USART3_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_USART3_RTS, +#endif +#ifdef CONFIG_USART3_TXDMA + .txdma_channel = DMAMUX_USART3_TX, +#endif +#ifdef CONFIG_USART3_RXDMA + .rxdma_channel = DMAMUX_USART3_RX, + .rxfifo = g_usart3rxfifo, +#endif + +#ifdef CONFIG_USART3_RS485 + .rs485_dir_gpio = GPIO_USART3_RS485_DIR, +# if (CONFIG_USART3_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif +}; +#endif + +/* This describes the state of the AT32 UART4 port. */ + +#ifdef CONFIG_AT32_UART4_SERIALDRIVER +static struct up_dev_s g_uart4priv = +{ + .dev = + { +#if CONSOLE_UART == 4 + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_UART4_RXBUFSIZE, + .buffer = g_uart4rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART4_TXBUFSIZE, + .buffer = g_uart4txbuffer, + }, +#if defined(CONFIG_UART4_RXDMA) && defined(CONFIG_UART4_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_UART4_RXDMA) && !defined(CONFIG_UART4_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_UART4_RXDMA) && defined(CONFIG_UART4_TXDMA) + .ops = &g_uart_txdma_ops, +#else + .ops = &g_uart_ops, +#endif + .priv = &g_uart4priv, + }, + + .irq = AT32_IRQ_UART4, + .parity = CONFIG_UART4_PARITY, + .bits = CONFIG_UART4_BITS, + .stopbits2 = CONFIG_UART4_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_UART4_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_UART4_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_UART4_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_UART4_RTS, +#endif + .baud = CONFIG_UART4_BAUD, + .apbclock = AT32_PCLK1_FREQUENCY, + .usartbase = AT32_UART4_BASE, + .tx_gpio = GPIO_UART4_TX, + .rx_gpio = GPIO_UART4_RX, +#ifdef CONFIG_UART4_TXDMA + .txdma_channel = DMAMUX_UART4_TX, +#endif +#ifdef CONFIG_UART4_RXDMA + .rxdma_channel = DMAMUX_UART4_RX, + .rxfifo = g_uart4rxfifo, +#endif + +#ifdef CONFIG_UART4_RS485 + .rs485_dir_gpio = GPIO_UART4_RS485_DIR, +# if (CONFIG_UART4_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif +}; +#endif + +/* This describes the state of the AT32 UART5 port. */ + +#ifdef CONFIG_AT32_UART5_SERIALDRIVER +static struct up_dev_s g_uart5priv = +{ + .dev = + { +#if CONSOLE_UART == 5 + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_UART5_RXBUFSIZE, + .buffer = g_uart5rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART5_TXBUFSIZE, + .buffer = g_uart5txbuffer, + }, +#if defined(CONFIG_UART5_RXDMA) && defined(CONFIG_UART5_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_UART5_RXDMA) && !defined(CONFIG_UART5_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_UART5_RXDMA) && defined(CONFIG_UART5_TXDMA) + .ops = &g_uart_txdma_ops, +#else + .ops = &g_uart_ops, +#endif + .priv = &g_uart5priv, + }, + + .irq = AT32_IRQ_UART5, + .parity = CONFIG_UART5_PARITY, + .bits = CONFIG_UART5_BITS, + .stopbits2 = CONFIG_UART5_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_UART5_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_UART5_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_UART5_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_UART5_RTS, +#endif + .baud = CONFIG_UART5_BAUD, + .apbclock = AT32_PCLK1_FREQUENCY, + .usartbase = AT32_UART5_BASE, + .tx_gpio = GPIO_UART5_TX, + .rx_gpio = GPIO_UART5_RX, +#ifdef CONFIG_UART5_TXDMA + .txdma_channel = DMAMUX_UART5_TX, +#endif +#ifdef CONFIG_UART5_RXDMA + .rxdma_channel = DMAMUX_UART5_RX, + .rxfifo = g_uart5rxfifo, +#endif + +#ifdef CONFIG_UART5_RS485 + .rs485_dir_gpio = GPIO_UART5_RS485_DIR, +# if (CONFIG_UART5_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif +}; +#endif + +/* This describes the state of the AT32 USART6 port. */ + +#ifdef CONFIG_AT32_USART6_SERIALDRIVER +static struct up_dev_s g_usart6priv = +{ + .dev = + { +#if CONSOLE_UART == 6 + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_USART6_RXBUFSIZE, + .buffer = g_usart6rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART6_TXBUFSIZE, + .buffer = g_usart6txbuffer, + }, +#if defined(CONFIG_USART6_RXDMA) && defined(CONFIG_USART6_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_USART6_RXDMA) && !defined(CONFIG_USART6_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_USART6_RXDMA) && defined(CONFIG_USART6_TXDMA) + .ops = &g_uart_txdma_ops, +#else + .ops = &g_uart_ops, +#endif + .priv = &g_usart6priv, + }, + + .irq = AT32_IRQ_USART6, + .parity = CONFIG_USART6_PARITY, + .bits = CONFIG_USART6_BITS, + .stopbits2 = CONFIG_USART6_2STOP, + .baud = CONFIG_USART6_BAUD, + .apbclock = AT32_PCLK2_FREQUENCY, + .usartbase = AT32_USART6_BASE, + .tx_gpio = GPIO_USART6_TX, + .rx_gpio = GPIO_USART6_RX, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_USART6_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_USART6_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_USART6_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_USART6_RTS, +#endif +#ifdef CONFIG_USART6_TXDMA + .txdma_channel = DMAMUX_USART6_TX, +#endif +#ifdef CONFIG_USART6_RXDMA + .rxdma_channel = DMAMUX_USART6_RX, + .rxfifo = g_usart6rxfifo, +#endif + +#ifdef CONFIG_USART6_RS485 + .rs485_dir_gpio = GPIO_USART6_RS485_DIR, +# if (CONFIG_USART6_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif +}; +#endif + +/* This describes the state of the AT32 UART7 port. */ + +#ifdef CONFIG_AT32_UART7_SERIALDRIVER +static struct up_dev_s g_uart7priv = +{ + .dev = + { +#if CONSOLE_UART == 7 + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_UART7_RXBUFSIZE, + .buffer = g_uart7rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART7_TXBUFSIZE, + .buffer = g_uart7txbuffer, + }, +#if defined(CONFIG_UART7_RXDMA) && defined(CONFIG_UART7_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_UART7_RXDMA) && !defined(CONFIG_UART7_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_UART7_RXDMA) && defined(CONFIG_UART7_TXDMA) + .ops = &g_uart_txdma_ops, +#else + .ops = &g_uart_ops, +#endif + .priv = &g_uart7priv, + }, + + .irq = AT32_IRQ_UART7, + .parity = CONFIG_UART7_PARITY, + .bits = CONFIG_UART7_BITS, + .stopbits2 = CONFIG_UART7_2STOP, + .baud = CONFIG_UART7_BAUD, + .apbclock = AT32_PCLK1_FREQUENCY, + .usartbase = AT32_UART7_BASE, + .tx_gpio = GPIO_UART7_TX, + .rx_gpio = GPIO_UART7_RX, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_UART7_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_UART7_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_UART7_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_UART7_RTS, +#endif +#ifdef CONFIG_UART7_TXDMA + .txdma_channel = DMAMUX_UART7_TX, +#endif +#ifdef CONFIG_UART7_RXDMA + .rxdma_channel = DMAMUX_UART7_RX, + .rxfifo = g_uart7rxfifo, +#endif + +#ifdef CONFIG_UART7_RS485 + .rs485_dir_gpio = GPIO_UART7_RS485_DIR, +# if (CONFIG_UART7_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif +}; +#endif + +/* This describes the state of the AT32 UART8 port. */ + +#ifdef CONFIG_AT32_UART8_SERIALDRIVER +static struct up_dev_s g_uart8priv = +{ + .dev = + { +#if CONSOLE_UART == 8 + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_UART8_RXBUFSIZE, + .buffer = g_uart8rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART8_TXBUFSIZE, + .buffer = g_uart8txbuffer, + }, +#if defined(CONFIG_UART8_RXDMA) && defined(CONFIG_UART8_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_UART8_RXDMA) && !defined(CONFIG_UART8_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_UART8_RXDMA) && defined(CONFIG_UART8_TXDMA) + .ops = &g_uart_txdma_ops, +#else + .ops = &g_uart_ops, +#endif + .priv = &g_uart8priv, + }, + + .irq = AT32_IRQ_UART8, + .parity = CONFIG_UART8_PARITY, + .bits = CONFIG_UART8_BITS, + .stopbits2 = CONFIG_UART8_2STOP, + .baud = CONFIG_UART8_BAUD, + .apbclock = AT32_PCLK1_FREQUENCY, + .usartbase = AT32_UART8_BASE, + .tx_gpio = GPIO_UART8_TX, + .rx_gpio = GPIO_UART8_RX, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_UART8_OFLOWCONTROL) + .oflow = true, + .cts_gpio = GPIO_UART8_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_UART8_IFLOWCONTROL) + .iflow = true, + .rts_gpio = GPIO_UART8_RTS, +#endif +#ifdef CONFIG_UART8_TXDMA + .txdma_channel = DMAMUX_UART8_TX, +#endif +#ifdef CONFIG_UART8_RXDMA + .rxdma_channel = DMAMUX_UART8_RX, + .rxfifo = g_uart8rxfifo, +#endif + +#ifdef CONFIG_UART8_RS485 + .rs485_dir_gpio = GPIO_UART8_RS485_DIR, +# if (CONFIG_UART8_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif +}; +#endif + +/* This table lets us iterate over the configured USARTs */ + +static struct up_dev_s * const g_uart_devs[AT32_NUSART] = +{ +#ifdef CONFIG_AT32_USART1_SERIALDRIVER + [0] = &g_usart1priv, +#endif +#ifdef CONFIG_AT32_USART2_SERIALDRIVER + [1] = &g_usart2priv, +#endif +#ifdef CONFIG_AT32_USART3_SERIALDRIVER + [2] = &g_usart3priv, +#endif +#ifdef CONFIG_AT32_UART4_SERIALDRIVER + [3] = &g_uart4priv, +#endif +#ifdef CONFIG_AT32_UART5_SERIALDRIVER + [4] = &g_uart5priv, +#endif +#ifdef CONFIG_AT32_USART6_SERIALDRIVER + [5] = &g_usart6priv, +#endif +#ifdef CONFIG_AT32_UART7_SERIALDRIVER + [6] = &g_uart7priv, +#endif +#ifdef CONFIG_AT32_UART8_SERIALDRIVER + [7] = &g_uart8priv, +#endif +}; + +#ifdef CONFIG_PM +static struct pm_callback_s g_serialcb = +{ + .notify = up_pm_notify, + .prepare = up_pm_prepare, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_serialin + ****************************************************************************/ + +static inline uint32_t up_serialin(struct up_dev_s *priv, int offset) +{ + return getreg32(priv->usartbase + offset); +} + +/**************************************************************************** + * Name: up_serialout + ****************************************************************************/ + +static inline void up_serialout(struct up_dev_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->usartbase + offset); +} + +/**************************************************************************** + * Name: up_setusartint + ****************************************************************************/ + +static inline void up_setusartint(struct up_dev_s *priv, uint16_t ie) +{ + uint32_t cr; + + /* Save the interrupt mask */ + + priv->ie = ie; + + /* And restore the interrupt state (see the interrupt enable/usage + * table above) + */ + + cr = up_serialin(priv, AT32_USART_CTRL1_OFFSET); + cr &= ~(USART_CR1_USED_INTS); + cr |= (ie & (USART_CR1_USED_INTS)); + up_serialout(priv, AT32_USART_CTRL1_OFFSET, cr); + + cr = up_serialin(priv, AT32_USART_CTRL3_OFFSET); + cr &= ~USART_CTRL3_ERRIEN; + cr |= (ie & USART_CTRL3_ERRIEN); + up_serialout(priv, AT32_USART_CTRL3_OFFSET, cr); +} + +/**************************************************************************** + * Name: up_restoreusartint + ****************************************************************************/ + +static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + up_setusartint(priv, ie); + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: up_disableusartint + ****************************************************************************/ + +static void up_disableusartint(struct up_dev_s *priv, uint16_t *ie) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + if (ie) + { + uint32_t cr1; + uint32_t cr3; + + /* USART interrupts: + * + * Enable Status Meaning Usage + * ------------------ --------------- ------------------- ---------- + * USART_CR1_IDLEIE USART_SR_IDLE Idle Line Detected (not used) + * USART_CTRL1_RDBFIEN USART_STS_RDBF Rx Data Ready + * " " USART_STS_ROERR Overrun Error Detected + * USART_CTRL1_TDCIEN USART_STS_TDC Transmit Complete (RS-485) + * USART_CTRL1_TDBEIEN USART_STS_TDBE Tx Data Register Empty + * USART_CTRL1_PERRIEN USART_SR_PE Parity Error + * + * USART_CTRL2_BFIEN USART_SR_LBD Break Flag (not used) + * USART_CTRL3_ERRIEN USART_STS_FERR Framing Error + * " " USART_STS_NERR Noise Error + * " " USART_STS_ROERR Overrun Error Detected + * USART_CTRL3_CTSCFIEN USART_SR_CTS CTS flag (not used) + */ + + cr1 = up_serialin(priv, AT32_USART_CTRL1_OFFSET); + cr3 = up_serialin(priv, AT32_USART_CTRL3_OFFSET); + + /* Return the current interrupt mask value for the used interrupts. + * Notice that this depends on the fact that none of the used interrupt + * enable bits overlap. This logic would fail if we needed the break + * interrupt! + */ + + *ie = (cr1 & (USART_CR1_USED_INTS)) | (cr3 & USART_CTRL3_ERRIEN); + } + + /* Disable all interrupts */ + + up_setusartint(priv, 0); + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: up_dma_nextrx + * + * Description: + * Returns the index into the RX FIFO where the DMA will place the next + * byte that it receives. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static int up_dma_nextrx(struct up_dev_s *priv) +{ + size_t dmaresidual; + + dmaresidual = at32_dmaresidual(priv->rxdma); + + return (RXDMA_BUFFER_SIZE - (int)dmaresidual); +} +#endif + +/**************************************************************************** + * Name: up_set_format + * + * Description: + * Set the serial line format and speed. + * + ****************************************************************************/ + +#ifndef CONFIG_SUPPRESS_UART_CONFIG +static void up_set_format(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + uint32_t regval; + uint32_t brr; + + /* Calibrate baudrate div */ + + regval = (priv->apbclock * 10 / priv->baud); + brr = ((regval % 10) < 5) ? (regval / 10) : (regval / 10 + 1); + + up_serialout(priv, AT32_USART_BAUDR_OFFSET, brr); + + /* Load CR1 */ + + regval = up_serialin(priv, AT32_USART_CTRL1_OFFSET); + + /* Configure parity mode */ + + regval &= ~(USART_CTRL1_PEN | USART_CTRL1_PSEL | \ + USART_CTRL1_DBN0 | USART_CTRL1_DBN1); + + if (priv->parity == 1) /* Odd parity */ + { + regval |= (USART_CTRL1_PEN | USART_CTRL1_PSEL); + } + else if (priv->parity == 2) /* Even parity */ + { + regval |= USART_CTRL1_PEN; + } + + /* Configure word length (parity uses one of configured bits) + * + * Default: 1 start, 8 data (no parity), n stop, OR + * 1 start, 7 data + parity, n stop + */ + + if (priv->bits == 9 || (priv->bits == 8 && priv->parity != 0)) + { + /* Select: 1 start, 8 data + parity, n stop, OR + * 1 start, 9 data (no parity), n stop. + */ + + regval |= USART_CTRL1_DBN0; + } + + up_serialout(priv, AT32_USART_CTRL1_OFFSET, regval); + + /* Configure STOP bits */ + + regval = up_serialin(priv, AT32_USART_CTRL2_OFFSET); + regval &= ~(USART_CTRL2_STOPBN_MASK); + + if (priv->stopbits2) + { + regval |= USART_CTRL2_STOPBN_20; + } + + up_serialout(priv, AT32_USART_CTRL2_OFFSET, regval); + + /* Configure hardware flow control */ + + regval = up_serialin(priv, AT32_USART_CTRL3_OFFSET); + regval &= ~(USART_CTRL3_CTSEN | USART_CTRL3_RTSEN); + +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && \ + !defined(CONFIG_AT32_FLOWCONTROL_BROKEN) + if (priv->iflow && (priv->rts_gpio != 0)) + { + regval |= USART_CTRL3_RTSEN; + } +#endif + +#ifdef CONFIG_SERIAL_OFLOWCONTROL + if (priv->oflow && (priv->cts_gpio != 0)) + { + regval |= USART_CTRL3_CTSEN; + } +#endif + + up_serialout(priv, AT32_USART_CTRL3_OFFSET, regval); +} +#endif /* CONFIG_SUPPRESS_UART_CONFIG */ + +/**************************************************************************** + * Name: up_set_apb_clock + * + * Description: + * Enable or disable APB clock for the USART peripheral + * + * Input Parameters: + * dev - A reference to the UART driver state structure + * on - Enable clock if 'on' is 'true' and disable if 'false' + * + ****************************************************************************/ + +static void up_set_apb_clock(struct uart_dev_s *dev, bool on) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + uint32_t rcc_en; + uint32_t regaddr; + + /* Determine which USART to configure */ + + switch (priv->usartbase) + { + default: + return; +#ifdef CONFIG_AT32_USART1_SERIALDRIVER + case AT32_USART1_BASE: + rcc_en = CRM_APB2EN_USART1EN; + regaddr = AT32_CRM_APB2EN; + break; +#endif +#ifdef CONFIG_AT32_USART2_SERIALDRIVER + case AT32_USART2_BASE: + rcc_en = CRM_APB1EN_USART2EN; + regaddr = AT32_CRM_APB1EN; + break; +#endif +#ifdef CONFIG_AT32_USART3_SERIALDRIVER + case AT32_USART3_BASE: + rcc_en = CRM_APB1EN_USART3EN; + regaddr = AT32_CRM_APB1EN; + break; +#endif +#ifdef CONFIG_AT32_UART4_SERIALDRIVER + case AT32_UART4_BASE: + rcc_en = CRM_APB1EN_UART4EN; + regaddr = AT32_CRM_APB1EN; + break; +#endif +#ifdef CONFIG_AT32_UART5_SERIALDRIVER + case AT32_UART5_BASE: + rcc_en = CRM_APB1EN_UART5EN; + regaddr = AT32_CRM_APB1EN; + break; +#endif +#ifdef CONFIG_AT32_USART6_SERIALDRIVER + case AT32_USART6_BASE: + rcc_en = CRM_APB2EN_USART6EN; + regaddr = AT32_CRM_APB2EN; + break; +#endif +#ifdef CONFIG_AT32_UART7_SERIALDRIVER + case AT32_UART7_BASE: + rcc_en = CRM_APB1EN_UART7EN; + regaddr = AT32_CRM_APB1EN; + break; +#endif +#ifdef CONFIG_AT32_UART8_SERIALDRIVER + case AT32_UART8_BASE: + rcc_en = CRM_APB1EN_UART8EN; + regaddr = AT32_CRM_APB1EN; + break; +#endif + } + + /* Enable/disable APB 1/2 clock for USART */ + + if (on) + { + modifyreg32(regaddr, 0, rcc_en); + } + else + { + modifyreg32(regaddr, rcc_en, 0); + } +} + +/**************************************************************************** + * Name: up_setup + * + * Description: + * Configure the USART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +static int up_setup(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + +#ifndef CONFIG_SUPPRESS_UART_CONFIG + uint32_t regval; + + /* Note: The logic here depends on the fact that that the USART module + * was enabled in at32_lowsetup(). + */ + + /* Enable USART APB1/2 clock */ + + up_set_apb_clock(dev, true); + + /* Configure pins for USART use */ + + at32_configgpio(priv->tx_gpio); + at32_configgpio(priv->rx_gpio); + +#ifdef CONFIG_SERIAL_OFLOWCONTROL + if (priv->cts_gpio != 0) + { + at32_configgpio(priv->cts_gpio); + } +#endif + +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->rts_gpio != 0) + { + uint32_t config = priv->rts_gpio; + +#ifdef CONFIG_AT32_FLOWCONTROL_BROKEN + /* Instead of letting hw manage this pin, we will bitbang */ + + config = (config & ~GPIO_MODE_MASK) | GPIO_OUTPUT; +#endif + at32_configgpio(config); + } +#endif + +#ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + at32_configgpio(priv->rs485_dir_gpio); + at32_gpiowrite(priv->rs485_dir_gpio, !priv->rs485_dir_polarity); + } +#endif + + /* Configure CR2 + * Clear STOP, CLKEN, CPOL, CPHA, LBCL, and interrupt enable bits + */ + + regval = up_serialin(priv, AT32_USART_CTRL2_OFFSET); + regval &= ~(USART_CTRL2_STOPBN_MASK | USART_CTRL2_CLKEN | \ + USART_CTRL2_CLKPOL | USART_CTRL2_CLKPHA | \ + USART_CTRL2_LBCP | USART_CTRL2_BFIEN); + + /* Configure STOP bits */ + + if (priv->stopbits2) + { + regval |= USART_CTRL2_STOPBN_20; + } + + up_serialout(priv, AT32_USART_CTRL2_OFFSET, regval); + + /* Configure CR1 + * Clear TE, REm and all interrupt enable bits + */ + + regval = up_serialin(priv, AT32_USART_CTRL1_OFFSET); + regval &= ~(USART_CTRL1_TEN | USART_CTRL1_REN | USART_CTRL1_ALLINTS); + + up_serialout(priv, AT32_USART_CTRL1_OFFSET, regval); + + /* Configure CR3 + * Clear CTSE, RTSE, and all interrupt enable bits + */ + + regval = up_serialin(priv, AT32_USART_CTRL3_OFFSET); + regval &= ~(USART_CTRL3_CTSCFIEN | USART_CTRL3_CTSEN | USART_CTRL3_RTSEN | + USART_CTRL3_ERRIEN); + + up_serialout(priv, AT32_USART_CTRL3_OFFSET, regval); + + /* Configure the USART line format and speed. */ + + up_set_format(dev); + + /* Enable Rx, Tx, and the USART */ + + regval = up_serialin(priv, AT32_USART_CTRL1_OFFSET); + regval |= (USART_CTRL1_UEN | USART_CTRL1_TEN | USART_CTRL1_REN); + up_serialout(priv, AT32_USART_CTRL1_OFFSET, regval); + +#endif /* CONFIG_SUPPRESS_UART_CONFIG */ + + /* Set up the cached interrupt enables value */ + + priv->ie = 0; + + /* Mark device as initialized. */ + + priv->initialized = true; + + return OK; +} + +/**************************************************************************** + * Name: up_dma_setup + * + * Description: + * Configure the USART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int up_dma_setup(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + int result; + + /* Do the basic UART setup first, unless we are the console */ + + if (!dev->isconsole) + { + result = up_setup(dev); + if (result != OK) + { + return result; + } + } + +#if defined(SERIAL_HAVE_TXDMA) + /* Acquire the Tx DMA channel. This should always succeed. */ + + if (priv->txdma_channel != INVALID_SERIAL_DMA_CHANNEL) + { + priv->txdma = at32_dmachannel(priv->txdma_channel); + + /* Enable receive Tx DMA for the UART */ + + modifyreg32(priv->usartbase + AT32_USART_CTRL3_OFFSET, + 0, USART_CTRL3_DMATEN); + } +#endif + +#if defined(SERIAL_HAVE_RXDMA) + /* Acquire the DMA channel. This should always succeed. */ + + if (priv->rxdma_channel != INVALID_SERIAL_DMA_CHANNEL) + { + priv->rxdma = at32_dmachannel(priv->rxdma_channel); + + /* Configure for circular DMA reception into the RX fifo */ + + at32_dmasetup(priv->rxdma, + priv->usartbase + AT32_USART_RDR_OFFSET, + (uint32_t)priv->rxfifo, + RXDMA_BUFFER_SIZE, + SERIAL_RXDMA_CONTROL_WORD); + + /* Reset our DMA shadow pointer to match the address just + * programmed above. + */ + + priv->rxdmanext = 0; + + /* Enable receive Rx DMA for the UART */ + + modifyreg32(priv->usartbase + AT32_USART_CTRL3_OFFSET, + 0, USART_CTRL3_DMAREN); + + /* Start the DMA channel, and arrange for callbacks at the half and + * full points in the FIFO. This ensures that we have half a FIFO + * worth of time to claim bytes before they are overwritten. + */ + + at32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, true); + } +#endif + + return OK; +} +#endif + +/**************************************************************************** + * Name: up_shutdown + * + * Description: + * Disable the USART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +static void up_shutdown(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + uint32_t regval; + + /* Mark device as uninitialized. */ + + priv->initialized = false; + + /* Disable all interrupts */ + + up_disableusartint(priv, NULL); + + /* Disable USART APB1/2 clock */ + + up_set_apb_clock(dev, false); + + /* Disable Rx, Tx, and the UART */ + + regval = up_serialin(priv, AT32_USART_CTRL1_OFFSET); + regval &= ~(USART_CTRL1_UEN | USART_CTRL1_TEN | USART_CTRL1_REN); + up_serialout(priv, AT32_USART_CTRL1_OFFSET, regval); + + /* Release pins. "If the serial-attached device is powered down, the TX + * pin causes back-powering, potentially confusing the device to the point + * of complete lock-up." + * + * REVISIT: Is unconfiguring the pins appropriate for all device? If not, + * then this may need to be a configuration option. + */ + + at32_unconfiggpio(priv->tx_gpio); + at32_unconfiggpio(priv->rx_gpio); + +#ifdef CONFIG_SERIAL_OFLOWCONTROL + if (priv->cts_gpio != 0) + { + at32_unconfiggpio(priv->cts_gpio); + } +#endif + +#ifdef CONFIG_SERIAL_IFLOWCONTROL + if (priv->rts_gpio != 0) + { + at32_unconfiggpio(priv->rts_gpio); + } +#endif + +#ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + at32_unconfiggpio(priv->rs485_dir_gpio); + } +#endif +} + +/**************************************************************************** + * Name: up_dma_shutdown + * + * Description: + * Disable the USART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static void up_dma_shutdown(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + + /* Perform the normal UART shutdown */ + + up_shutdown(dev); + +#if defined(SERIAL_HAVE_RXDMA) + /* Stop the RX DMA channel */ + + if (priv->rxdma_channel != INVALID_SERIAL_DMA_CHANNEL) + { + at32_dmastop(priv->rxdma); + + /* Release the RX DMA channel */ + + at32_dmafree(priv->rxdma); + priv->rxdma = NULL; + } +#endif + +#if defined(SERIAL_HAVE_TXDMA) + /* Stop the TX DMA channel */ + + if (priv->txdma_channel != INVALID_SERIAL_DMA_CHANNEL) + { + at32_dmastop(priv->txdma); + + /* Release the TX DMA channel */ + + at32_dmafree(priv->txdma); + priv->txdma = NULL; + } +#endif +} +#endif + +/**************************************************************************** + * Name: up_attach + * + * Description: + * Configure the USART to operation in interrupt driven mode. This method + * is called when the serial port is opened. Normally, this is just after + * the setup() method is called, however, the serial console may operate + * in a non-interrupt driven mode during the boot phase. + * + * RX and TX interrupts are not enabled when by the attach method (unless + * the hardware supports multiple levels of interrupt enabling). The RX + * and TX interrupts are not enabled until the txint() and rxint() methods + * are called. + * + ****************************************************************************/ + +static int up_attach(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + int ret; + + /* Attach and enable the IRQ */ + + ret = irq_attach(priv->irq, up_interrupt, priv); + if (ret == OK) + { + /* Enable the interrupt (RX and TX interrupts are still disabled + * in the USART + */ + + up_enable_irq(priv->irq); + } + + return ret; +} + +/**************************************************************************** + * Name: up_detach + * + * Description: + * Detach USART interrupts. This method is called when the serial port is + * closed normally just before the shutdown method is called. The + * exception is the serial console which is never shutdown. + * + ****************************************************************************/ + +static void up_detach(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + up_disable_irq(priv->irq); + irq_detach(priv->irq); +} + +/**************************************************************************** + * Name: up_interrupt + * + * Description: + * This is the UART interrupt handler. It will be invoked when an + * interrupt is received on the 'irq'. It should call uart_xmitchars or + * uart_recvchars to perform the appropriate data transfers. The + * interrupt handling logic must be able to map the 'arg' to the + * appropriate uart_dev_s structure in order to call these functions. + * + ****************************************************************************/ + +static int up_interrupt(int irq, void *context, void *arg) +{ + struct up_dev_s *priv = (struct up_dev_s *)arg; + int passes; + bool handled; + + DEBUGASSERT(priv != NULL); + + /* Report serial activity to the power management logic */ + +#if defined(CONFIG_PM) && CONFIG_AT32_PM_SERIAL_ACTIVITY > 0 + pm_activity(PM_IDLE_DOMAIN, CONFIG_AT32_PM_SERIAL_ACTIVITY); +#endif + + /* Loop until there are no characters to be transferred or, + * until we have been looping for a long time. + */ + + handled = true; + for (passes = 0; passes < 256 && handled; passes++) + { + handled = false; + + /* Get the masked USART status word. */ + + priv->sr = up_serialin(priv, AT32_USART_STS_OFFSET); + + /* USART interrupts: + * + * Enable Status Meaning Usage + * ------------------ --------------- ------------------- ---------- + * USART_CR1_IDLEIE USART_SR_IDLE Idle Line Detected (not used) + * USART_CTRL1_RDBFIEN USART_STS_RDBF Rx Data Ready + * " " USART_STS_ROERR Overrun Error Detected + * USART_CTRL1_TDCIEN USART_STS_TDC Tx Complete (RS-485) + * USART_CTRL1_TDBEIEN USART_STS_TDBE Tx Data Register Empty + * USART_CTRL1_PERRIEN USART_SR_PE Parity Error + * + * USART_CTRL2_BFIEN USART_SR_LBD Break Flag (not used) + * USART_CTRL3_ERRIEN USART_STS_FERR Framing Error + * " " USART_STS_NERR Noise Error + * " " USART_STS_ROERR Overrun Error Detected + * USART_CTRL3_CTSCFIEN USART_SR_CTS CTS flag (not used) + * + * NOTE: Some of these status bits must be cleared by explicitly + * writing zero to the SR register: USART_SR_CTS, USART_SR_LBD. Note of + * those are currently being used. + */ + +#ifdef HAVE_RS485 + /* Transmission of whole buffer is over - TC is set, TXEIE is cleared. + * Note - this should be first, to have the most recent TC bit value + * from SR register - sending data affects TC, but without refresh we + * will not know that... + */ + + if (((priv->sr & USART_STS_TDC) != 0) && + ((priv->ie & USART_CTRL1_TDCIEN) != 0) && + ((priv->ie & USART_CTRL1_TDBEIEN) == 0)) + { + at32_gpiowrite(priv->rs485_dir_gpio, !priv->rs485_dir_polarity); + up_restoreusartint(priv, priv->ie & ~USART_CTRL1_TDCIEN); + } +#endif + + /* Handle incoming, receive bytes. */ + + if (((priv->sr & USART_STS_RDBF) != 0) && + ((priv->ie & USART_CTRL1_RDBFIEN) != 0)) + { + /* Received data ready... process incoming bytes. NOTE the check + * for RXNEIE: We cannot call uart_recvchards of RX interrupts are + * disabled. + */ + + uart_recvchars(&priv->dev); + handled = true; + } + + /* We may still have to read from the DR register to clear any pending + * error conditions. + */ + + else if ((priv->sr & (USART_STS_ROERR | \ + USART_STS_NERR | USART_STS_FERR)) != 0) + { + /* If an error occurs, read from DR to clear the error (data has + * been lost). If ORE is set along with RXNE then it tells you + * that the byte *after* the one in the data register has been + * lost, but the data register value is correct. That case will + * be handled above if interrupts are enabled. Otherwise, that + * good byte will be lost. + */ + + up_serialin(priv, AT32_USART_DT_OFFSET); + } + + /* Handle outgoing, transmit bytes */ + + if (((priv->sr & USART_STS_TDBE) != 0) && + ((priv->ie & USART_CTRL1_TDBEIEN) != 0)) + { + /* Transmit data register empty ... process outgoing bytes */ + + uart_xmitchars(&priv->dev); + handled = true; + } + } + + return OK; +} + +/**************************************************************************** + * Name: up_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + ****************************************************************************/ + +static int up_ioctl(struct file *filep, int cmd, unsigned long arg) +{ +#if defined(CONFIG_SERIAL_TERMIOS) || defined(CONFIG_SERIAL_TIOCSERGSTRUCT) \ + || defined(CONFIG_AT32_SERIALBRK_BSDCOMPAT) + struct inode *inode = filep->f_inode; + struct uart_dev_s *dev = inode->i_private; +#endif +#if defined(CONFIG_SERIAL_TERMIOS) || defined(CONFIG_AT32_SERIALBRK_BSDCOMPAT) + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; +#endif + int ret = OK; + + switch (cmd) + { +#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT + case TIOCSERGSTRUCT: + { + struct up_dev_s *user = (struct up_dev_s *)arg; + if (!user) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev, sizeof(struct up_dev_s)); + } + } + break; +#endif + +#ifdef CONFIG_AT32_USART_SINGLEWIRE + case TIOCSSINGLEWIRE: + { + /* Change the TX port to be open-drain/push-pull and enable/disable + * half-duplex mode. + */ + + uint32_t cr = up_serialin(priv, AT32_USART_CTRL3_OFFSET); + + if ((arg & SER_SINGLEWIRE_ENABLED) != 0) + { + uint32_t gpio_val = (arg & SER_SINGLEWIRE_PUSHPULL) == + SER_SINGLEWIRE_PUSHPULL ? + GPIO_PUSHPULL : GPIO_OPENDRAIN; + gpio_val |= ((arg & SER_SINGLEWIRE_PULL_MASK) == + SER_SINGLEWIRE_PULLUP) ? GPIO_PULLUP + : GPIO_FLOAT; + gpio_val |= ((arg & SER_SINGLEWIRE_PULL_MASK) == + SER_SINGLEWIRE_PULLDOWN) ? GPIO_PULLDOWN + : GPIO_FLOAT; + at32_configgpio((priv->tx_gpio & ~(GPIO_PUPD_MASK | + GPIO_OPENDRAIN)) | + gpio_val); + cr |= USART_CTRL3_SLBEN; + } + else + { + at32_configgpio((priv->tx_gpio & ~(GPIO_PUPD_MASK | + GPIO_OPENDRAIN)) | + GPIO_PUSHPULL); + cr &= ~USART_CTRL3_SLBEN; + } + + up_serialout(priv, AT32_USART_CTRL3_OFFSET, cr); + } + break; +#endif + +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Note that since we only support 8/9 bit modes and + * there is no way to report 9-bit mode, we always claim 8. + */ + + termiosp->c_cflag = + ((priv->parity != 0) ? PARENB : 0) | + ((priv->parity == 1) ? PARODD : 0) | + ((priv->stopbits2) ? CSTOPB : 0) | +#ifdef CONFIG_SERIAL_OFLOWCONTROL + ((priv->oflow) ? CCTS_OFLOW : 0) | +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + ((priv->iflow) ? CRTS_IFLOW : 0) | +#endif + CS8; + + cfsetispeed(termiosp, priv->baud); + + /* TODO: CRTS_IFLOW, CCTS_OFLOW */ + } + break; + + case TCSETS: + { + struct termios *termiosp = (struct termios *)arg; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Perform some sanity checks before accepting any changes */ + + if (((termiosp->c_cflag & CSIZE) != CS8) +#ifdef CONFIG_SERIAL_OFLOWCONTROL + || ((termiosp->c_cflag & CCTS_OFLOW) && (priv->cts_gpio == 0)) +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + || ((termiosp->c_cflag & CRTS_IFLOW) && (priv->rts_gpio == 0)) +#endif + ) + { + ret = -EINVAL; + break; + } + + if (termiosp->c_cflag & PARENB) + { + priv->parity = (termiosp->c_cflag & PARODD) ? 1 : 2; + } + else + { + priv->parity = 0; + } + + priv->stopbits2 = (termiosp->c_cflag & CSTOPB) != 0; +#ifdef CONFIG_SERIAL_OFLOWCONTROL + priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; +#endif + + /* Note that since there is no way to request 9-bit mode + * and no way to support 5/6/7-bit modes, we ignore them + * all here. + */ + + /* Note that only cfgetispeed is used because we have knowledge + * that only one speed is supported. + */ + + priv->baud = cfgetispeed(termiosp); + + /* Effect the changes immediately - note that we do not implement + * TCSADRAIN / TCSAFLUSH + */ + + up_set_format(dev); + } + break; +#endif /* CONFIG_SERIAL_TERMIOS */ + +#ifdef CONFIG_AT32_USART_BREAKS +# ifdef CONFIG_AT32_SERIALBRK_BSDCOMPAT + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + { + irqstate_t flags; + uint32_t tx_break; + + flags = enter_critical_section(); + + /* Disable any further tx activity */ + + priv->ie |= USART_CR1_IE_BREAK_INPROGRESS; + + up_txint(dev, false); + + /* Configure TX as a GPIO output pin and Send a break signal */ + + tx_break = GPIO_OUTPUT | (~(GPIO_MODE_MASK | GPIO_OUTPUT_SET) & + priv->tx_gpio); + at32_configgpio(tx_break); + + leave_critical_section(flags); + } + break; + + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + { + irqstate_t flags; + + flags = enter_critical_section(); + + /* Configure TX back to U(S)ART */ + + at32_configgpio(priv->tx_gpio); + + priv->ie &= ~USART_CR1_IE_BREAK_INPROGRESS; + + /* Enable further tx activity */ + + up_txint(dev, true); + + leave_critical_section(flags); + } + break; +# else + case TIOCSBRK: /* No BSD compatibility: Turn break on for M bit times */ + { + uint32_t cr1; + irqstate_t flags; + + flags = enter_critical_section(); + cr1 = up_serialin(priv, AT32_USART_CTRL1_OFFSET); + up_serialout(priv, AT32_USART_CTRL1_OFFSET, cr1 | USART_CR1_SBK); + leave_critical_section(flags); + } + break; + + case TIOCCBRK: /* No BSD compatibility: May turn off break too soon */ + { + uint32_t cr1; + irqstate_t flags; + + flags = enter_critical_section(); + cr1 = up_serialin(priv, AT32_USART_CTRL1_OFFSET); + up_serialout(priv, AT32_USART_CTRL1_OFFSET, cr1 & ~USART_CR1_SBK); + leave_critical_section(flags); + } + break; +# endif +#endif + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: up_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the USART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_TXDMA_OPS) || defined(SERIAL_HAVE_NODMA_OPS) +static int up_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + uint32_t rdr; + + /* Get the Rx byte */ + + rdr = up_serialin(priv, AT32_USART_DT_OFFSET); + + /* Get the Rx byte plux error information. Return those in status */ + + *status = priv->sr << 16 | rdr; + priv->sr = 0; + + /* Then return the actual received byte */ + + return rdr & 0xff; +} +#endif + +/**************************************************************************** + * Name: up_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_TXDMA_OPS) || defined(SERIAL_HAVE_NODMA_OPS) +static void up_rxint(struct uart_dev_s *dev, bool enable) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + irqstate_t flags; + uint16_t ie; + + /* USART receive interrupts: + * + * Enable Status Meaning Usage + * ------------------ --------------- ---------------------- ---------- + * USART_CR1_IDLEIE USART_SR_IDLE Idle Line Detected (not used) + * USART_CTRL1_RDBFIEN USART_STS_RDBF Rx Data Ready to be Read + * " " USART_STS_ROERR Overrun Error Detected + * USART_CTRL1_PERRIEN USART_SR_PE Parity Error + * + * USART_CTRL2_BFIEN USART_SR_LBD Break Flag (not used) + * USART_CTRL3_ERRIEN USART_STS_FERR Framing Error + * " " USART_STS_NERR Noise Error + * " " USART_STS_ROERR Overrun Error Detected + */ + + flags = enter_critical_section(); + ie = priv->ie; + if (enable) + { + /* Receive an interrupt when their is anything in the Rx data register + * (or an Rx timeout occurs). + */ + +#ifndef CONFIG_SUPPRESS_SERIAL_INTS +#ifdef CONFIG_USART_ERRINTS + ie |= (USART_CTRL1_RDBFIEN | USART_CTRL1_PERRIEN | USART_CTRL3_ERRIEN); +#else + ie |= USART_CTRL1_RDBFIEN; +#endif +#endif + } + else + { + ie &= ~(USART_CTRL1_RDBFIEN | USART_CTRL1_PERRIEN | \ + USART_CTRL3_ERRIEN); + } + + /* Then set the new interrupt state */ + + up_restoreusartint(priv, ie); + leave_critical_section(flags); +} +#endif + +/**************************************************************************** + * Name: up_rxavailable + * + * Description: + * Return true if the receive register is not empty + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_TXDMA_OPS) || defined(SERIAL_HAVE_NODMA_OPS) +static bool up_rxavailable(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + return ((up_serialin(priv, AT32_USART_STS_OFFSET) & USART_STS_RDBF) != 0); +} +#endif + +/**************************************************************************** + * Name: up_rxflowcontrol + * + * Description: + * Called when Rx buffer is full (or exceeds configured watermark levels + * if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is defined). + * Return true if UART activated RX flow control to block more incoming + * data + * + * Input Parameters: + * dev - UART device instance + * nbuffered - the number of characters currently buffered + * (if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is + * not defined the value will be 0 for an empty buffer or the + * defined buffer size for a full buffer) + * upper - true indicates the upper watermark was crossed where + * false indicates the lower watermark has been crossed + * + * Returned Value: + * true if RX flow control activated. + * + ****************************************************************************/ + +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool up_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + +#if defined(CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS) && \ + defined(CONFIG_AT32_FLOWCONTROL_BROKEN) + if (priv->iflow && (priv->rts_gpio != 0)) + { + /* Assert/de-assert nRTS set it high resume/stop sending */ + + at32_gpiowrite(priv->rts_gpio, upper); + + if (upper) + { + /* With heavy Rx traffic, RXNE might be set and data pending. + * Returning 'true' in such case would cause RXNE left unhandled + * and causing interrupt storm. Sending end might be also be slow + * to react on nRTS, and returning 'true' here would prevent + * processing that data. + * + * Therefore, return 'false' so input data is still being processed + * until sending end reacts on nRTS signal and stops sending more. + */ + + return false; + } + + return upper; + } + +#else + if (priv->iflow) + { + /* Is the RX buffer full? */ + + if (upper) + { + /* Disable Rx interrupt to prevent more data being from + * peripheral. When hardware RTS is enabled, this will + * prevent more data from coming in. + * + * This function is only called when UART recv buffer is full, + * that is: "dev->recv.head + 1 == dev->recv.tail". + * + * Logic in "uart_read" will automatically toggle Rx interrupts + * when buffer is read empty and thus we do not have to re- + * enable Rx interrupts. + */ + + uart_disablerxint(dev); + return true; + } + + /* No.. The RX buffer is empty */ + + else + { + /* We might leave Rx interrupt disabled if full recv buffer was + * read empty. Enable Rx interrupt to make sure that more input is + * received. + */ + + uart_enablerxint(dev); + } + } +#endif + + return false; +} +#endif + +/**************************************************************************** + * Name: up_dma_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the USART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static int up_dma_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + int c = 0; + + if (up_dma_nextrx(priv) != priv->rxdmanext) + { + c = priv->rxfifo[priv->rxdmanext]; + + priv->rxdmanext++; + if (priv->rxdmanext == RXDMA_BUFFER_SIZE) + { + priv->rxdmanext = 0; + } + } + + return c; +} +#endif + +/**************************************************************************** + * Name: up_dma_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void up_dma_rxint(struct uart_dev_s *dev, bool enable) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + + /* En/disable DMA reception. + * + * Note that it is not safe to check for available bytes and immediately + * pass them to uart_recvchars as that could potentially recurse back + * to us again. Instead, bytes must wait until the next up_dma_poll or + * DMA event. + */ + + priv->rxenable = enable; +} +#endif + +/**************************************************************************** + * Name: up_dma_rxavailable + * + * Description: + * Return true if the receive register is not empty + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static bool up_dma_rxavailable(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + + /* Compare our receive pointer to the current DMA pointer, if they + * do not match, then there are bytes to be received. + */ + + return (up_dma_nextrx(priv) != priv->rxdmanext); +} +#endif + +/**************************************************************************** + * Name: up_dma_txcallback + * + * Description: + * This function clears dma buffer at complete of DMA transfer and wakes up + * threads waiting for space in buffer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void up_dma_txcallback(DMA_HANDLE handle, uint8_t status, void *arg) +{ + struct up_dev_s *priv = (struct up_dev_s *)arg; + + /* Update 'nbytes' indicating number of bytes actually transferred by DMA. + * This is important to free TX buffer space by 'uart_xmitchars_done'. + */ + + if (status & DMA_ISR_TCIF_BIT) + { + priv->dev.dmatx.nbytes += priv->dev.dmatx.length; + if (priv->dev.dmatx.nlength) + { + /* Set up DMA on next buffer */ + + at32_dmasetup(priv->txdma, + priv->usartbase + AT32_USART_DT_OFFSET, + (uint32_t) priv->dev.dmatx.nbuffer, + (size_t) priv->dev.dmatx.nlength, + SERIAL_TXDMA_CONTROL_WORD); + + /* Set length for the next completion */ + + priv->dev.dmatx.length = priv->dev.dmatx.nlength; + priv->dev.dmatx.nlength = 0; + + /* Start transmission with the callback on DMA completion */ + + at32_dmastart(priv->txdma, up_dma_txcallback, + (void *)priv, false); + + return; + } + } + else if (status & DMA_ISR_HTIF_BIT) + { + priv->dev.dmatx.nbytes += priv->dev.dmatx.length / 2; + } + + /* Adjust the pointers */ + + uart_xmitchars_done(&priv->dev); +} +#endif + +/**************************************************************************** + * Name: up_dma_txavailable + * + * Description: + * Informs DMA that Tx data is available and is ready for transfer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void up_dma_txavailable(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + + /* Only send when the DMA is idle */ + + if (at32_dmaresidual(priv->txdma) == 0) + { + uart_xmitchars_dma(dev); + } +} +#endif + +/**************************************************************************** + * Name: up_dma_send + * + * Description: + * Called (usually) from the interrupt level to start DMA transfer. + * (Re-)Configures DMA Stream updating buffer and buffer length. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void up_dma_send(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + + /* We need to stop DMA before reconfiguration */ + + at32_dmastop(priv->txdma); + + /* Reset the number sent */ + + dev->dmatx.nbytes = 0; + + /* Make use of setup function to update buffer and its length for + * next transfer + */ + + at32_dmasetup(priv->txdma, + priv->usartbase + AT32_USART_DT_OFFSET, + (uint32_t) dev->dmatx.buffer, + (size_t) dev->dmatx.length, + SERIAL_TXDMA_CONTROL_WORD); + + /* Start transmission with the callback on DMA completion */ + + at32_dmastart(priv->txdma, up_dma_txcallback, (void *)priv, false); +} +#endif + +/**************************************************************************** + * Name: up_send + * + * Description: + * This method will send one byte on the USART + * + ****************************************************************************/ + +static void up_send(struct uart_dev_s *dev, int ch) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; +#ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + at32_gpiowrite(priv->rs485_dir_gpio, priv->rs485_dir_polarity); + } +#endif + + up_serialout(priv, AT32_USART_DT_OFFSET, (uint32_t)ch); +} + +/**************************************************************************** + * Name: up_dma_txint + * + * Description: + * Call to enable or disable TX interrupts from the UART. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void up_dma_txint(struct uart_dev_s *dev, bool enable) +{ + /* Nothing to do. */ + + /* In case of DMA transfer we do not want to make use of UART interrupts. + * Instead, we use DMA interrupts that are activated once during boot + * sequence. Furthermore we can use up_dma_txcallback() to handle staff at + * half DMA transfer or after transfer completion (depending configuration, + * see at32_dmastart(...) ). + */ +} +#endif + +/**************************************************************************** + * Name: up_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA_OPS) || defined(SERIAL_HAVE_NODMA_OPS) || \ + defined(CONFIG_AT32_SERIALBRK_BSDCOMPAT) +static void up_txint(struct uart_dev_s *dev, bool enable) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + irqstate_t flags; + + /* USART transmit interrupts: + * + * Enable Status Meaning Usage + * ------------------ --------------- ----------------------- ---------- + * USART_CTRL1_TDCIEN USART_STS_TDC Tx Complete (RS-485) + * USART_CTRL1_TDBEIEN USART_STS_TDBE Tx Data Register Empty + * USART_CTRL3_CTSCFIEN USART_SR_CTS CTS flag (not used) + */ + + flags = enter_critical_section(); + if (enable) + { + /* Set to receive an interrupt when the TX data register is empty */ + +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + uint16_t ie = priv->ie | USART_CTRL1_TDBEIEN; + + /* If RS-485 is supported on this U[S]ART, then also enable the + * transmission complete interrupt. + */ + +# ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + ie |= USART_CTRL1_TDCIEN; + } +# endif + +# ifdef CONFIG_AT32_SERIALBRK_BSDCOMPAT + if (priv->ie & USART_CR1_IE_BREAK_INPROGRESS) + { + leave_critical_section(flags); + return; + } +# endif + + up_restoreusartint(priv, ie); + +#else + /* Fake a TX interrupt here by just calling uart_xmitchars() with + * interrupts disabled (note this may recurse). + */ + + uart_xmitchars(dev); +#endif + } + else + { + /* Disable the TX interrupt */ + + up_restoreusartint(priv, priv->ie & ~USART_CTRL1_TDBEIEN); + } + + leave_critical_section(flags); +} +#endif + +/**************************************************************************** + * Name: up_txready + * + * Description: + * Return true if the transmit data register is empty + * + ****************************************************************************/ + +static bool up_txready(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + return ((up_serialin(priv, AT32_USART_STS_OFFSET) & USART_STS_TDBE) != 0); +} + +/**************************************************************************** + * Name: up_dma_rxcallback + * + * Description: + * This function checks the current DMA state and calls the generic + * serial stack when bytes appear to be available. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void up_dma_rxcallback(DMA_HANDLE handle, uint8_t status, void *arg) +{ + struct up_dev_s *priv = (struct up_dev_s *)arg; + + if (priv->rxenable && up_dma_rxavailable(&priv->dev)) + { + uart_recvchars(&priv->dev); + } +} +#endif + +/**************************************************************************** + * Name: up_pm_notify + * + * Description: + * Notify the driver of new power state. This callback is called after + * all drivers have had the opportunity to prepare for the new power state. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * None - The driver already agreed to transition to the low power + * consumption state when when it returned OK to the prepare() call. + * + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void up_pm_notify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + switch (pmstate) + { + case(PM_NORMAL): + { + /* Logic for PM_NORMAL goes here */ + } + break; + + case(PM_IDLE): + { + /* Logic for PM_IDLE goes here */ + } + break; + + case(PM_STANDBY): + { + /* Logic for PM_STANDBY goes here */ + } + break; + + case(PM_SLEEP): + { + /* Logic for PM_SLEEP goes here */ + } + break; + + default: + { + /* Should not get here */ + } + break; + } +} +#endif + +/**************************************************************************** + * Name: up_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a warning + * that the system is about to enter into a new power state. The driver + * should begin whatever operations that may be required to enter power + * state. The driver may abort the state change mode by returning a + * non-zero value from the callback function. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * Zero - (OK) means the event was successfully processed and that the + * driver is prepared for the PM state change. + * + * Non-zero - means that the driver is not prepared to perform the tasks + * needed achieve this power setting and will cause the state + * change to be aborted. NOTE: The prepare() method will also + * be called when reverting from lower back to higher power + * consumption modes (say because another driver refused a + * lower power state change). Drivers are not permitted to + * return non-zero values when reverting back to higher power + * consumption modes! + * + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static int up_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + /* Logic to prepare for a reduced power state goes here. */ + + return OK; +} +#endif +#endif /* HAVE_SERIALDRIVER */ +#endif /* USE_SERIALDRIVER */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef USE_SERIALDRIVER + +/**************************************************************************** + * Name: at32_serial_get_uart + * + * Description: + * Get serial driver structure for AT32 USART + * + ****************************************************************************/ + +#ifdef HAVE_SERIALDRIVER +uart_dev_t *at32_serial_get_uart(int uart_num) +{ + int uart_idx = uart_num - 1; + + if (uart_idx < 0 || uart_idx >= AT32_NUSART || !g_uart_devs[uart_idx]) + { + return NULL; + } + + if (!g_uart_devs[uart_idx]->initialized) + { + return NULL; + } + + return &g_uart_devs[uart_idx]->dev; +} +#endif /* HAVE_SERIALDRIVER */ + +/**************************************************************************** + * Name: arm_earlyserialinit + * + * Description: + * Performs the low level USART initialization early in debug so that the + * serial console will be available during bootup. This must be called + * before arm_serialinit. + * + ****************************************************************************/ + +#ifdef USE_EARLYSERIALINIT +void arm_earlyserialinit(void) +{ +#ifdef HAVE_SERIALDRIVER + unsigned i; + + /* Disable all USART interrupts */ + + for (i = 0; i < AT32_NUSART; i++) + { + if (g_uart_devs[i]) + { + up_disableusartint(g_uart_devs[i], NULL); + } + } + + /* Configure whichever one is the console */ + +#if CONSOLE_UART > 0 + up_setup(&g_uart_devs[CONSOLE_UART - 1]->dev); +#endif +#endif /* HAVE UART */ +} +#endif + +/**************************************************************************** + * Name: arm_serialinit + * + * Description: + * Register serial console and serial ports. This assumes + * that arm_earlyserialinit was called previously. + * + ****************************************************************************/ + +void arm_serialinit(void) +{ +#ifdef HAVE_SERIALDRIVER + char devname[16]; + unsigned i; + unsigned minor = 0; +#ifdef CONFIG_PM + int ret; +#endif + + /* Register to receive power management callbacks */ + +#ifdef CONFIG_PM + ret = pm_register(&g_serialcb); + DEBUGASSERT(ret == OK); + UNUSED(ret); +#endif + + /* Register the console */ + +#if CONSOLE_UART > 0 + uart_register("/dev/console", &g_uart_devs[CONSOLE_UART - 1]->dev); + +#ifndef CONFIG_AT32_SERIAL_DISABLE_REORDERING + /* If not disabled, register the console UART to ttyS0 and exclude + * it from initializing it further down + */ + + uart_register("/dev/ttyS0", &g_uart_devs[CONSOLE_UART - 1]->dev); + minor = 1; +#endif + +#if defined(SERIAL_HAVE_CONSOLE_RXDMA) || defined(SERIAL_HAVE_CONSOLE_TXDMA) + /* If we need to re-initialise the console to enable DMA do that here. */ + + up_dma_setup(&g_uart_devs[CONSOLE_UART - 1]->dev); +#endif +#endif /* CONSOLE_UART > 0 */ + + /* Register all remaining USARTs */ + + strcpy(devname, "/dev/ttySx"); + + for (i = 0; i < AT32_NUSART; i++) + { + /* Don't create a device for non-configured ports. */ + + if (g_uart_devs[i] == 0) + { + continue; + } + +#ifndef CONFIG_AT32_SERIAL_DISABLE_REORDERING + /* Don't create a device for the console - we did that above */ + + if (g_uart_devs[i]->dev.isconsole) + { + continue; + } +#endif + + /* Register USARTs as devices in increasing order */ + + devname[9] = '0' + minor++; + uart_register(devname, &g_uart_devs[i]->dev); + } +#endif /* HAVE UART */ +} + +/**************************************************************************** + * Name: at32_serial_dma_poll + * + * Description: + * Checks receive DMA buffers for received bytes that have not accumulated + * to the point where the DMA half/full interrupt has triggered. + * + * This function should be called from a timer or other periodic context. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +void at32_serial_dma_poll(void) +{ + irqstate_t flags; + + flags = enter_critical_section(); + +#ifdef CONFIG_USART1_RXDMA + if (g_usart1priv.rxdma != NULL) + { + up_dma_rxcallback(g_usart1priv.rxdma, 0, &g_usart1priv); + } +#endif + +#ifdef CONFIG_USART2_RXDMA + if (g_usart2priv.rxdma != NULL) + { + up_dma_rxcallback(g_usart2priv.rxdma, 0, &g_usart2priv); + } +#endif + +#ifdef CONFIG_USART3_RXDMA + if (g_usart3priv.rxdma != NULL) + { + up_dma_rxcallback(g_usart3priv.rxdma, 0, &g_usart3priv); + } +#endif + +#ifdef CONFIG_UART4_RXDMA + if (g_uart4priv.rxdma != NULL) + { + up_dma_rxcallback(g_uart4priv.rxdma, 0, &g_uart4priv); + } +#endif + +#ifdef CONFIG_UART5_RXDMA + if (g_uart5priv.rxdma != NULL) + { + up_dma_rxcallback(g_uart5priv.rxdma, 0, &g_uart5priv); + } +#endif + +#ifdef CONFIG_USART6_RXDMA + if (g_usart6priv.rxdma != NULL) + { + up_dma_rxcallback(g_usart6priv.rxdma, 0, &g_usart6priv); + } +#endif + +#ifdef CONFIG_UART7_RXDMA + if (g_uart7priv.rxdma != NULL) + { + up_dma_rxcallback(g_uart7priv.rxdma, 0, &g_uart7priv); + } +#endif + +#ifdef CONFIG_UART8_RXDMA + if (g_uart8priv.rxdma != NULL) + { + up_dma_rxcallback(g_uart8priv.rxdma, 0, &g_uart8priv); + } +#endif + + leave_critical_section(flags); +} +#endif + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#if CONSOLE_UART > 0 + struct up_dev_s *priv = g_uart_devs[CONSOLE_UART - 1]; + uint16_t ie; + + up_disableusartint(priv, &ie); + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + arm_lowputc('\r'); + } + + arm_lowputc(ch); + up_restoreusartint(priv, ie); +#endif + return ch; +} + +#else /* USE_SERIALDRIVER */ + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#if CONSOLE_UART > 0 + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + arm_lowputc('\r'); + } + + arm_lowputc(ch); +#endif + return ch; +} + +#endif /* USE_SERIALDRIVER */ diff --git a/arch/arm/src/at32/at32_spi.c b/arch/arm/src/at32/at32_spi.c new file mode 100644 index 0000000000..569a7d3480 --- /dev/null +++ b/arch/arm/src/at32/at32_spi.c @@ -0,0 +1,1949 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_spi.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32.h" +#include "at32_gpio.h" +#include "at32_dma.h" +#include "at32_spi.h" + +#if defined(CONFIG_AT32_SPI1) || defined(CONFIG_AT32_SPI2) || \ + defined(CONFIG_AT32_SPI3) || defined(CONFIG_AT32_SPI4) + + /************************************************************************** + * Pre-processor Definitions + *************************************************************************/ + + /* Configuration **********************************************************/ + + /* SPI interrupts */ + +#ifdef CONFIG_AT32_SPI_INTERRUPTS +# error "Interrupt driven SPI not yet supported" +#endif + +/* Can't have both interrupt driven SPI and SPI DMA */ + +#if defined(CONFIG_AT32_SPI_INTERRUPTS) && defined(CONFIG_AT32_SPI_DMA) +# error "Cannot enable both interrupt mode and DMA mode for SPI" +#endif + +/* SPI DMA priority */ + +#ifdef CONFIG_AT32_SPI_DMA + +# if defined(CONFIG_SPI_DMAPRIO) +# define SPI_DMA_PRIO CONFIG_SPI_DMAPRIO +# elif defined(CONFIG_AT32_AT32F43XX) +# define SPI_DMA_PRIO DMA_CCR_PRIMED +# else +# error "Unknown AT32 DMA" +# endif + +# if defined(CONFIG_AT32_AT32F43XX) +# if (SPI_DMA_PRIO & ~DMA_CCR_PL_MASK) != 0 +# error "Illegal value for CONFIG_SPI_DMAPRIO" +# endif +# else +# error "Unknown AT32 DMA" +# endif + +/* DMA channel configuration */ + +#if defined(CONFIG_AT32_AT32F43XX) +# define SPI_RXDMA16_CONFIG (SPI_DMA_PRIO|DMA_CCR_MSIZE_16BITS|DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC ) +# define SPI_RXDMA8_CONFIG (SPI_DMA_PRIO|DMA_CCR_MSIZE_8BITS |DMA_CCR_PSIZE_8BITS |DMA_CCR_MINC ) +# define SPI_RXDMA16NULL_CONFIG (SPI_DMA_PRIO|DMA_CCR_MSIZE_8BITS |DMA_CCR_PSIZE_16BITS ) +# define SPI_RXDMA8NULL_CONFIG (SPI_DMA_PRIO|DMA_CCR_MSIZE_8BITS |DMA_CCR_PSIZE_8BITS ) +# define SPI_TXDMA16_CONFIG (SPI_DMA_PRIO|DMA_CCR_MSIZE_16BITS|DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC|DMA_CCR_DIR) +# define SPI_TXDMA8_CONFIG (SPI_DMA_PRIO|DMA_CCR_MSIZE_8BITS |DMA_CCR_PSIZE_8BITS |DMA_CCR_MINC|DMA_CCR_DIR) +# define SPI_TXDMA16NULL_CONFIG (SPI_DMA_PRIO|DMA_CCR_MSIZE_8BITS |DMA_CCR_PSIZE_16BITS |DMA_CCR_DIR) +# define SPI_TXDMA8NULL_CONFIG (SPI_DMA_PRIO|DMA_CCR_MSIZE_8BITS |DMA_CCR_PSIZE_8BITS |DMA_CCR_DIR) +#else +# error "Unknown AT32 DMA" +#endif + +# define SPIDMA_BUFFER_MASK (4 - 1) +# define SPIDMA_SIZE(b) (((b) + SPIDMA_BUFFER_MASK) & ~SPIDMA_BUFFER_MASK) +# define SPIDMA_BUF_ALIGN aligned_data(4) + +# if defined(CONFIG_AT32_SPI1_DMA_BUFFER) && \ + CONFIG_AT32_SPI1_DMA_BUFFER > 0 +# define SPI1_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_AT32_SPI1_DMA_BUFFER) +# define SPI1_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN +# endif + +# if defined(CONFIG_AT32_SPI2_DMA_BUFFER) && \ + CONFIG_AT32_SPI2_DMA_BUFFER > 0 +# define SPI2_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_AT32_SPI2_DMA_BUFFER) +# define SPI2_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN +# endif + +# if defined(CONFIG_AT32_SPI3_DMA_BUFFER) && \ + CONFIG_AT32_SPI3_DMA_BUFFER > 0 +# define SPI3_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_AT32_SPI3_DMA_BUFFER) +# define SPI3_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN +# endif + +# if defined(CONFIG_AT32_SPI4_DMA_BUFFER) && \ + CONFIG_AT32_SPI4_DMA_BUFFER > 0 +# define SPI4_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_AT32_SPI4_DMA_BUFFER) +# define SPI4_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN +# endif + +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct at32_spidev_s +{ + struct spi_dev_s spidev; /* Externally visible part of the SPI interface */ + uint32_t spibase; /* SPIn base address */ + uint32_t spiclock; /* Clocking for the SPI module */ +#ifdef CONFIG_AT32_SPI_INTERRUPTS + uint8_t spiirq; /* SPI IRQ number */ +#endif +#ifdef CONFIG_AT32_SPI_DMA + volatile uint8_t rxresult; /* Result of the RX DMA */ + volatile uint8_t txresult; /* Result of the RX DMA */ +#ifdef CONFIG_SPI_TRIGGER + bool defertrig; /* Flag indicating that trigger should be deferred */ + bool trigarmed; /* Flag indicating that the trigger is armed */ +#endif + uint8_t rxch; /* The RX DMA channel number */ + uint8_t txch; /* The TX DMA channel number */ + uint8_t *rxbuf; /* The RX DMA buffer */ + uint8_t *txbuf; /* The TX DMA buffer */ + size_t buflen; /* The DMA buffer length */ + DMA_HANDLE rxdma; /* DMA channel handle for RX transfers */ + DMA_HANDLE txdma; /* DMA channel handle for TX transfers */ + sem_t rxsem; /* Wait for RX DMA to complete */ + sem_t txsem; /* Wait for TX DMA to complete */ + uint32_t txccr; /* DMA control register for TX transfers */ + uint32_t rxccr; /* DMA control register for RX transfers */ +#endif + bool initialized; /* Has SPI interface been initialized */ + mutex_t lock; /* Held while chip is selected for mutual exclusion */ + uint32_t frequency; /* Requested clock frequency */ + uint32_t actual; /* Actual clock frequency */ + uint8_t nbits; /* Width of word in bits (4 through 16) */ + uint8_t mode; /* Mode 0,1,2,3 */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Helpers */ + +static inline uint16_t spi_getreg(struct at32_spidev_s *priv, + uint8_t offset); + +static inline void spi_putreg(struct at32_spidev_s *priv, + uint8_t offset, uint16_t value); + +static inline uint16_t spi_readword(struct at32_spidev_s *priv); +static inline void spi_writeword(struct at32_spidev_s *priv, + uint16_t byte); + +/* DMA support */ + +#ifdef CONFIG_AT32_SPI_DMA +static int spi_dmarxwait(struct at32_spidev_s *priv); +static int spi_dmatxwait(struct at32_spidev_s *priv); +static inline void spi_dmarxwakeup(struct at32_spidev_s *priv); +static inline void spi_dmatxwakeup(struct at32_spidev_s *priv); +static void spi_dmarxcallback(DMA_HANDLE handle, uint8_t isr, + void *arg); +static void spi_dmatxcallback(DMA_HANDLE handle, uint8_t isr, + void *arg); +static void spi_dmarxsetup(struct at32_spidev_s *priv, + void *rxbuffer, + void *rxdummy, + size_t nwords); +static void spi_dmatxsetup(struct at32_spidev_s *priv, + const void *txbuffer, + const void *txdummy, + size_t nwords); +static inline void spi_dmarxstart(struct at32_spidev_s *priv); +static inline void spi_dmatxstart(struct at32_spidev_s *priv); +#endif + +/* SPI methods */ + +static int spi_lock(struct spi_dev_s *dev, bool lock); +static uint32_t spi_setfrequency(struct spi_dev_s *dev, + uint32_t frequency); +static void spi_setmode(struct spi_dev_s *dev, + enum spi_mode_e mode); +static void spi_setbits(struct spi_dev_s *dev, int nbits); +#ifdef CONFIG_SPI_HWFEATURES +static int spi_hwfeatures(struct spi_dev_s *dev, + spi_hwfeatures_t features); +#endif +static uint32_t spi_send(struct spi_dev_s *dev, uint32_t wd); +static void spi_exchange(struct spi_dev_s *dev, + const void *txbuffer, + void *rxbuffer, size_t nwords); +#ifdef CONFIG_SPI_TRIGGER +static int spi_trigger(struct spi_dev_s *dev); +#endif +#ifndef CONFIG_SPI_EXCHANGE +static void spi_sndblock(struct spi_dev_s *dev, + const void *txbuffer, + size_t nwords); +static void spi_recvblock(struct spi_dev_s *dev, + void *rxbuffer, + size_t nwords); +#endif + +/* Initialization */ + +static void spi_bus_initialize(struct at32_spidev_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI1 +static const struct spi_ops_s g_sp1iops = +{ + .lock = spi_lock, + .select = at32_spi1select, + .setfrequency = spi_setfrequency, + .setmode = spi_setmode, + .setbits = spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = spi_hwfeatures, +#endif + .status = at32_spi1status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = at32_spi1cmddata, +#endif + .send = spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = spi_exchange, +#else + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, +#endif +#ifdef CONFIG_SPI_TRIGGER + .trigger = spi_trigger, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = at32_spi1register, /* Provided externally */ +#else + .registercallback = 0, /* Not implemented */ +#endif +}; + +#if defined(SPI1_DMABUFSIZE_ADJUSTED) +static uint8_t g_spi1_txbuf[SPI1_DMABUFSIZE_ADJUSTED] SPI1_DMABUFSIZE_ALGN; +static uint8_t g_spi1_rxbuf[SPI1_DMABUFSIZE_ADJUSTED] SPI1_DMABUFSIZE_ALGN; +#endif + +static struct at32_spidev_s g_spi1dev = +{ + .spidev = + { + .ops = &g_sp1iops + }, + .spibase = AT32_SPI1_BASE, + .spiclock = AT32_PCLK2_FREQUENCY, +#ifdef CONFIG_AT32_SPI_INTERRUPTS + .spiirq = AT32_IRQ_SPI1, +#endif +#ifdef CONFIG_AT32_SPI_DMA +# ifdef CONFIG_AT32_SPI1_DMA + .rxch = DMAMUX_SPI1_RX, + .txch = DMAMUX_SPI1_TX, +# ifdef SPI1_DMABUFSIZE_ADJUSTED + .rxbuf = g_spi1_rxbuf, + .txbuf = g_spi1_txbuf, + .buflen = SPI1_DMABUFSIZE_ADJUSTED, +# endif +# else + .rxch = 0, + .txch = 0, +# endif + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif + .lock = NXMUTEX_INITIALIZER, +}; +#endif + +#ifdef CONFIG_AT32_SPI2 +static const struct spi_ops_s g_sp2iops = +{ + .lock = spi_lock, + .select = at32_spi2select, + .setfrequency = spi_setfrequency, + .setmode = spi_setmode, + .setbits = spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = spi_hwfeatures, +#endif + .status = at32_spi2status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = at32_spi2cmddata, +#endif + .send = spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = spi_exchange, +#else + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, +#endif +#ifdef CONFIG_SPI_TRIGGER + .trigger = spi_trigger, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = at32_spi2register, /* provided externally */ +#else + .registercallback = 0, /* not implemented */ +#endif +}; + +#if defined(SPI2_DMABUFSIZE_ADJUSTED) +static uint8_t g_spi2_txbuf[SPI2_DMABUFSIZE_ADJUSTED] SPI2_DMABUFSIZE_ALGN; +static uint8_t g_spi2_rxbuf[SPI2_DMABUFSIZE_ADJUSTED] SPI2_DMABUFSIZE_ALGN; +#endif + +static struct at32_spidev_s g_spi2dev = +{ + .spidev = + { + .ops = &g_sp2iops + }, + .spibase = AT32_SPI2_BASE, + .spiclock = AT32_PCLK1_FREQUENCY, +#ifdef CONFIG_AT32_SPI_INTERRUPTS + .spiirq = AT32_IRQ_SPI2, +#endif +#ifdef CONFIG_AT32_SPI_DMA +# ifdef CONFIG_AT32_SPI2_DMA + .rxch = DMAMUX_SPI2_RX, + .txch = DMAMUX_SPI2_TX, +# ifdef SPI2_DMABUFSIZE_ADJUSTED + .rxbuf = g_spi2_rxbuf, + .txbuf = g_spi2_txbuf, + .buflen = SPI2_DMABUFSIZE_ADJUSTED, +# endif +# else + .rxch = 0, + .txch = 0, +# endif + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif + .lock = NXMUTEX_INITIALIZER, +}; +#endif + +#ifdef CONFIG_AT32_SPI3 +static const struct spi_ops_s g_sp3iops = +{ + .lock = spi_lock, + .select = at32_spi3select, + .setfrequency = spi_setfrequency, + .setmode = spi_setmode, + .setbits = spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = spi_hwfeatures, +#endif + .status = at32_spi3status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = at32_spi3cmddata, +#endif + .send = spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = spi_exchange, +#else + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, +#endif +#ifdef CONFIG_SPI_TRIGGER + .trigger = spi_trigger, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = at32_spi3register, /* provided externally */ +#else + .registercallback = 0, /* not implemented */ +#endif +}; + +#if defined(SPI3_DMABUFSIZE_ADJUSTED) +static uint8_t g_spi3_txbuf[SPI3_DMABUFSIZE_ADJUSTED] SPI3_DMABUFSIZE_ALGN; +static uint8_t g_spi3_rxbuf[SPI3_DMABUFSIZE_ADJUSTED] SPI3_DMABUFSIZE_ALGN; +#endif + +static struct at32_spidev_s g_spi3dev = +{ + .spidev = + { + .ops = &g_sp3iops + }, + .spibase = AT32_SPI3_BASE, + .spiclock = AT32_PCLK1_FREQUENCY, +#ifdef CONFIG_AT32_SPI_INTERRUPTS + .spiirq = AT32_IRQ_SPI3, +#endif +#ifdef CONFIG_AT32_SPI_DMA +# ifdef CONFIG_AT32_SPI3_DMA + .rxch = DMAMUX_SPI3_RX, + .txch = DMAMUX_SPI3_TX, +# ifdef SPI3_DMABUFSIZE_ADJUSTED + .rxbuf = g_spi3_rxbuf, + .txbuf = g_spi3_txbuf, + .buflen = SPI3_DMABUFSIZE_ADJUSTED, +# endif +# else + .rxch = 0, + .txch = 0, +# endif + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif + .lock = NXMUTEX_INITIALIZER, +}; +#endif + +#ifdef CONFIG_AT32_SPI4 +static const struct spi_ops_s g_sp4iops = +{ + .lock = spi_lock, + .select = at32_spi4select, + .setfrequency = spi_setfrequency, + .setmode = spi_setmode, + .setbits = spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = spi_hwfeatures, +#endif + .status = at32_spi4status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = at32_spi4cmddata, +#endif + .send = spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = spi_exchange, +#else + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, +#endif +#ifdef CONFIG_SPI_TRIGGER + .trigger = spi_trigger, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = at32_spi4register, /* provided externally */ +#else + .registercallback = 0, /* not implemented */ +#endif +}; + +#if defined(SPI4_DMABUFSIZE_ADJUSTED) +static uint8_t g_spi4_txbuf[SPI4_DMABUFSIZE_ADJUSTED] SPI4_DMABUFSIZE_ALGN; +static uint8_t g_spi4_rxbuf[SPI4_DMABUFSIZE_ADJUSTED] SPI4_DMABUFSIZE_ALGN; +#endif + +static struct at32_spidev_s g_spi4dev = +{ + .spidev = + { + .ops = &g_sp4iops + }, + .spibase = AT32_SPI4_BASE, + .spiclock = AT32_PCLK2_FREQUENCY, +#ifdef CONFIG_AT32_SPI_INTERRUPTS + .spiirq = AT32_IRQ_SPI4, +#endif +#ifdef CONFIG_AT32_SPI_DMA +# ifdef CONFIG_AT32_SPI4_DMA + .rxch = DMAMUX_SPI4_RX, + .txch = DMAMUX_SPI4_TX, +# ifdef SPI4_DMABUFSIZE_ADJUSTED + .rxbuf = g_spi4_rxbuf, + .txbuf = g_spi4_txbuf, + .buflen = SPI4_DMABUFSIZE_ADJUSTED, +# endif +# else + .rxch = 0, + .txch = 0, +# endif + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif + .lock = NXMUTEX_INITIALIZER, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spi_getreg + * + * Description: + * Get the contents of the SPI register at offset + * + * Input Parameters: + * priv - private SPI device structure + * offset - offset to the register of interest + * + * Returned Value: + * The contents of the 16-bit register + * + ****************************************************************************/ + +static inline uint16_t spi_getreg(struct at32_spidev_s *priv, + uint8_t offset) +{ + return getreg16(priv->spibase + offset); +} + +/**************************************************************************** + * Name: spi_putreg + * + * Description: + * Write a 16-bit value to the SPI register at offset + * + * Input Parameters: + * priv - private SPI device structure + * offset - offset to the register of interest + * value - the 16-bit value to be written + * + * Returned Value: + * The contents of the 16-bit register + * + ****************************************************************************/ + +static inline void spi_putreg(struct at32_spidev_s *priv, + uint8_t offset, + uint16_t value) +{ + putreg16(value, priv->spibase + offset); +} + +/**************************************************************************** + * Name: spi_readword + * + * Description: + * Read one byte from SPI + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * Byte as read + * + ****************************************************************************/ + +static inline uint16_t spi_readword(struct at32_spidev_s *priv) +{ + /* Wait until the receive buffer is not empty */ + + while ((spi_getreg(priv, AT32_SPI_STS_OFFSET) & SPI_STS_RDBF) == 0) + { + } + + /* Then return the received byte */ + + return spi_getreg(priv, AT32_SPI_DT_OFFSET); +} + +/**************************************************************************** + * Name: spi_writeword + * + * Description: + * Write one byte to SPI + * + * Input Parameters: + * priv - Device-specific state data + * byte - Byte to send + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void spi_writeword(struct at32_spidev_s *priv, + uint16_t word) +{ + /* Wait until the transmit buffer is empty */ + + while ((spi_getreg(priv, AT32_SPI_STS_OFFSET) & SPI_STS_TDBE) == 0) + { + } + + /* Then send the word */ + + spi_putreg(priv, AT32_SPI_DT_OFFSET, word); +} + +/**************************************************************************** + * Name: spi_dmarxwait + * + * Description: + * Wait for DMA to complete. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI_DMA +static int spi_dmarxwait(struct at32_spidev_s *priv) +{ + int ret; + + /* Take the semaphore (perhaps waiting). If the result is zero, then the + * DMA must not really have completed??? + */ + + do + { + ret = nxsem_wait_uninterruptible(&priv->rxsem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(ret == OK || ret == -ECANCELED); + } + while (priv->rxresult == 0 && ret == OK); + + while (spi_getreg(priv, AT32_SPI_STS_OFFSET) & SPI_STS_BF); + + return ret; +} +#endif + +/**************************************************************************** + * Name: spi_dmatxwait + * + * Description: + * Wait for DMA to complete. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI_DMA +static int spi_dmatxwait(struct at32_spidev_s *priv) +{ + int ret; + + /* Take the semaphore (perhaps waiting). If the result is zero, then the + * DMA must not really have completed??? + */ + + do + { + ret = nxsem_wait_uninterruptible(&priv->txsem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(ret == OK || ret == -ECANCELED); + } + while (priv->txresult == 0 && ret == OK); + + while (spi_getreg(priv, AT32_SPI_STS_OFFSET) & SPI_STS_BF); + + return ret; +} +#endif + +/**************************************************************************** + * Name: spi_dmarxwakeup + * + * Description: + * Signal that DMA is complete + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI_DMA +static inline void spi_dmarxwakeup(struct at32_spidev_s *priv) +{ + nxsem_post(&priv->rxsem); +} +#endif + +/**************************************************************************** + * Name: spi_dmatxwakeup + * + * Description: + * Signal that DMA is complete + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI_DMA +static inline void spi_dmatxwakeup(struct at32_spidev_s *priv) +{ + nxsem_post(&priv->txsem); +} +#endif + +/**************************************************************************** + * Name: spi_dmarxcallback + * + * Description: + * Called when the RX DMA completes + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI_DMA +static void spi_dmarxcallback(DMA_HANDLE handle, uint8_t isr, void *arg) +{ + struct at32_spidev_s *priv = (struct at32_spidev_s *)arg; + + /* Wake-up the SPI driver */ + + priv->rxresult = isr | 0x080; /* OR'ed with 0x80 to assure non-zero */ + spi_dmarxwakeup(priv); +} +#endif + +/**************************************************************************** + * Name: spi_dmatxcallback + * + * Description: + * Called when the RX DMA completes + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI_DMA +static void spi_dmatxcallback(DMA_HANDLE handle, uint8_t isr, void *arg) +{ + struct at32_spidev_s *priv = (struct at32_spidev_s *)arg; + + /* Wake-up the SPI driver */ + + priv->txresult = isr | 0x080; /* OR'ed with 0x80 to assure non-zero */ + spi_dmatxwakeup(priv); +} +#endif + +/**************************************************************************** + * Name: spi_dmarxsetup + * + * Description: + * Setup to perform RX DMA + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI_DMA +static void spi_dmarxsetup(struct at32_spidev_s *priv, + void *rxbuffer, + void *rxdummy, size_t nwords) +{ + /* 8- or 16-bit mode? */ + + if (priv->nbits > 8) + { + /* 16-bit mode -- is there a buffer to receive data in? */ + + if (rxbuffer) + { + priv->rxccr = SPI_RXDMA16_CONFIG; + } + else + { + rxbuffer = rxdummy; + priv->rxccr = SPI_RXDMA16NULL_CONFIG; + } + } + else + { + /* 8-bit mode -- is there a buffer to receive data in? */ + + if (rxbuffer) + { + priv->rxccr = SPI_RXDMA8_CONFIG; + } + else + { + rxbuffer = rxdummy; + priv->rxccr = SPI_RXDMA8NULL_CONFIG; + } + } + + /* Configure the RX DMA */ + + at32_dmasetup(priv->rxdma, priv->spibase + AT32_SPI_DT_OFFSET, + (uint32_t)rxbuffer, nwords, priv->rxccr); +} +#endif + +/**************************************************************************** + * Name: spi_dmatxsetup + * + * Description: + * Setup to perform TX DMA + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI_DMA +static void spi_dmatxsetup(struct at32_spidev_s *priv, + const void *txbuffer, + const void *txdummy, size_t nwords) +{ + /* 8- or 16-bit mode? */ + + if (priv->nbits > 8) + { + /* 16-bit mode -- is there a buffer to transfer data from? */ + + if (txbuffer) + { + priv->txccr = SPI_TXDMA16_CONFIG; + } + else + { + txbuffer = txdummy; + priv->txccr = SPI_TXDMA16NULL_CONFIG; + } + } + else + { + /* 8-bit mode -- is there a buffer to transfer data from? */ + + if (txbuffer) + { + priv->txccr = SPI_TXDMA8_CONFIG; + } + else + { + txbuffer = txdummy; + priv->txccr = SPI_TXDMA8NULL_CONFIG; + } + } + + /* Setup the TX DMA */ + + at32_dmasetup(priv->txdma, priv->spibase + AT32_SPI_DT_OFFSET, + (uint32_t)txbuffer, nwords, priv->txccr); +} +#endif + +/**************************************************************************** + * Name: spi_dmarxstart + * + * Description: + * Start RX DMA + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI_DMA +static inline void spi_dmarxstart(struct at32_spidev_s *priv) +{ + priv->rxresult = 0; + at32_dmastart(priv->rxdma, spi_dmarxcallback, priv, false); +} +#endif + +/**************************************************************************** + * Name: spi_dmatxstart + * + * Description: + * Start TX DMA + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI_DMA +static inline void spi_dmatxstart(struct at32_spidev_s *priv) +{ + priv->txresult = 0; + at32_dmastart(priv->txdma, spi_dmatxcallback, priv, false); +} +#endif + +/**************************************************************************** + * Name: spi_modifycr1 + * + * Description: + * Clear and set bits in the CR1 register + * + * Input Parameters: + * priv - Device-specific state data + * clrbits - The bits to clear + * setbits - The bits to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void spi_modifycr1(struct at32_spidev_s *priv, + uint16_t setbits, + uint16_t clrbits) +{ + uint16_t cr1; + cr1 = spi_getreg(priv, AT32_SPI_CTRL1_OFFSET); + cr1 &= ~clrbits; + cr1 |= setbits; + spi_putreg(priv, AT32_SPI_CTRL1_OFFSET, cr1); +} + +/**************************************************************************** + * Name: spi_modifycr2 + * + * Description: + * Clear and set bits in the CR2 register + * + * Input Parameters: + * priv - Device-specific state data + * clrbits - The bits to clear + * setbits - The bits to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_AT32_AT32F43XX) || defined(CONFIG_AT32_SPI_DMA) +static void spi_modifycr2(struct at32_spidev_s *priv, uint16_t setbits, + uint16_t clrbits) +{ + uint16_t cr2; + cr2 = spi_getreg(priv, AT32_SPI_CTRL2_OFFSET); + cr2 &= ~clrbits; + cr2 |= setbits; + spi_putreg(priv, AT32_SPI_CTRL2_OFFSET, cr2); +} +#endif + +/**************************************************************************** + * Name: spi_lock + * + * Description: + * On SPI buses where there are multiple devices, it will be necessary to + * lock SPI to have exclusive access to the buses for a sequence of + * transfers. The bus should be locked before the chip is selected. After + * locking the SPI bus, the caller should then also call the setfrequency, + * setbits, and setmode methods to make sure that the SPI is properly + * configured for the device. If the SPI bus is being shared, then it + * may have been left in an incompatible state. + * + * Input Parameters: + * dev - Device-specific state data + * lock - true: Lock spi bus, false: unlock SPI bus + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int spi_lock(struct spi_dev_s *dev, bool lock) +{ + struct at32_spidev_s *priv = (struct at32_spidev_s *)dev; + int ret; + + if (lock) + { + ret = nxmutex_lock(&priv->lock); + } + else + { + ret = nxmutex_unlock(&priv->lock); + } + + return ret; +} + +/**************************************************************************** + * Name: spi_setfrequency + * + * Description: + * Set the SPI frequency. + * + * Input Parameters: + * dev - Device-specific state data + * frequency - The SPI frequency requested + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + +static uint32_t spi_setfrequency(struct spi_dev_s *dev, + uint32_t frequency) +{ + struct at32_spidev_s *priv = (struct at32_spidev_s *)dev; + uint16_t setbits; + uint32_t actual; + + /* Has the frequency changed? */ + + if (frequency != priv->frequency) + { + /* Choices are limited by PCLK frequency with a set of divisors */ + + if (frequency >= priv->spiclock >> 1) + { + /* More than fPCLK/2. This is as fast as we can go */ + + setbits = SPI_CTRL1_MDIV_2; /* 000: fPCLK/2 */ + actual = priv->spiclock >> 1; + } + else if (frequency >= priv->spiclock >> 2) + { + /* Between fPCLCK/2 and fPCLCK/4, pick the slower */ + + setbits = SPI_CTRL1_MDIV_4; /* 001: fPCLK/4 */ + actual = priv->spiclock >> 2; + } + else if (frequency >= priv->spiclock >> 3) + { + /* Between fPCLCK/4 and fPCLCK/8, pick the slower */ + + setbits = SPI_CTRL1_MDIV_8; /* 010: fPCLK/8 */ + actual = priv->spiclock >> 3; + } + else if (frequency >= priv->spiclock >> 4) + { + /* Between fPCLCK/8 and fPCLCK/16, pick the slower */ + + setbits = SPI_CTRL1_MDIV_16; /* 011: fPCLK/16 */ + actual = priv->spiclock >> 4; + } + else if (frequency >= priv->spiclock >> 5) + { + /* Between fPCLCK/16 and fPCLCK/32, pick the slower */ + + setbits = SPI_CTRL1_MDIV_32; /* 100: fPCLK/32 */ + actual = priv->spiclock >> 5; + } + else if (frequency >= priv->spiclock >> 6) + { + /* Between fPCLCK/32 and fPCLCK/64, pick the slower */ + + setbits = SPI_CTRL1_MDIV_64; /* 101: fPCLK/64 */ + actual = priv->spiclock >> 6; + } + else if (frequency >= priv->spiclock >> 7) + { + /* Between fPCLCK/64 and fPCLCK/128, pick the slower */ + + setbits = SPI_CTRL1_MDIV_128; /* 110: fPCLK/128 */ + actual = priv->spiclock >> 7; + } + else if (frequency >= priv->spiclock >> 8) + { + /* Between fPCLCK/128 and fPCLCK/256, pick the slower */ + + setbits = SPI_CTRL1_MDIV_256; /* 111: fPCLK/256 */ + actual = priv->spiclock >> 8; + } + else if (frequency >= priv->spiclock >> 9) + { + /* Between fPCLCK/256 and fPCLCK/512, pick the slower */ + + setbits = SPI_CTRL1_MDIV_512; /* 1000: fPCLK/512 */ + actual = priv->spiclock >> 9; + } + else + { + /* Less than fPCLK/1024. This is as slow as we can go */ + + setbits = SPI_CTRL1_MDIV_1024; /* 1001: fPCLK/1024 */ + actual = priv->spiclock >> 10; + } + + spi_modifycr1(priv, 0, SPI_CTRL1_SPIEN); + spi_modifycr1(priv, (setbits & SPI_CTRL1_MDIV_MASK), \ + SPI_CTRL1_MDIV_MASK); + spi_modifycr2(priv, ((setbits >> 6) << 8), SPI_CTRL2_MDIV); + spi_modifycr1(priv, SPI_CTRL1_SPIEN, 0); + + /* Save the frequency selection so that subsequent reconfigurations + * will be faster. + */ + + spiinfo("Frequency %" PRIu32 "->%" PRIu32 "\n", frequency, actual); + + priv->frequency = frequency; + priv->actual = actual; + } + + return priv->actual; +} + +/**************************************************************************** + * Name: spi_setmode + * + * Description: + * Set the SPI mode. see enum spi_mode_e for mode definitions + * + * Input Parameters: + * dev - Device-specific state data + * mode - The SPI mode requested + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + +static void spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode) +{ + struct at32_spidev_s *priv = (struct at32_spidev_s *)dev; + uint16_t setbits; + uint16_t clrbits; + + spiinfo("mode=%d\n", mode); + + /* Has the mode changed? */ + + if (mode != priv->mode) + { + /* Yes... Set CR1 appropriately */ + + switch (mode) + { + case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */ + setbits = 0; + clrbits = SPI_CTRL1_CLKPOL | SPI_CTRL1_CLKPHA; + break; + + case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */ + setbits = SPI_CTRL1_CLKPHA; + clrbits = SPI_CTRL1_CLKPOL; + break; + + case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */ + setbits = SPI_CTRL1_CLKPOL; + clrbits = SPI_CTRL1_CLKPHA; + break; + + case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */ + setbits = SPI_CTRL1_CLKPOL | SPI_CTRL1_CLKPHA; + clrbits = 0; + break; + + #ifdef SPI_CTRL2_TIEN /* If MCU supports TI Synchronous Serial Frame Format */ + case SPIDEV_MODETI: + setbits = 0; + clrbits = SPI_CTRL1_CLKPOL | SPI_CTRL1_CLKPHA; + break; + #endif + + default: + return; + } + + spi_modifycr1(priv, 0, SPI_CTRL1_SPIEN); + spi_modifycr1(priv, setbits, clrbits); + spi_modifycr1(priv, SPI_CTRL1_SPIEN, 0); + + #ifdef SPI_CTRL2_TIEN /* If MCU supports TI Synchronous Serial Frame Format */ + switch (mode) + { + case SPIDEV_MODE0: + case SPIDEV_MODE1: + case SPIDEV_MODE2: + case SPIDEV_MODE3: + setbits = 0; + clrbits = SPI_CTRL2_TIEN; + break; + + case SPIDEV_MODETI: + setbits = SPI_CTRL2_TIEN; + clrbits = 0; + break; + + default: + return; + } + + spi_modifycr1(priv, 0, SPI_CTRL1_SPIEN); + spi_modifycr2(priv, setbits, clrbits); + spi_modifycr1(priv, SPI_CTRL1_SPIEN, 0); + #endif + + /* Save the mode so that subsequent re-configurations will be + * faster + */ + + priv->mode = mode; + } +} + +/**************************************************************************** + * Name: spi_setbits + * + * Description: + * Set the number of bits per word. + * + * Input Parameters: + * dev - Device-specific state data + * nbits - The number of bits requested + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void spi_setbits(struct spi_dev_s *dev, int nbits) +{ + struct at32_spidev_s *priv = (struct at32_spidev_s *)dev; + uint16_t setbits; + uint16_t clrbits; + + spiinfo("nbits=%d\n", nbits); + + /* Has the number of bits changed? */ + + if (nbits != priv->nbits) + { + /* Yes... Set CR1 appropriately */ + + switch (nbits) + { + case 8: + setbits = 0; + clrbits = SPI_CTRL1_FBN; + break; + + case 16: + setbits = SPI_CTRL1_FBN; + clrbits = 0; + break; + + default: + return; + } + + spi_modifycr1(priv, 0, SPI_CTRL1_SPIEN); + spi_modifycr1(priv, setbits, clrbits); + spi_modifycr1(priv, SPI_CTRL1_SPIEN, 0); + + /* Save the selection so that subsequent re-configurations will be + * faster. + */ + + priv->nbits = nbits; + } +} + +/**************************************************************************** + * Name: spi_hwfeatures + * + * Description: + * Set hardware-specific feature flags. + * + * Input Parameters: + * dev - Device-specific state data + * features - H/W feature flags + * + * Returned Value: + * Zero (OK) if the selected H/W features are enabled; A negated errno + * value if any H/W feature is not supportable. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_HWFEATURES +static int spi_hwfeatures(struct spi_dev_s *dev, + spi_hwfeatures_t features) +{ +#if defined(CONFIG_SPI_BITORDER) || defined(CONFIG_SPI_TRIGGER) + struct at32_spidev_s *priv = (struct at32_spidev_s *)dev; +#endif + +#ifdef CONFIG_SPI_BITORDER + uint16_t setbits; + uint16_t clrbits; + + spiinfo("features=%08x\n", features); + + /* Transfer data LSB first? */ + + if ((features & HWFEAT_LSBFIRST) != 0) + { + setbits = SPI_CTRL1_LTF; + clrbits = 0; + } + else + { + setbits = 0; + clrbits = SPI_CTRL1_LTF; + } + + spi_modifycr1(priv, 0, SPI_CTRL1_SPIEN); + spi_modifycr1(priv, setbits, clrbits); + spi_modifycr1(priv, SPI_CTRL1_SPIEN, 0); + + features &= ~HWFEAT_LSBFIRST; +#endif + +#ifdef CONFIG_SPI_TRIGGER + /* Turn deferred trigger mode on or off. Only applicable for DMA mode. + * If a transfer is deferred then the DMA will not actually be triggered + * until a subsequent call to SPI_TRIGGER to set it off. The thread will + * be waiting on the transfer completing as normal. + */ + + priv->defertrig = ((features & HWFEAT_TRIGGER) != 0); + features &= ~HWFEAT_TRIGGER; +#endif + + /* Other H/W features are not supported */ + + return (features == 0) ? OK : -ENOSYS; +} +#endif + +/**************************************************************************** + * Name: spi_send + * + * Description: + * Exchange one word on SPI + * + * Input Parameters: + * dev - Device-specific state data + * wd - The word to send. the size of the data is determined by the + * number of bits selected for the SPI interface. + * + * Returned Value: + * response + * + ****************************************************************************/ + +static uint32_t spi_send(struct spi_dev_s *dev, uint32_t wd) +{ + struct at32_spidev_s *priv = (struct at32_spidev_s *)dev; + uint32_t regval; + uint32_t ret; + + DEBUGASSERT(priv && priv->spibase); + + spi_writeword(priv, (uint32_t)(wd & 0xffff)); + ret = (uint16_t)spi_readword(priv); + + /* Check and clear any error flags + * (Reading from the SR clears the error flags) + */ + + do + { + regval = spi_getreg(priv, AT32_SPI_STS_OFFSET); + } + while (regval & SPI_STS_BF); + + spiinfo("Sent: %04" PRIx32 " Return: %04" PRIx32 + " Status: %02" PRIx32 "\n", wd, ret, regval); + + UNUSED(regval); + + return ret; +} + +/**************************************************************************** + * Name: spi_exchange (no DMA). aka spi_exchange_nodma + * + * Description: + * Exchange a block of data on SPI without using DMA + * + * REVISIT: + * This function could be much more efficient by exploiting (1) RX and TX + * FIFOs and (2) the AT32 data packing. + * + * Input Parameters: + * dev - Device-specific state data + * txbuffer - A pointer to the buffer of data to be sent + * rxbuffer - A pointer to a buffer in which to receive data + * nwords - the length of data to be exchanged in units of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if !defined(CONFIG_AT32_SPI_DMA) || defined(CONFIG_AT32_DMACAPABLE) || \ + defined(CONFIG_AT32_SPI_DMATHRESHOLD) +#if !defined(CONFIG_AT32_SPI_DMA) +static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, + void *rxbuffer, size_t nwords) +#else +static void spi_exchange_nodma(struct spi_dev_s *dev, + const void *txbuffer, + void *rxbuffer, size_t nwords) +#endif +{ + struct at32_spidev_s *priv = (struct at32_spidev_s *)dev; + DEBUGASSERT(priv && priv->spibase); + + spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n", txbuffer, rxbuffer, nwords); + + /* 8- or 16-bit mode? */ + + if (priv->nbits > 8) + { + /* 16-bit mode */ + + const uint16_t *src = (const uint16_t *)txbuffer; + uint16_t *dest = (uint16_t *)rxbuffer; + uint16_t word; + + while (nwords-- > 0) + { + /* Get the next word to write. Is there a source buffer? */ + + if (src) + { + word = *src++; + } + else + { + word = 0xffff; + } + + /* Exchange one word */ + + word = (uint16_t)spi_send(dev, (uint32_t)word); + + /* Is there a buffer to receive the return value? */ + + if (dest) + { + *dest++ = word; + } + } + } + else + { + /* 8-bit mode */ + + const uint8_t *src = (const uint8_t *)txbuffer; + uint8_t *dest = (uint8_t *)rxbuffer; + uint8_t word; + + while (nwords-- > 0) + { + /* Get the next word to write. Is there a source buffer? */ + + if (src) + { + word = *src++; + } + else + { + word = 0xff; + } + + /* Exchange one word */ + + word = (uint8_t)spi_send(dev, (uint32_t)word); + + /* Is there a buffer to receive the return value? */ + + if (dest) + { + *dest++ = word; + } + } + } +} +#endif /* !CONFIG_AT32_SPI_DMA || CONFIG_AT32_DMACAPABLE || CONFIG_AT32_SPI_DMATHRESHOLD */ + +/**************************************************************************** + * Name: spi_exchange (with DMA capability) + * + * Description: + * Exchange a block of data on SPI using DMA + * + * Input Parameters: + * dev - Device-specific state data + * txbuffer - A pointer to the buffer of data to be sent + * rxbuffer - A pointer to a buffer in which to receive data + * nwords - the length of data to be exchanged in units of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI_DMA +static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, + void *rxbuffer, size_t nwords) +{ + struct at32_spidev_s *priv = (struct at32_spidev_s *)dev; + void *xbuffer = rxbuffer; + int ret; + + DEBUGASSERT(priv != NULL); + + /* Convert the number of word to a number of bytes */ + + size_t nbytes = (priv->nbits > 8) ? nwords << 1 : nwords; + +#ifdef CONFIG_AT32_SPI_DMATHRESHOLD + /* If this is a small SPI transfer, then let spi_exchange_nodma() do the + * work. + */ + + if (nbytes <= CONFIG_AT32_SPI_DMATHRESHOLD) + { + spi_exchange_nodma(dev, txbuffer, rxbuffer, nwords); + return; + } +#endif + + if ((priv->rxdma == NULL) || (priv->txdma == NULL) || + up_interrupt_context()) + { + /* Invalid DMA channels, or interrupt context, fall + * back to non-DMA method. + */ + + spi_exchange_nodma(dev, txbuffer, rxbuffer, nwords); + return; + } + +#ifdef CONFIG_AT32_DMACAPABLE + if ((txbuffer && priv->txbuf == 0 && + !at32_dmacapable((uintptr_t)txbuffer, nwords, priv->txccr)) || + (rxbuffer && priv->rxbuf == 0 && + !at32_dmacapable((uintptr_t)rxbuffer, nwords, priv->rxccr))) + { + /* Unsupported memory region fall back to non-DMA method. */ + + spi_exchange_nodma(dev, txbuffer, rxbuffer, nwords); + } + else +#endif + { + static uint16_t rxdummy = 0xffff; + static const uint16_t txdummy = 0xffff; + + spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n", + txbuffer, rxbuffer, nwords); + DEBUGASSERT(priv && priv->spibase); + + /* Setup DMAs */ + + /* If this bus uses a in driver buffers we will incur 2 copies, + * The copy cost is << less the non DMA transfer time and having + * the buffer in the driver ensures DMA can be used. This is because + * the API does not support passing the buffer extent so the only + * extent is buffer + the transfer size. These can sizes be less than + * the cache line size, and not aligned and typically greater then 4 + * bytes, which is about the break even point for the DMA IO overhead. + */ + + if (txbuffer && priv->txbuf) + { + if (nbytes > priv->buflen) + { + nbytes = priv->buflen; + } + + memcpy(priv->txbuf, txbuffer, nbytes); + txbuffer = priv->txbuf; + rxbuffer = rxbuffer ? priv->rxbuf : rxbuffer; + } + + spi_modifycr1(priv, 0, SPI_CTRL1_SPIEN); + + spi_dmarxsetup(priv, rxbuffer, &rxdummy, nwords); + spi_dmatxsetup(priv, txbuffer, &txdummy, nwords); + + #ifdef CONFIG_SPI_TRIGGER + /* Is deferred triggering in effect? */ + + if (!priv->defertrig) + { + /* No.. Start the DMAs */ + + spi_dmarxstart(priv); + spi_dmatxstart(priv); + } + else + { + /* Yes.. indicated that we are ready to be started */ + + priv->trigarmed = true; + } + #else + /* Start the DMAs */ + + spi_dmarxstart(priv); + spi_dmatxstart(priv); + #endif + + spi_modifycr1(priv, SPI_CTRL1_SPIEN, 0); + + /* Then wait for each to complete */ + + ret = spi_dmarxwait(priv); + if (ret < 0) + { + ret = spi_dmatxwait(priv); + } + + if (rxbuffer != NULL && priv->rxbuf != NULL && ret >= 0) + { + memcpy(xbuffer, priv->rxbuf, nbytes); + } + + #ifdef CONFIG_SPI_TRIGGER + priv->trigarmed = false; + #endif + } +} +#endif /* CONFIG_AT32_SPI_DMA */ + +/**************************************************************************** + * Name: spi_trigger + * + * Description: + * Trigger a previously configured DMA transfer. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * OK - Trigger was fired + * ENOTSUP - Trigger not fired due to lack of DMA support + * EIO - Trigger not fired because not previously primed + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_TRIGGER +static int spi_trigger(struct spi_dev_s *dev) +{ +#ifdef CONFIG_AT32_SPI_DMA + struct at32_spidev_s *priv = (struct at32_spidev_s *)dev; + + if (!priv->trigarmed) + { + return -EIO; + } + + spi_dmarxstart(priv); + spi_dmatxstart(priv); + + return OK; +#else + return -ENOSYS; +#endif +} +#endif + +/**************************************************************************** + * Name: spi_sndblock + * + * Description: + * Send a block of data on SPI + * + * Input Parameters: + * dev - Device-specific state data + * txbuffer - A pointer to the buffer of data to be sent + * nwords - the length of data to send from the buffer in number of + * words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_EXCHANGE +static void spi_sndblock(struct spi_dev_s *dev, + const void *txbuffer, + size_t nwords) +{ + spiinfo("txbuffer=%p nwords=%d\n", txbuffer, nwords); + return spi_exchange(dev, txbuffer, NULL, nwords); +} +#endif + +/**************************************************************************** + * Name: spi_recvblock + * + * Description: + * Receive a block of data from SPI + * + * Input Parameters: + * dev - Device-specific state data + * rxbuffer - A pointer to the buffer in which to receive data + * nwords - the length of data that can be received in the buffer in + * number of words. The wordsize is determined by the number + * of bits-per-word selected for the SPI interface. If + * nbits <= 8, the data is packed into uint8_t's; if nbits >8, + * the data is packed into uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_EXCHANGE +static void spi_recvblock(struct spi_dev_s *dev, void *rxbuffer, + size_t nwords) +{ + spiinfo("rxbuffer=%p nwords=%d\n", rxbuffer, nwords); + return spi_exchange(dev, NULL, rxbuffer, nwords); +} +#endif + +/**************************************************************************** + * Name: spi_bus_initialize + * + * Description: + * Initialize the selected SPI bus in its default state (Master, 8-bit, + * mode 0, etc.) + * + * Input Parameters: + * priv - private SPI device structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void spi_bus_initialize(struct at32_spidev_s *priv) +{ + uint16_t setbits; + uint16_t clrbits; + + /* Configure CR1. Default configuration: + * Mode 0: CPHA=0 and CPOL=0 + * Master: MSTR=1 + * 8-bit: DFF=0 + * MSB transmitted first: LSBFIRST=0 + * Replace NSS with SSI & SSI=1: SSI=1 SSM=1 (prevents MODF error) + * Two lines full duplex: BIDIMODE=0 BIDIOIE=(Don't care) + * and RXONLY=0 + */ + + clrbits = SPI_CTRL1_CLKPHA | SPI_CTRL1_CLKPOL | SPI_CTRL1_MDIV_MASK | + SPI_CTRL1_LTF | SPI_CTRL1_ORA | SPI_CTRL1_FBN | + SPI_CTRL1_SLBTD | SPI_CTRL1_SLBEN; + setbits = SPI_CTRL1_MSTEN | SPI_CTRL1_SWCSIL | SPI_CTRL1_SWCSEN; + spi_modifycr1(priv, setbits, clrbits); + + priv->frequency = 0; + priv->nbits = 8; + priv->mode = SPIDEV_MODE0; + + /* Select a default frequency of approx. 400KHz */ + + spi_setfrequency((struct spi_dev_s *)priv, 400000); + + /* CRCPOLY configuration */ + + spi_putreg(priv, AT32_SPI_CPOLY_OFFSET, 7); + +#ifdef CONFIG_AT32_SPI_DMA + if (priv->rxch && priv->txch) + { + /* Get DMA channels. NOTE: at32_dmachannel() will always assign the + * DMA channel. If the channel is not available, then + * at32_dmachannel() will block and wait until the channel becomes + * available. + * WARNING: If you have another device sharing a DMA channel with + * SPI and the code never releases that channel, then the call to + * at32_dmachannel() will hang forever in this function! + * Don't let your design do that! + */ + + priv->rxdma = at32_dmachannel(priv->rxch); + priv->txdma = at32_dmachannel(priv->txch); + DEBUGASSERT(priv->rxdma && priv->txdma); + + spi_modifycr2(priv, SPI_CTRL2_DMAREN | SPI_CTRL2_DMATEN, 0); + } + else + { + priv->rxdma = NULL; + priv->txdma = NULL; + } +#endif + + /* Enable SPI */ + + spi_modifycr1(priv, SPI_CTRL1_SPIEN, 0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_spibus_initialize + * + * Description: + * Initialize the selected SPI bus + * + * Input Parameters: + * Port number (for hardware that has multiple SPI interfaces) + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct spi_dev_s *at32_spibus_initialize(int bus) +{ + struct at32_spidev_s *priv = NULL; + + irqstate_t flags = enter_critical_section(); + +#ifdef CONFIG_AT32_SPI1 + if (bus == 1) + { + /* Select SPI1 */ + + priv = &g_spi1dev; + + /* Only configure if the bus is not already configured */ + + if (!priv->initialized) + { + /* Configure SPI1 pins: SCK, MISO, and MOSI */ + + at32_configgpio(GPIO_SPI1_SCK); + at32_configgpio(GPIO_SPI1_MISO); + at32_configgpio(GPIO_SPI1_MOSI); + + /* Set up default configuration: Master, 8-bit, etc. */ + + spi_bus_initialize(priv); + priv->initialized = true; + } + } + else +#endif +#ifdef CONFIG_AT32_SPI2 + if (bus == 2) + { + /* Select SPI2 */ + + priv = &g_spi2dev; + + /* Only configure if the bus is not already configured */ + + if (!priv->initialized) + { + /* Configure SPI2 pins: SCK, MISO, and MOSI */ + + at32_configgpio(GPIO_SPI2_SCK); + at32_configgpio(GPIO_SPI2_MISO); + at32_configgpio(GPIO_SPI2_MOSI); + + /* Set up default configuration: Master, 8-bit, etc. */ + + spi_bus_initialize(priv); + priv->initialized = true; + } + } + else +#endif +#ifdef CONFIG_AT32_SPI3 + if (bus == 3) + { + /* Select SPI3 */ + + priv = &g_spi3dev; + + /* Only configure if the bus is not already configured */ + + if (!priv->initialized) + { + /* Configure SPI3 pins: SCK, MISO, and MOSI */ + + at32_configgpio(GPIO_SPI3_SCK); + at32_configgpio(GPIO_SPI3_MISO); + at32_configgpio(GPIO_SPI3_MOSI); + + /* Set up default configuration: Master, 8-bit, etc. */ + + spi_bus_initialize(priv); + priv->initialized = true; + } + } + else +#endif +#ifdef CONFIG_AT32_SPI4 + if (bus == 4) + { + /* Select SPI4 */ + + priv = &g_spi4dev; + + /* Only configure if the bus is not already configured */ + + if (!priv->initialized) + { + /* Configure SPI4 pins: SCK, MISO, and MOSI */ + + at32_configgpio(GPIO_SPI4_SCK); + at32_configgpio(GPIO_SPI4_MISO); + at32_configgpio(GPIO_SPI4_MOSI); + + /* Set up default configuration: Master, 8-bit, etc. */ + + spi_bus_initialize(priv); + priv->initialized = true; + } + } + else +#endif + { + spierr("ERROR: Unsupported SPI bus: %d\n", bus); + } + + leave_critical_section(flags); + + return (struct spi_dev_s *)priv; +} + +#endif /* CONFIG_AT32_SPI1 || CONFIG_AT32_SPI2 || CONFIG_AT32_SPI3 || + * CONFIG_AT32_SPI4 */ \ No newline at end of file diff --git a/arch/arm/src/at32/at32_spi.h b/arch/arm/src/at32/at32_spi.h new file mode 100644 index 0000000000..74bc6168b7 --- /dev/null +++ b/arch/arm/src/at32/at32_spi.h @@ -0,0 +1,184 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_spi.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_SPI_H +#define __ARCH_ARM_SRC_AT32_AT32_SPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "chip.h" +#include "hardware/at32_spi.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +struct spi_dev_s; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_spibus_initialize + * + * Description: + * Initialize the selected SPI bus + * + * Input Parameters: + * bus number (for hardware that has multiple SPI interfaces) + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct spi_dev_s *at32_spibus_initialize(int bus); + +/**************************************************************************** + * Name: at32_spi1/2/...select and at32_spi1/2/...status + * + * Description: + * The external functions, at32_spi1/2/...select, at32_spi1/2/...status, + * and at32_spi1/2/...cmddata must be provided by board-specific logic. + * These are implementations of the select, status, and cmddata methods of + * the SPI interface defined by struct spi_ops_s (see + * include/nuttx/spi/spi.h). All other methods (including + * at32_spibus_initialize()) are provided by common AT32 logic. To use + * this common SPI logic on your board: + * + * 1. Provide logic in at32_boardinitialize() to configure SPI chip + * select pins. + * 2. Provide at32_spi1/2/...select() and at32_spi1/2/...status() + * functions in your board-specific logic. These functions will + * perform chip selection and status operations using GPIOs in the way + * your board is configured. + * 3. If CONFIG_SPI_CMDDATA is defined in your NuttX configuration file, + * then provide at32_spi1/2/...cmddata() functions in your board- + * specific logic. These functions will perform cmd/data selection + * operations using GPIOs in the way your board is configured. + * 4. Add a calls to at32_spibus_initialize() in your low level + * application initialization logic + * 5. The handle returned by at32_spibus_initialize() may then be used to + * bind the SPI driver to higher level logic (e.g., calling + * mmcsd_spislotinitialize(), for example, will bind the SPI driver to + * the SPI MMC/SD driver). + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI1 +void at32_spi1select(struct spi_dev_s *dev, uint32_t devid, + bool selected); +uint8_t at32_spi1status(struct spi_dev_s *dev, uint32_t devid); +int at32_spi1cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif + +#ifdef CONFIG_AT32_SPI2 +void at32_spi2select(struct spi_dev_s *dev, uint32_t devid, + bool selected); +uint8_t at32_spi2status(struct spi_dev_s *dev, uint32_t devid); +int at32_spi2cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif + +#ifdef CONFIG_AT32_SPI3 +void at32_spi3select(struct spi_dev_s *dev, uint32_t devid, + bool selected); +uint8_t at32_spi3status(struct spi_dev_s *dev, uint32_t devid); +int at32_spi3cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif + +#ifdef CONFIG_AT32_SPI4 +void at32_spi4select(struct spi_dev_s *dev, uint32_t devid, + bool selected); +uint8_t at32_spi4status(struct spi_dev_s *dev, uint32_t devid); +int at32_spi4cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif + +/**************************************************************************** + * Name: at32_spi1/2/...register + * + * Description: + * If the board supports a card detect callback to inform the SPI-based + * MMC/SD driver when an SD card is inserted or removed, then + * CONFIG_SPI_CALLBACK should be defined and the following function(s) + * must be implemented. These functions implements the registercallback + * method of the SPI interface (see include/nuttx/spi/spi.h for details) + * + * Input Parameters: + * dev - Device-specific state data + * callback - The function to call on the media change + * arg - A caller provided value to return with the callback + * + * Returned Value: + * 0 on success; negated errno on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_CALLBACK +#ifdef CONFIG_AT32_SPI1 +int at32_spi1register(struct spi_dev_s *dev, spi_mediachange_t callback, + void *arg); +#endif + +#ifdef CONFIG_AT32_SPI2 +int at32_spi2register(struct spi_dev_s *dev, spi_mediachange_t callback, + void *arg); +#endif + +#ifdef CONFIG_AT32_SPI3 +int at32_spi3register(struct spi_dev_s *dev, spi_mediachange_t callback, + void *arg); +#endif + +#ifdef CONFIG_AT32_SPI4 +int at32_spi4register(struct spi_dev_s *dev, spi_mediachange_t callback, + void *arg); +#endif + +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_SPI_H */ diff --git a/arch/arm/src/at32/at32_start.c b/arch/arm/src/at32/at32_start.c new file mode 100644 index 0000000000..7dd2372715 --- /dev/null +++ b/arch/arm/src/at32/at32_start.c @@ -0,0 +1,201 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_start.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include "arm_internal.h" +#include "nvic.h" +#include "mpu.h" + +#include "at32.h" +#include "at32_gpio.h" +#include "at32_userspace.h" +#include "at32_start.h" +#include "arch/board/board.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* .data is positioned first in the primary RAM followed immediately by .bss. + * The IDLE thread stack lies just after .bss and has size give by + * CONFIG_IDLETHREAD_STACKSIZE; The heap then begins just after the IDLE. + * ARM EABI requires 64 bit stack alignment. + */ + +#define HEAP_BASE ((uintptr_t)_ebss + CONFIG_IDLETHREAD_STACKSIZE) + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* g_idle_topstack: _sbss is the start of the BSS region as defined by the + * linker script. _ebss lies at the end of the BSS region. The idle task + * stack starts at the end of BSS and is of size CONFIG_IDLETHREAD_STACKSIZE. + * The IDLE thread is the thread that the system boots on and, eventually, + * becomes the IDLE, do nothing task that runs only when there is nothing + * else to run. The heap continues from there until the end of memory. + * g_idle_topstack is a read-only variable the provides this computed + * address. + */ + +const uintptr_t g_idle_topstack = HEAP_BASE; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: showprogress + * + * Description: + * Print a character on the UART to show boot status. + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_FEATURES +# define showprogress(c) arm_lowputc(c) +#else +# define showprogress(c) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_ARMV7M_STACKCHECK +/* we need to get r10 set before we can allow instrumentation calls */ + +void __start(void) noinstrument_function; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: __start + * + * Description: + * This is the reset entry point. + * + ****************************************************************************/ + +void __start(void) +{ + const uint32_t *src; + uint32_t *dest; + +#ifdef CONFIG_ARMV7M_STACKCHECK + /* Set the stack limit before we attempt to call any functions */ + + __asm__ volatile("sub r10, sp, %0" : : + "r"(CONFIG_IDLETHREAD_STACKSIZE - 64) :); +#endif + + /* If enabled reset the MPU */ + + mpu_early_reset(); + + /* Configure the UART so that we can get debug output as soon as possible */ + + at32_clockconfig(); + arm_fpuconfig(); + at32_lowsetup(); + at32_gpioinit(); + showprogress('A'); + + /* Clear .bss. We'll do this inline (vs. calling memset) just to be + * certain that there are no issues with the state of global variables. + */ + + for (dest = (uint32_t *)_START_BSS; dest < (uint32_t *)_END_BSS; ) + { + *dest++ = 0; + } + + showprogress('B'); + + /* Move the initialized data section from his temporary holding spot in + * FLASH into the correct place in SRAM. The correct place in SRAM is + * give by _sdata and _edata. The temporary location is in FLASH at the + * end of all of the other read-only data (.text, .rodata) at _eronly. + */ + + for (src = (const uint32_t *)_DATA_INIT, + dest = (uint32_t *)_START_DATA; dest < (uint32_t *)_END_DATA; + ) + { + *dest++ = *src++; + } + + showprogress('C'); + +#ifdef CONFIG_SCHED_IRQMONITOR + up_perf_init((void *)AT32_SYSCLK_FREQUENCY); +#endif + +#ifdef CONFIG_ARMV7M_ITMSYSLOG + /* Perform ARMv7-M ITM SYSLOG initialization */ + + itm_syslog_initialize(); +#endif + + /* Perform early serial initialization */ + +#ifdef USE_EARLYSERIALINIT + arm_earlyserialinit(); +#endif + showprogress('D'); + + /* For the case of the separate user-/kernel-space build, perform whatever + * platform specific initialization of the user memory is required. + * Normally this just means initializing the user space .data and .bss + * segments. + */ + +#ifdef CONFIG_BUILD_PROTECTED + at32_userspace(); + showprogress('E'); +#endif + + /* Initialize onboard resources */ + + at32_boardinitialize(); + showprogress('F'); + + /* Then start NuttX */ + + showprogress('\r'); + showprogress('\n'); + + nx_start(); + + /* Shouldn't get here */ + + for (; ; ); +} diff --git a/arch/arm/src/at32/at32_start.h b/arch/arm/src/at32/at32_start.h new file mode 100644 index 0000000000..d8655f337c --- /dev/null +++ b/arch/arm/src/at32/at32_start.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_start.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_START_H +#define __ARCH_ARM_SRC_AT32_AT32_START_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_boardinitialize + * + * Description: + * All AT32 architectures must provide the following entry point. + * This entry point is called early in the initialization -- after + * clocking and memory have been configured but before caches have been + * enabled and before any devices have been initialized. + * + ****************************************************************************/ + +void at32_boardinitialize(void); + +#endif /* __ARCH_ARM_SRC_AT32_AT32_START_H */ diff --git a/arch/arm/src/at32/at32_syscfg.h b/arch/arm/src/at32/at32_syscfg.h new file mode 100644 index 0000000000..abefa3f650 --- /dev/null +++ b/arch/arm/src/at32/at32_syscfg.h @@ -0,0 +1,39 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_syscfg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_SYSCFG_H +#define __ARCH_ARM_SRC_AT32_AT32_SYSCFG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip.h" + +#if defined(CONFIG_AT32_AT32F43XX) +# include "hardware/at32f43xxx_syscfg.h" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_AT32_AT32_SYSCFG_H */ diff --git a/arch/arm/src/at32/at32_tim.c b/arch/arm/src/at32/at32_tim.c new file mode 100644 index 0000000000..d9dce43094 --- /dev/null +++ b/arch/arm/src/at32/at32_tim.c @@ -0,0 +1,1819 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_tim.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "chip.h" +#include "arm_internal.h" +#include "at32.h" +#include "at32_gpio.h" +#include "at32_tim.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Timer devices may be used for different purposes. Such special purposes + * include: + * + * - To generate modulated outputs for such things as motor control. If + * CONFIG_AT32_TIMn is defined then the CONFIG_AT32_TIMn_PWM may also be + * defined to indicate that the timer is intended to be used for pulsed + * output modulation. + * + * - To control periodic ADC input sampling. If CONFIG_AT32_TIMn is + * defined then CONFIG_AT32_TIMn_ADC may also be defined to indicate that + * timer "n" is intended to be used for that purpose. + * + * - To control periodic DAC outputs. If CONFIG_AT32_TIMn is defined then + * CONFIG_AT32_TIMn_DAC may also be defined to indicate that timer "n" is + * intended to be used for that purpose. + * + * - To use a Quadrature Encoder. If CONFIG_AT32_TIMn is defined then + * CONFIG_AT32_TIMn_QE may also be defined to indicate that timer "n" is + * intended to be used for that purpose. + * + * In any of these cases, the timer will not be used by this timer module. + */ + +#if defined(CONFIG_AT32_TIM1_PWM) || defined (CONFIG_AT32_TIM1_ADC) || \ + defined(CONFIG_AT32_TIM1_DAC) || defined(CONFIG_AT32_TIM1_QE) || \ + defined(CONFIG_AT32_TIM1_CAP) +# undef CONFIG_AT32_TIM1 +#endif +#if defined(CONFIG_AT32_TIM2_PWM) || defined (CONFIG_AT32_TIM2_ADC) || \ + defined(CONFIG_AT32_TIM2_DAC) || defined(CONFIG_AT32_TIM2_QE) || \ + defined(CONFIG_AT32_TIM2_CAP) +# undef CONFIG_AT32_TIM2 +#endif +#if defined(CONFIG_AT32_TIM3_PWM) || defined (CONFIG_AT32_TIM3_ADC) || \ + defined(CONFIG_AT32_TIM3_DAC) || defined(CONFIG_AT32_TIM3_QE) || \ + defined(CONFIG_AT32_TIM3_CAP) +# undef CONFIG_AT32_TIM3 +#endif +#if defined(CONFIG_AT32_TIM4_PWM) || defined (CONFIG_AT32_TIM4_ADC) || \ + defined(CONFIG_AT32_TIM4_DAC) || defined(CONFIG_AT32_TIM4_QE) || \ + defined(CONFIG_AT32_TIM4_CAP) +# undef CONFIG_AT32_TIM4 +#endif +#if defined(CONFIG_AT32_TIM5_PWM) || defined (CONFIG_AT32_TIM5_ADC) || \ + defined(CONFIG_AT32_TIM5_DAC) || defined(CONFIG_AT32_TIM5_QE) || \ + defined(CONFIG_AT32_TIM5_CAP) +# undef CONFIG_AT32_TIM5 +#endif +#if defined(CONFIG_AT32_TIM6_PWM) || defined (CONFIG_AT32_TIM6_ADC) || \ + defined(CONFIG_AT32_TIM6_DAC) || defined(CONFIG_AT32_TIM6_QE) +# undef CONFIG_AT32_TIM6 +#endif +#if defined(CONFIG_AT32_TIM7_PWM) || defined (CONFIG_AT32_TIM7_ADC) || \ + defined(CONFIG_AT32_TIM7_DAC) || defined(CONFIG_AT32_TIM7_QE) +# undef CONFIG_AT32_TIM7 +#endif +#if defined(CONFIG_AT32_TIM8_PWM) || defined (CONFIG_AT32_TIM8_ADC) || \ + defined(CONFIG_AT32_TIM8_DAC) || defined(CONFIG_AT32_TIM8_QE) || \ + defined(CONFIG_AT32_TIM8_CAP) +# undef CONFIG_AT32_TIM8 +#endif +#if defined(CONFIG_AT32_TIM9_PWM) || defined (CONFIG_AT32_TIM9_ADC) || \ + defined(CONFIG_AT32_TIM9_DAC) || defined(CONFIG_AT32_TIM9_QE) || \ + defined(CONFIG_AT32_TIM9_CAP) +# undef CONFIG_AT32_TIM9 +#endif +#if defined(CONFIG_AT32_TIM10_PWM) || defined (CONFIG_AT32_TIM10_ADC) || \ + defined(CONFIG_AT32_TIM10_DAC) || defined(CONFIG_AT32_TIM10_QE) || \ + defined(CONFIG_AT32_TIM10_CAP) +# undef CONFIG_AT32_TIM10 +#endif +#if defined(CONFIG_AT32_TIM11_PWM) || defined (CONFIG_AT32_TIM11_ADC) || \ + defined(CONFIG_AT32_TIM11_DAC) || defined(CONFIG_AT32_TIM11_QE) || \ + defined(CONFIG_AT32_TIM11_CAP) +# undef CONFIG_AT32_TIM11 +#endif +#if defined(CONFIG_AT32_TIM12_PWM) || defined (CONFIG_AT32_TIM12_ADC) || \ + defined(CONFIG_AT32_TIM12_DAC) || defined(CONFIG_AT32_TIM12_QE) || \ + defined(CONFIG_AT32_TIM12_CAP) +# undef CONFIG_AT32_TIM12 +#endif +#if defined(CONFIG_AT32_TIM13_PWM) || defined (CONFIG_AT32_TIM13_ADC) || \ + defined(CONFIG_AT32_TIM13_DAC) || defined(CONFIG_AT32_TIM13_QE) || \ + defined(CONFIG_AT32_TIM13_CAP) +# undef CONFIG_AT32_TIM13 +#endif +#if defined(CONFIG_AT32_TIM14_PWM) || defined (CONFIG_AT32_TIM14_ADC) || \ + defined(CONFIG_AT32_TIM14_DAC) || defined(CONFIG_AT32_TIM14_QE) || \ + defined(CONFIG_AT32_TIM14_CAP) +# undef CONFIG_AT32_TIM14 +#endif +#if defined(CONFIG_AT32_TIM20_PWM) || defined (CONFIG_AT32_TIM20_ADC) || \ + defined(CONFIG_AT32_TIM20_DAC) || defined(CONFIG_AT32_TIM20_QE) || \ + defined(CONFIG_AT32_TIM20_CAP) +# undef CONFIG_AT32_TIM20 +#endif + +#undef HAVE_TIM_GPIOCONFIG +#if defined(CONFIG_AT32_TIM1) +# if defined(GPIO_TIM1_CH1OUT) ||defined(GPIO_TIM1_CH2OUT)||\ + defined(GPIO_TIM1_CH3OUT) ||defined(GPIO_TIM1_CH4OUT) +# undef HAVE_TIM_GPIOCONFIG +# define HAVE_TIM_GPIOCONFIG 1 +# define HAVE_TIM1_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM2) +# if defined(GPIO_TIM2_CH1OUT) ||defined(GPIO_TIM2_CH2OUT)||\ + defined(GPIO_TIM2_CH3OUT) ||defined(GPIO_TIM2_CH4OUT) +# undef HAVE_TIM_GPIOCONFIG +# define HAVE_TIM_GPIOCONFIG 1 +# define HAVE_TIM2_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM3) +# if defined(GPIO_TIM3_CH1OUT) ||defined(GPIO_TIM3_CH2OUT)||\ + defined(GPIO_TIM3_CH3OUT) ||defined(GPIO_TIM3_CH4OUT) +# undef HAVE_TIM_GPIOCONFIG +# define HAVE_TIM_GPIOCONFIG 1 +# define HAVE_TIM3_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM4) +# if defined(GPIO_TIM4_CH1OUT) ||defined(GPIO_TIM4_CH2OUT)||\ + defined(GPIO_TIM4_CH3OUT) ||defined(GPIO_TIM4_CH4OUT) +# undef HAVE_TIM_GPIOCONFIG +# define HAVE_TIM_GPIOCONFIG 1 +# define HAVE_TIM4_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM5) +# if defined(GPIO_TIM5_CH1OUT) ||defined(GPIO_TIM5_CH2OUT)||\ + defined(GPIO_TIM5_CH3OUT) ||defined(GPIO_TIM5_CH4OUT) +# undef HAVE_TIM_GPIOCONFIG +# define HAVE_TIM_GPIOCONFIG 1 +# define HAVE_TIM5_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM8) +# if defined(GPIO_TIM8_CH1OUT) ||defined(GPIO_TIM8_CH2OUT)||\ + defined(GPIO_TIM8_CH3OUT) ||defined(GPIO_TIM8_CH4OUT) +# undef HAVE_TIM_GPIOCONFIG +# define HAVE_TIM_GPIOCONFIG 1 +# define HAVE_TIM8_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM9) +# if defined(GPIO_TIM9_CH1OUT) ||defined(GPIO_TIM9_CH2OUT)||\ + defined(GPIO_TIM9_CH3OUT) ||defined(GPIO_TIM9_CH4OUT) +# define HAVE_TIM9_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM10) +# if defined(GPIO_TIM10_CH1OUT) ||defined(GPIO_TIM10_CH2OUT)||\ + defined(GPIO_TIM10_CH3OUT) ||defined(GPIO_TIM10_CH4OUT) +# define HAVE_TIM10_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM11) +# if defined(GPIO_TIM11_CH1OUT) ||defined(GPIO_TIM11_CH2OUT)||\ + defined(GPIO_TIM11_CH3OUT) ||defined(GPIO_TIM11_CH4OUT) +# define HAVE_TIM11_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM12) +# if defined(GPIO_TIM12_CH1OUT) ||defined(GPIO_TIM12_CH2OUT)||\ + defined(GPIO_TIM12_CH3OUT) ||defined(GPIO_TIM12_CH4OUT) +# define HAVE_TIM12_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM13) +# if defined(GPIO_TIM13_CH1OUT) ||defined(GPIO_TIM13_CH2OUT)||\ + defined(GPIO_TIM13_CH3OUT) ||defined(GPIO_TIM13_CH4OUT) +# define HAVE_TIM13_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM14) +# if defined(GPIO_TIM14_CH1OUT) ||defined(GPIO_TIM14_CH2OUT)||\ + defined(GPIO_TIM14_CH3OUT) ||defined(GPIO_TIM14_CH4OUT) +# define HAVE_TIM14_GPIOCONFIG 1 +#endif +#endif + +#if defined(CONFIG_AT32_TIM20) +# if defined(GPIO_TIM20_CH1OUT) ||defined(GPIO_TIM20_CH2OUT)||\ + defined(GPIO_TIM20_CH3OUT) ||defined(GPIO_TIM20_CH4OUT) +# undef HAVE_TIM_GPIOCONFIG +# define HAVE_TIM_GPIOCONFIG 1 +# define HAVE_TIM20_GPIOCONFIG 1 +#endif +#endif + +/* This module then only compiles if there are enabled timers that are not + * intended for some other purpose. + */ + +#if defined(CONFIG_AT32_TIM1) || defined(CONFIG_AT32_TIM2) || \ + defined(CONFIG_AT32_TIM3) || defined(CONFIG_AT32_TIM4) || \ + defined(CONFIG_AT32_TIM5) || defined(CONFIG_AT32_TIM6) || \ + defined(CONFIG_AT32_TIM7) || defined(CONFIG_AT32_TIM8) || \ + defined(CONFIG_AT32_TIM9) || defined(CONFIG_AT32_TIM10) || \ + defined(CONFIG_AT32_TIM11) || defined(CONFIG_AT32_TIM12) || \ + defined(CONFIG_AT32_TIM13) || defined(CONFIG_AT32_TIM14) || \ + defined(CONFIG_AT32_TIM20) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* TIM Device Structure */ + +struct at32_tim_priv_s +{ + const struct at32_tim_ops_s *ops; + at32_tim_mode_t mode; + uint32_t base; /* TIMn base address */ +}; + +/**************************************************************************** + * Private Function prototypes + ****************************************************************************/ + +/* Register helpers */ + +static inline uint16_t at32_getreg16(struct at32_tim_dev_s *dev, + uint8_t offset); +static inline void at32_putreg16(struct at32_tim_dev_s *dev, + uint8_t offset, uint16_t value); +static inline void at32_modifyreg16(struct at32_tim_dev_s *dev, + uint8_t offset, uint16_t clearbits, + uint16_t setbits); +static inline uint32_t at32_getreg32(struct at32_tim_dev_s *dev, + uint8_t offset); +static inline void at32_putreg32(struct at32_tim_dev_s *dev, + uint8_t offset, uint32_t value); + +/* Timer helpers */ + +static void at32_tim_reload_counter(struct at32_tim_dev_s *dev); +static void at32_tim_enable(struct at32_tim_dev_s *dev); +static void at32_tim_disable(struct at32_tim_dev_s *dev); +static void at32_tim_reset(struct at32_tim_dev_s *dev); + +#ifdef HAVE_TIM_GPIOCONFIG +static void at32_tim_gpioconfig(uint32_t cfg, at32_tim_channel_t mode); +#endif + +/* Timer methods */ + +static int at32_tim_setmode(struct at32_tim_dev_s *dev, + at32_tim_mode_t mode); +static int at32_tim_setclock(struct at32_tim_dev_s *dev, + uint32_t freq); +static void at32_tim_setperiod(struct at32_tim_dev_s *dev, + uint32_t period); +static uint32_t at32_tim_getcounter(struct at32_tim_dev_s *dev); +static void at32_tim_setcounter(struct at32_tim_dev_s *dev, + uint32_t count); +static int at32_tim_getwidth(struct at32_tim_dev_s *dev); +static int at32_tim_setchannel(struct at32_tim_dev_s *dev, + uint8_t channel, at32_tim_channel_t mode); +static int at32_tim_setcompare(struct at32_tim_dev_s *dev, + uint8_t channel, uint32_t compare); +static int at32_tim_getcapture(struct at32_tim_dev_s *dev, + uint8_t channel); +static int at32_tim_setisr(struct at32_tim_dev_s *dev, + xcpt_t handler, void *arg, int source); +static void at32_tim_enableint(struct at32_tim_dev_s *dev, + int source); +static void at32_tim_disableint(struct at32_tim_dev_s *dev, + int source); +static void at32_tim_ackint(struct at32_tim_dev_s *dev, int source); +static int at32_tim_checkint(struct at32_tim_dev_s *dev, int source); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct at32_tim_ops_s at32_tim_ops = +{ + .setmode = at32_tim_setmode, + .setclock = at32_tim_setclock, + .setperiod = at32_tim_setperiod, + .getcounter = at32_tim_getcounter, + .setcounter = at32_tim_setcounter, + .getwidth = at32_tim_getwidth, + .setchannel = at32_tim_setchannel, + .setcompare = at32_tim_setcompare, + .getcapture = at32_tim_getcapture, + .setisr = at32_tim_setisr, + .enableint = at32_tim_enableint, + .disableint = at32_tim_disableint, + .ackint = at32_tim_ackint, + .checkint = at32_tim_checkint, +}; + +#ifdef CONFIG_AT32_TIM1 +struct at32_tim_priv_s at32_tim1_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR1_BASE, +}; +#endif +#ifdef CONFIG_AT32_TIM2 +struct at32_tim_priv_s at32_tim2_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR2_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM3 +struct at32_tim_priv_s at32_tim3_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR3_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM4 +struct at32_tim_priv_s at32_tim4_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR4_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM5 +struct at32_tim_priv_s at32_tim5_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR5_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM6 +struct at32_tim_priv_s at32_tim6_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR6_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM7 +struct at32_tim_priv_s at32_tim7_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR7_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM8 +struct at32_tim_priv_s at32_tim8_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR8_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM9 +struct at32_tim_priv_s at32_tim9_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR9_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM10 +struct at32_tim_priv_s at32_tim10_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR10_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM11 +struct at32_tim_priv_s at32_tim11_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR11_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM12 +struct at32_tim_priv_s at32_tim12_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR12_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM13 +struct at32_tim_priv_s at32_tim13_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR13_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM14 +struct at32_tim_priv_s at32_tim14_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR14_BASE, +}; +#endif + +#ifdef CONFIG_AT32_TIM20 +struct at32_tim_priv_s at32_tim20_priv = +{ + .ops = &at32_tim_ops, + .mode = AT32_TIM_MODE_UNUSED, + .base = AT32_TMR20_BASE, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_getreg16 + * + * Description: + * Get a 16-bit register value by offset + * + ****************************************************************************/ + +static inline uint16_t at32_getreg16(struct at32_tim_dev_s *dev, + uint8_t offset) +{ + return getreg16(((struct at32_tim_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: at32_putreg16 + * + * Description: + * Put a 16-bit register value by offset + * + ****************************************************************************/ + +static inline void at32_putreg16(struct at32_tim_dev_s *dev, + uint8_t offset, uint16_t value) +{ + putreg16(value, ((struct at32_tim_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: at32_modifyreg16 + * + * Description: + * Modify a 16-bit register value by offset + * + ****************************************************************************/ + +static inline void at32_modifyreg16(struct at32_tim_dev_s *dev, + uint8_t offset, uint16_t clearbits, + uint16_t setbits) +{ + modifyreg16(((struct at32_tim_priv_s *)dev)->base + offset, + clearbits, setbits); +} + +/**************************************************************************** + * Name: at32_getreg32 + * + * Description: + * Get a 32-bit register value by offset. This applies only for the AT32 + * F4 32-bit registers (CNT, ARR, CRR1-4) in the 32-bit timers TIM2-5. + * + ****************************************************************************/ + +static inline uint32_t at32_getreg32(struct at32_tim_dev_s *dev, + uint8_t offset) +{ + return getreg32(((struct at32_tim_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: at32_putreg32 + * + * Description: + * Put a 32-bit register value by offset. This applies only for the AT32 + * F4 32-bit registers (CNT, ARR, CRR1-4) in the 32-bit timers TIM2-5. + * + ****************************************************************************/ + +static inline void at32_putreg32(struct at32_tim_dev_s *dev, + uint8_t offset, uint32_t value) +{ + putreg32(value, ((struct at32_tim_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: at32_tim_reload_counter + ****************************************************************************/ + +static void at32_tim_reload_counter(struct at32_tim_dev_s *dev) +{ + uint16_t val = at32_getreg16(dev, AT32_GTIM_EGR_OFFSET); + val |= GTIM_EGR_UG; + at32_putreg16(dev, AT32_GTIM_EGR_OFFSET, val); +} + +/**************************************************************************** + * Name: at32_tim_enable + ****************************************************************************/ + +static void at32_tim_enable(struct at32_tim_dev_s *dev) +{ + uint16_t val = at32_getreg16(dev, AT32_GTIM_CR1_OFFSET); + val |= GTIM_CR1_CEN; + at32_tim_reload_counter(dev); + at32_putreg16(dev, AT32_GTIM_CR1_OFFSET, val); +} + +/**************************************************************************** + * Name: at32_tim_disable + ****************************************************************************/ + +static void at32_tim_disable(struct at32_tim_dev_s *dev) +{ + uint16_t val = at32_getreg16(dev, AT32_GTIM_CR1_OFFSET); + val &= ~GTIM_CR1_CEN; + at32_putreg16(dev, AT32_GTIM_CR1_OFFSET, val); +} + +/**************************************************************************** + * Name: at32_tim_reset + * + * Description: + * Reset timer into system default state, but do not affect output/input + * pins + * + ****************************************************************************/ + +static void at32_tim_reset(struct at32_tim_dev_s *dev) +{ + ((struct at32_tim_priv_s *)dev)->mode = AT32_TIM_MODE_DISABLED; + at32_tim_disable(dev); +} + +/**************************************************************************** + * Name: at32_tim_gpioconfig + ****************************************************************************/ + +#ifdef HAVE_TIM_GPIOCONFIG +static void at32_tim_gpioconfig(uint32_t cfg, at32_tim_channel_t mode) +{ + /* TODO: Add support for input capture and bipolar dual outputs for TIM8 */ + + if (mode & AT32_TIM_CH_MODE_MASK) + { + at32_configgpio(cfg); + } + else + { + at32_unconfiggpio(cfg); + } +} +#endif + +/**************************************************************************** + * Name: at32_tim_setmode + ****************************************************************************/ + +static int at32_tim_setmode(struct at32_tim_dev_s *dev, + at32_tim_mode_t mode) +{ + uint16_t val = GTIM_CR1_CEN | GTIM_CR1_ARPE; + + DEBUGASSERT(dev != NULL); + + /* This function is not supported on basic timers. To enable or + * disable it, simply set its clock to valid frequency or zero. + */ + +#if AT32_NBTIM > 0 + if (((struct at32_tim_priv_s *)dev)->base == AT32_TMR6_BASE +#endif +#if AT32_NBTIM > 1 + || ((struct at32_tim_priv_s *)dev)->base == AT32_TMR7_BASE +#endif +#if AT32_NBTIM > 0 + ) + { + return -EINVAL; + } +#endif + + /* Decode operational modes */ + + switch (mode & AT32_TIM_MODE_MASK) + { + case AT32_TIM_MODE_DISABLED: + val = 0; + break; + + case AT32_TIM_MODE_DOWN: + val |= GTIM_CR1_DIR; + + case AT32_TIM_MODE_UP: + break; + + case AT32_TIM_MODE_UPDOWN: + /* Our default: + * Interrupts are generated on compare, when counting down + */ + + val |= GTIM_CR1_CENTER1; + break; + + case AT32_TIM_MODE_PULSE: + val |= GTIM_CR1_OPM; + break; + + default: + return -EINVAL; + } + + at32_tim_reload_counter(dev); + at32_putreg16(dev, AT32_GTIM_CR1_OFFSET, val); + +#if AT32_NATIM > 0 + /* Advanced registers require Main Output Enable */ + + if (((struct at32_tim_priv_s *)dev)->base == AT32_TMR1_BASE +#ifdef AT32_TMR8_BASE + || ((struct at32_tim_priv_s *)dev)->base == AT32_TMR8_BASE +#endif +#ifdef AT32_TMR20_BASE + || ((struct at32_tim_priv_s *)dev)->base == AT32_TMR20_BASE +#endif + ) + { + at32_modifyreg16(dev, AT32_ATIM_BDTR_OFFSET, 0, ATIM_BDTR_MOE); + } +#endif + + return OK; +} + +/**************************************************************************** + * Name: at32_tim_setclock + ****************************************************************************/ + +static int at32_tim_setclock(struct at32_tim_dev_s *dev, uint32_t freq) +{ + uint32_t freqin; + int prescaler; + + DEBUGASSERT(dev != NULL); + + /* Disable Timer? */ + + if (freq == 0) + { + at32_tim_disable(dev); + return 0; + } + + /* Get the input clock frequency for this timer. These vary with + * different timer clock sources, MCU-specific timer configuration, and + * board-specific clock configuration. The correct input clock frequency + * must be defined in the board.h header file. + */ + + switch (((struct at32_tim_priv_s *)dev)->base) + { +#ifdef CONFIG_AT32_TIM1 + case AT32_TMR1_BASE: + freqin = AT32_APB2_TIM1_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM2 + case AT32_TMR2_BASE: + freqin = AT32_APB1_TIM2_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM3 + case AT32_TMR3_BASE: + freqin = AT32_APB1_TIM3_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM4 + case AT32_TMR4_BASE: + freqin = AT32_APB1_TIM4_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM5 + case AT32_TMR5_BASE: + freqin = AT32_APB1_TIM5_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM6 + case AT32_TMR6_BASE: + freqin = AT32_APB1_TIM6_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM7 + case AT32_TMR7_BASE: + freqin = AT32_APB1_TIM7_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM8 + case AT32_TMR8_BASE: + freqin = AT32_APB2_TIM8_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM9 + case AT32_TMR9_BASE: + freqin = AT32_APB2_TIM9_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM10 + case AT32_TMR10_BASE: + freqin = AT32_APB2_TIM10_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM11 + case AT32_TMR11_BASE: + freqin = AT32_APB2_TIM11_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM12 + case AT32_TMR12_BASE: + freqin = AT32_APB1_TIM12_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM13 + case AT32_TMR13_BASE: + freqin = AT32_APB1_TIM13_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM14 + case AT32_TMR14_BASE: + freqin = AT32_APB1_TIM14_CLKIN; + break; +#endif +#ifdef CONFIG_AT32_TIM20 + case AT32_TMR20_BASE: + freqin = AT32_APB2_TIM20_CLKIN; + break; +#endif + + default: + return -EINVAL; + } + + /* Select a pre-scaler value for this timer using the input clock + * frequency. + */ + + prescaler = freqin / freq; + + /* We need to decrement value for '1', but only, if that will not to + * cause underflow. + */ + + if (prescaler > 0) + { + prescaler--; + } + + /* Check for overflow as well. */ + + if (prescaler > 0xffff) + { + prescaler = 0xffff; + } + + at32_putreg16(dev, AT32_GTIM_PSC_OFFSET, prescaler); + at32_tim_enable(dev); + + return prescaler; +} + +/**************************************************************************** + * Name: at32_tim_setperiod + ****************************************************************************/ + +static void at32_tim_setperiod(struct at32_tim_dev_s *dev, + uint32_t period) +{ + DEBUGASSERT(dev != NULL); + at32_putreg32(dev, AT32_GTIM_ARR_OFFSET, period); +} + +/**************************************************************************** + * Name: at32_tim_getcounter + ****************************************************************************/ + +static uint32_t at32_tim_getcounter(struct at32_tim_dev_s *dev) +{ + DEBUGASSERT(dev != NULL); + return at32_tim_getwidth(dev) > 16 ? + at32_getreg32(dev, AT32_GTIM_CNT_OFFSET) : + (uint32_t)at32_getreg16(dev, AT32_GTIM_CNT_OFFSET); +} + +/**************************************************************************** + * Name: at32_tim_setcounter + ****************************************************************************/ + +static void at32_tim_setcounter(struct at32_tim_dev_s *dev, + uint32_t count) +{ + DEBUGASSERT(dev != NULL); + + if (at32_tim_getwidth(dev) > 16) + { + at32_putreg32(dev, AT32_GTIM_CNT_OFFSET, count); + } + else + { + at32_putreg16(dev, AT32_GTIM_CNT_OFFSET, (uint16_t)count); + } +} + +/**************************************************************************** + * Name: at32_tim_getwidth + ****************************************************************************/ + +static int at32_tim_getwidth(struct at32_tim_dev_s *dev) +{ + /* Only TIM2 and TIM5 timers may be 32-bits in width + * + * Reference Table 2 of en.DM00042534.pdf + */ + + switch (((struct at32_tim_priv_s *)dev)->base) + { + /* TIM2 is 32-bits */ + + case AT32_TMR2_BASE: + return 32; + + /* TIM5 is 32-bits */ + + case AT32_TMR5_BASE: + return 32; + + /* All others are 16-bit times */ + + default: + return 16; + } +} + +/**************************************************************************** + * Name: at32_tim_setchannel + ****************************************************************************/ + +static int at32_tim_setchannel(struct at32_tim_dev_s *dev, + uint8_t channel, at32_tim_channel_t mode) +{ + uint16_t ccmr_orig = 0; + uint16_t ccmr_val = 0; + uint16_t ccmr_mask = 0xff; + uint16_t ccer_val = at32_getreg16(dev, AT32_GTIM_CCER_OFFSET); + uint8_t ccmr_offset = AT32_GTIM_CCMR1_OFFSET; + + DEBUGASSERT(dev != NULL); + + /* Further we use range as 0..3; if channel=0 it will also overflow here */ + + if (--channel > 4) + { + return -EINVAL; + } + + /* Assume that channel is disabled and polarity is active high */ + + ccer_val &= ~((GTIM_CCER_CC1P | GTIM_CCER_CC1E) << + GTIM_CCER_CCXBASE(channel)); + + /* This function is not supported on basic timers. To enable or + * disable it, simply set its clock to valid frequency or zero. + */ + +#if AT32_NBTIM > 0 + if (((struct at32_tim_priv_s *)dev)->base == AT32_TMR6_BASE +#endif +#if AT32_NBTIM > 1 + || ((struct at32_tim_priv_s *)dev)->base == AT32_TMR7_BASE +#endif +#if AT32_NBTIM > 0 + ) + { + return -EINVAL; + } +#endif + + /* Decode configuration */ + + switch (mode & AT32_TIM_CH_MODE_MASK) + { + case AT32_TIM_CH_DISABLED: + break; + + case AT32_TIM_CH_OUTPWM: + ccmr_val = (GTIM_CCMR_MODE_PWM1 << GTIM_CCMR1_OC1M_SHIFT) + + GTIM_CCMR1_OC1PE; + ccer_val |= GTIM_CCER_CC1E << GTIM_CCER_CCXBASE(channel); + break; + + default: + return -EINVAL; + } + + /* Set polarity */ + + if (mode & AT32_TIM_CH_POLARITY_NEG) + { + ccer_val |= GTIM_CCER_CC1P << GTIM_CCER_CCXBASE(channel); + } + + /* Define its position (shift) and get register offset */ + + if (channel & 1) + { + ccmr_val <<= 8; + ccmr_mask <<= 8; + } + + if (channel > 1) + { + ccmr_offset = AT32_GTIM_CCMR2_OFFSET; + } + + ccmr_orig = at32_getreg16(dev, ccmr_offset); + ccmr_orig &= ~ccmr_mask; + ccmr_orig |= ccmr_val; + at32_putreg16(dev, ccmr_offset, ccmr_orig); + at32_putreg16(dev, AT32_GTIM_CCER_OFFSET, ccer_val); + + /* set GPIO */ + + switch (((struct at32_tim_priv_s *)dev)->base) + { +#ifdef CONFIG_AT32_TIM1 + case AT32_TMR1_BASE: + switch (channel) + { +#if defined(GPIO_TIM1_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM1_CH1OUT, mode); break; +#endif +#if defined(GPIO_TIM1_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM1_CH2OUT, mode); break; +#endif +#if defined(GPIO_TIM1_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM1_CH3OUT, mode); break; +#endif +#if defined(GPIO_TIM1_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM1_CH4OUT, mode); break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM2 + case AT32_TMR2_BASE: + switch (channel) + { +#if defined(GPIO_TIM2_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM2_CH1OUT, mode); + break; +#endif +#if defined(GPIO_TIM2_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM2_CH2OUT, mode); + break; +#endif +#if defined(GPIO_TIM2_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM2_CH3OUT, mode); + break; +#endif +#if defined(GPIO_TIM2_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM2_CH4OUT, mode); + break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM3 + case AT32_TMR3_BASE: + switch (channel) + { +#if defined(GPIO_TIM3_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM3_CH1OUT, mode); + break; +#endif +#if defined(GPIO_TIM3_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM3_CH2OUT, mode); + break; +#endif +#if defined(GPIO_TIM3_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM3_CH3OUT, mode); + break; +#endif +#if defined(GPIO_TIM3_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM3_CH4OUT, mode); + break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM4 + case AT32_TMR4_BASE: + switch (channel) + { +#if defined(GPIO_TIM4_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM4_CH1OUT, mode); + break; +#endif +#if defined(GPIO_TIM4_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM4_CH2OUT, mode); + break; +#endif +#if defined(GPIO_TIM4_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM4_CH3OUT, mode); + break; +#endif +#if defined(GPIO_TIM4_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM4_CH4OUT, mode); + break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM5 + case AT32_TMR5_BASE: + switch (channel) + { +#if defined(GPIO_TIM5_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM5_CH1OUT, mode); + break; +#endif +#if defined(GPIO_TIM5_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM5_CH2OUT, mode); + break; +#endif +#if defined(GPIO_TIM5_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM5_CH3OUT, mode); + break; +#endif +#if defined(GPIO_TIM5_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM5_CH4OUT, mode); + break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM8 + case AT32_TMR8_BASE: + switch (channel) + { +#if defined(GPIO_TIM8_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM8_CH1OUT, mode); break; +#endif +#if defined(GPIO_TIM8_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM8_CH2OUT, mode); break; +#endif +#if defined(GPIO_TIM8_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM8_CH3OUT, mode); break; +#endif +#if defined(GPIO_TIM8_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM8_CH4OUT, mode); break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM9 + case AT32_TMR9_BASE: + switch (channel) + { +#if defined(GPIO_TIM9_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM9_CH1OUT, mode); + break; +#endif +#if defined(GPIO_TIM9_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM9_CH2OUT, mode); + break; +#endif +#if defined(GPIO_TIM9_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM9_CH3OUT, mode); + break; +#endif +#if defined(GPIO_TIM9_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM9_CH4OUT, mode); + break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM10 + case AT32_TMR10_BASE: + switch (channel) + { +#if defined(GPIO_TIM10_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM10_CH1OUT, mode); + break; +#endif +#if defined(GPIO_TIM10_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM10_CH2OUT, mode); + break; +#endif +#if defined(GPIO_TIM10_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM10_CH3OUT, mode); + break; +#endif +#if defined(GPIO_TIM10_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM10_CH4OUT, mode); + break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM11 + case AT32_TMR11_BASE: + switch (channel) + { +#if defined(GPIO_TIM11_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM11_CH1OUT, mode); + break; +#endif +#if defined(GPIO_TIM11_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM11_CH2OUT, mode); + break; +#endif +#if defined(GPIO_TIM11_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM11_CH3OUT, mode); + break; +#endif +#if defined(GPIO_TIM11_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM11_CH4OUT, mode); + break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM12 + case AT32_TMR12_BASE: + switch (channel) + { +#if defined(GPIO_TIM12_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM12_CH1OUT, mode); + break; +#endif +#if defined(GPIO_TIM12_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM12_CH2OUT, mode); + break; +#endif +#if defined(GPIO_TIM12_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM12_CH3OUT, mode); + break; +#endif +#if defined(GPIO_TIM12_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM12_CH4OUT, mode); + break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM13 + case AT32_TMR13_BASE: + switch (channel) + { +#if defined(GPIO_TIM13_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM13_CH1OUT, mode); + break; +#endif +#if defined(GPIO_TIM13_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM13_CH2OUT, mode); + break; +#endif +#if defined(GPIO_TIM13_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM13_CH3OUT, mode); + break; +#endif +#if defined(GPIO_TIM13_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM13_CH4OUT, mode); + break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM14 + case AT32_TMR14_BASE: + switch (channel) + { +#if defined(GPIO_TIM14_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM14_CH1OUT, mode); + break; +#endif +#if defined(GPIO_TIM14_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM14_CH2OUT, mode); + break; +#endif +#if defined(GPIO_TIM14_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM14_CH3OUT, mode); + break; +#endif +#if defined(GPIO_TIM14_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM14_CH4OUT, mode); + break; +#endif + default: + return -EINVAL; + } + break; +#endif +#ifdef CONFIG_AT32_TIM20 + case AT32_TMR20_BASE: + switch (channel) + { +#if defined(GPIO_TIM20_CH1OUT) + case 0: + at32_tim_gpioconfig(GPIO_TIM20_CH1OUT, mode); break; +#endif +#if defined(GPIO_TIM20_CH2OUT) + case 1: + at32_tim_gpioconfig(GPIO_TIM20_CH2OUT, mode); break; +#endif +#if defined(GPIO_TIM20_CH3OUT) + case 2: + at32_tim_gpioconfig(GPIO_TIM20_CH3OUT, mode); break; +#endif +#if defined(GPIO_TIM20_CH4OUT) + case 3: + at32_tim_gpioconfig(GPIO_TIM20_CH4OUT, mode); break; +#endif + default: + return -EINVAL; + } + break; +#endif + default: + return -EINVAL; + } + + return OK; +} + +/**************************************************************************** + * Name: at32_tim_setcompare + ****************************************************************************/ + +static int at32_tim_setcompare(struct at32_tim_dev_s *dev, + uint8_t channel, uint32_t compare) +{ + DEBUGASSERT(dev != NULL); + + switch (channel) + { + case 1: + at32_putreg32(dev, AT32_GTIM_CCR1_OFFSET, compare); + break; + + case 2: + at32_putreg32(dev, AT32_GTIM_CCR2_OFFSET, compare); + break; + + case 3: + at32_putreg32(dev, AT32_GTIM_CCR3_OFFSET, compare); + break; + + case 4: + at32_putreg32(dev, AT32_GTIM_CCR4_OFFSET, compare); + break; + + default: + return -EINVAL; + } + + return OK; +} + +/**************************************************************************** + * Name: at32_tim_getcapture + ****************************************************************************/ + +static int at32_tim_getcapture(struct at32_tim_dev_s *dev, + uint8_t channel) +{ + DEBUGASSERT(dev != NULL); + + switch (channel) + { + case 1: + return at32_getreg32(dev, AT32_GTIM_CCR1_OFFSET); + case 2: + return at32_getreg32(dev, AT32_GTIM_CCR2_OFFSET); + case 3: + return at32_getreg32(dev, AT32_GTIM_CCR3_OFFSET); + case 4: + return at32_getreg32(dev, AT32_GTIM_CCR4_OFFSET); + } + + return -EINVAL; +} + +/**************************************************************************** + * Name: at32_tim_setisr + ****************************************************************************/ + +static int at32_tim_setisr(struct at32_tim_dev_s *dev, xcpt_t handler, + void * arg, int source) +{ + int vectorno; + + DEBUGASSERT(dev != NULL); + DEBUGASSERT(source == 0); + + switch (((struct at32_tim_priv_s *)dev)->base) + { +#ifdef CONFIG_AT32_TIM1 + case AT32_TMR1_BASE: + vectorno = AT32_IRQ_TIM1UP; + break; +#endif +#ifdef CONFIG_AT32_TIM2 + case AT32_TMR2_BASE: + vectorno = AT32_IRQ_TIM2; + break; +#endif +#ifdef CONFIG_AT32_TIM3 + case AT32_TMR3_BASE: + vectorno = AT32_IRQ_TIM3; + break; +#endif +#ifdef CONFIG_AT32_TIM4 + case AT32_TMR4_BASE: + vectorno = AT32_IRQ_TIM4; + break; +#endif +#ifdef CONFIG_AT32_TIM5 + case AT32_TMR5_BASE: + vectorno = AT32_IRQ_TIM5; + break; +#endif +#ifdef CONFIG_AT32_TIM6 + case AT32_TMR6_BASE: + vectorno = AT32_IRQ_TIM6; + break; +#endif +#ifdef CONFIG_AT32_TIM7 + case AT32_TMR7_BASE: + vectorno = AT32_IRQ_TIM7; + break; +#endif +#ifdef CONFIG_AT32_TIM8 + case AT32_TMR8_BASE: + vectorno = AT32_IRQ_TIM8UP; + break; +#endif +#ifdef CONFIG_AT32_TIM9 + case AT32_TMR9_BASE: + vectorno = AT32_IRQ_TIM9; + break; +#endif +#ifdef CONFIG_AT32_TIM10 + case AT32_TMR10_BASE: + vectorno = AT32_IRQ_TIM10; + break; +#endif +#ifdef CONFIG_AT32_TIM11 + case AT32_TMR11_BASE: + vectorno = AT32_IRQ_TIM11; + break; +#endif +#ifdef CONFIG_AT32_TIM12 + case AT32_TMR12_BASE: + vectorno = AT32_IRQ_TIM12; + break; +#endif +#ifdef CONFIG_AT32_TIM13 + case AT32_TMR13_BASE: + vectorno = AT32_IRQ_TIM13; + break; +#endif +#ifdef CONFIG_AT32_TIM14 + case AT32_TMR14_BASE: + vectorno = AT32_IRQ_TIM14; + break; +#endif +#ifdef CONFIG_AT32_TIM20 + case AT32_TMR20_BASE: + vectorno = AT32_IRQ_TIM20UP; + break; +#endif + + default: + return -EINVAL; + } + + /* Disable interrupt when callback is removed */ + + if (!handler) + { + up_disable_irq(vectorno); + irq_detach(vectorno); + return OK; + } + + /* Otherwise set callback and enable interrupt */ + + irq_attach(vectorno, handler, arg); + up_enable_irq(vectorno); + + return OK; +} + +/**************************************************************************** + * Name: at32_tim_enableint + ****************************************************************************/ + +static void at32_tim_enableint(struct at32_tim_dev_s *dev, int source) +{ + DEBUGASSERT(dev != NULL); + at32_modifyreg16(dev, AT32_GTIM_DIER_OFFSET, 0, source); +} + +/**************************************************************************** + * Name: at32_tim_disableint + ****************************************************************************/ + +static void at32_tim_disableint(struct at32_tim_dev_s *dev, int source) +{ + DEBUGASSERT(dev != NULL); + at32_modifyreg16(dev, AT32_GTIM_DIER_OFFSET, source, 0); +} + +/**************************************************************************** + * Name: at32_tim_ackint + ****************************************************************************/ + +static void at32_tim_ackint(struct at32_tim_dev_s *dev, int source) +{ + at32_putreg16(dev, AT32_GTIM_SR_OFFSET, ~source); +} + +/**************************************************************************** + * Name: at32_tim_checkint + ****************************************************************************/ + +static int at32_tim_checkint(struct at32_tim_dev_s *dev, int source) +{ + uint16_t regval = at32_getreg16(dev, AT32_GTIM_SR_OFFSET); + return (regval & source) ? 1 : 0; +} + +/**************************************************************************** + * Pubic Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_tim_init + ****************************************************************************/ + +struct at32_tim_dev_s *at32_tim_init(int timer) +{ + struct at32_tim_dev_s *dev = NULL; + + /* Get structure and enable power */ + + switch (timer) + { +#ifdef CONFIG_AT32_TIM1 + case 1: + dev = (struct at32_tim_dev_s *)&at32_tim1_priv; + modifyreg32(AT32_CRM_APB2EN, 0, CRM_APB2EN_TMR1EN); + break; +#endif +#ifdef CONFIG_AT32_TIM2 + case 2: + dev = (struct at32_tim_dev_s *)&at32_tim2_priv; + modifyreg32(AT32_CRM_APB1EN, 0, CRM_APB1EN_TMR2EN); + break; +#endif +#ifdef CONFIG_AT32_TIM3 + case 3: + dev = (struct at32_tim_dev_s *)&at32_tim3_priv; + modifyreg32(AT32_CRM_APB1EN, 0, CRM_APB1EN_TMR3EN); + break; +#endif +#ifdef CONFIG_AT32_TIM4 + case 4: + dev = (struct at32_tim_dev_s *)&at32_tim4_priv; + modifyreg32(AT32_CRM_APB1EN, 0, CRM_APB1EN_TMR4EN); + break; +#endif +#ifdef CONFIG_AT32_TIM5 + case 5: + dev = (struct at32_tim_dev_s *)&at32_tim5_priv; + modifyreg32(AT32_CRM_APB1EN, 0, CRM_APB1EN_TMR5EN); + break; +#endif +#ifdef CONFIG_AT32_TIM6 + case 6: + dev = (struct at32_tim_dev_s *)&at32_tim6_priv; + modifyreg32(AT32_CRM_APB1EN, 0, CRM_APB1EN_TMR6EN); + break; +#endif +#ifdef CONFIG_AT32_TIM7 + case 7: + dev = (struct at32_tim_dev_s *)&at32_tim7_priv; + modifyreg32(AT32_CRM_APB1EN, 0, CRM_APB1EN_TMR7EN); + break; +#endif +#ifdef CONFIG_AT32_TIM8 + case 8: + dev = (struct at32_tim_dev_s *)&at32_tim8_priv; + modifyreg32(AT32_CRM_APB2EN, 0, CRM_APB2EN_TMR8EN); + break; +#endif +#ifdef CONFIG_AT32_TIM9 + case 9: + dev = (struct at32_tim_dev_s *)&at32_tim9_priv; + modifyreg32(AT32_CRM_APB2EN, 0, CRM_APB2EN_TMR9EN); + break; +#endif +#ifdef CONFIG_AT32_TIM10 + case 10: + dev = (struct at32_tim_dev_s *)&at32_tim10_priv; + modifyreg32(AT32_CRM_APB2EN, 0, CRM_APB2EN_TMR10EN); + break; +#endif +#ifdef CONFIG_AT32_TIM11 + case 11: + dev = (struct at32_tim_dev_s *)&at32_tim11_priv; + modifyreg32(AT32_CRM_APB2EN, 0, CRM_APB2EN_TMR11EN); + break; +#endif +#ifdef CONFIG_AT32_TIM12 + case 12: + dev = (struct at32_tim_dev_s *)&at32_tim12_priv; + modifyreg32(AT32_CRM_APB1EN, 0, CRM_APB1EN_TMR12EN); + break; +#endif +#ifdef CONFIG_AT32_TIM13 + case 13: + dev = (struct at32_tim_dev_s *)&at32_tim13_priv; + modifyreg32(AT32_CRM_APB1EN, 0, CRM_APB1EN_TMR13EN); + break; +#endif +#ifdef CONFIG_AT32_TIM14 + case 14: + dev = (struct at32_tim_dev_s *)&at32_tim14_priv; + modifyreg32(AT32_CRM_APB1EN, 0, CRM_APB1EN_TMR14EN); + break; +#endif +#ifdef CONFIG_AT32_TIM20 + case 20: + dev = (struct at32_tim_dev_s *)&at32_tim20_priv; + modifyreg32(AT32_CRM_APB2EN, 0, CRM_APB2EN_TMR20EN); + break; +#endif + default: + return NULL; + } + + /* Is device already allocated */ + + if (((struct at32_tim_priv_s *)dev)->mode != AT32_TIM_MODE_UNUSED) + { + return NULL; + } + + at32_tim_reset(dev); + + return dev; +} + +/**************************************************************************** + * Name: at32_tim_deinit + * + * TODO: Detach interrupts, and close down all TIM Channels + * + ****************************************************************************/ + +int at32_tim_deinit(struct at32_tim_dev_s * dev) +{ + DEBUGASSERT(dev != NULL); + + /* Disable power */ + + switch (((struct at32_tim_priv_s *)dev)->base) + { +#ifdef CONFIG_AT32_TIM1 + case AT32_TMR1_BASE: + modifyreg32(AT32_CRM_APB2EN, CRM_APB2EN_TMR1EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM2 + case AT32_TMR2_BASE: + modifyreg32(AT32_CRM_APB1EN, CRM_APB1EN_TMR2EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM3 + case AT32_TMR3_BASE: + modifyreg32(AT32_CRM_APB1EN, CRM_APB1EN_TMR3EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM4 + case AT32_TMR4_BASE: + modifyreg32(AT32_CRM_APB1EN, CRM_APB1EN_TMR4EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM5 + case AT32_TMR5_BASE: + modifyreg32(AT32_CRM_APB1EN, CRM_APB1EN_TMR5EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM6 + case AT32_TMR6_BASE: + modifyreg32(AT32_CRM_APB1EN, CRM_APB1EN_TMR6EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM7 + case AT32_TMR7_BASE: + modifyreg32(AT32_CRM_APB1EN, CRM_APB1EN_TMR7EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM8 + case AT32_TMR8_BASE: + modifyreg32(AT32_CRM_APB2EN, CRM_APB2EN_TMR8EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM9 + case AT32_TMR9_BASE: + modifyreg32(AT32_CRM_APB2EN, CRM_APB2EN_TMR9EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM10 + case AT32_TMR10_BASE: + modifyreg32(AT32_CRM_APB2EN, CRM_APB2EN_TMR10EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM11 + case AT32_TMR11_BASE: + modifyreg32(AT32_CRM_APB2EN, CRM_APB2EN_TMR11EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM12 + case AT32_TMR12_BASE: + modifyreg32(AT32_CRM_APB1EN, CRM_APB1EN_TMR12EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM13 + case AT32_TMR13_BASE: + modifyreg32(AT32_CRM_APB1EN, CRM_APB1EN_TMR13EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM14 + case AT32_TMR14_BASE: + modifyreg32(AT32_CRM_APB1EN, CRM_APB1EN_TMR14EN, 0); + break; +#endif +#ifdef CONFIG_AT32_TIM20 + case AT32_TMR20_BASE: + modifyreg32(AT32_CRM_APB2EN, CRM_APB2EN_TMR20EN, 0); + break; +#endif + default: + return -EINVAL; + } + + /* Mark it as free */ + + ((struct at32_tim_priv_s *)dev)->mode = AT32_TIM_MODE_UNUSED; + + return OK; +} + +#endif /* defined(CONFIG_AT32_TIM1 || ... || TIM20) */ diff --git a/arch/arm/src/at32/at32_tim.h b/arch/arm/src/at32/at32_tim.h new file mode 100644 index 0000000000..c8aaf52ba3 --- /dev/null +++ b/arch/arm/src/at32/at32_tim.h @@ -0,0 +1,219 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_tim.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_TIM_H +#define __ARCH_ARM_SRC_AT32_AT32_TIM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" +#include "hardware/at32_tim.h" + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Helpers ******************************************************************/ + +#define AT32_TIM_SETMODE(d,mode) ((d)->ops->setmode(d,mode)) +#define AT32_TIM_SETCLOCK(d,freq) ((d)->ops->setclock(d,freq)) +#define AT32_TIM_SETPERIOD(d,period) ((d)->ops->setperiod(d,period)) +#define AT32_TIM_GETCOUNTER(d) ((d)->ops->getcounter(d)) +#define AT32_TIM_SETCOUNTER(d,c) ((d)->ops->setcounter(d,c)) +#define AT32_TIM_GETWIDTH(d) ((d)->ops->getwidth(d)) +#define AT32_TIM_SETCHANNEL(d,ch,mode) ((d)->ops->setchannel(d,ch,mode)) +#define AT32_TIM_SETCOMPARE(d,ch,comp) ((d)->ops->setcompare(d,ch,comp)) +#define AT32_TIM_GETCAPTURE(d,ch) ((d)->ops->getcapture(d,ch)) +#define AT32_TIM_SETISR(d,hnd,arg,s) ((d)->ops->setisr(d,hnd,arg,s)) +#define AT32_TIM_ENABLEINT(d,s) ((d)->ops->enableint(d,s)) +#define AT32_TIM_DISABLEINT(d,s) ((d)->ops->disableint(d,s)) +#define AT32_TIM_ACKINT(d,s) ((d)->ops->ackint(d,s)) +#define AT32_TIM_CHECKINT(d,s) ((d)->ops->checkint(d,s)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* TIM Device Structure */ + +struct at32_tim_dev_s +{ + struct at32_tim_ops_s *ops; +}; + +/* TIM Modes of Operation */ + +typedef enum +{ + AT32_TIM_MODE_UNUSED = -1, + + /* One of the following */ + + AT32_TIM_MODE_MASK = 0x0310, + AT32_TIM_MODE_DISABLED = 0x0000, + AT32_TIM_MODE_UP = 0x0100, + AT32_TIM_MODE_DOWN = 0x0110, + AT32_TIM_MODE_UPDOWN = 0x0200, + AT32_TIM_MODE_PULSE = 0x0300, + + /* One of the following */ + + AT32_TIM_MODE_CK_INT = 0x0000, + + /* AT32_TIM_MODE_CK_INT_TRIG = 0x0400, */ + + /* AT32_TIM_MODE_CK_EXT = 0x0800, */ + + /* AT32_TIM_MODE_CK_EXT_TRIG = 0x0C00, */ + + /* Clock sources, OR'ed with CK_EXT */ + + /* AT32_TIM_MODE_CK_CHINVALID = 0x0000, */ + + /* AT32_TIM_MODE_CK_CH1 = 0x0001, */ + + /* AT32_TIM_MODE_CK_CH2 = 0x0002, */ + + /* AT32_TIM_MODE_CK_CH3 = 0x0003, */ + + /* AT32_TIM_MODE_CK_CH4 = 0x0004 */ + + /* Todo: external trigger block */ +} at32_tim_mode_t; + +/* TIM Channel Modes */ + +typedef enum +{ + AT32_TIM_CH_DISABLED = 0x00, + + /* Common configuration */ + + AT32_TIM_CH_POLARITY_POS = 0x00, + AT32_TIM_CH_POLARITY_NEG = 0x01, + + /* MODES: */ + + AT32_TIM_CH_MODE_MASK = 0x06, + + /* Output Compare Modes */ + + AT32_TIM_CH_OUTPWM = 0x04, /* Enable standard PWM mode, active high when counter < compare */ + + /* AT32_TIM_CH_OUTCOMPARE = 0x06, */ + + /* TODO other modes ... as PWM capture, ENCODER and Hall Sensor */ + + /* AT32_TIM_CH_INCAPTURE = 0x10, */ + + /* AT32_TIM_CH_INPWM = 0x20 */ + + /* AT32_TIM_CH_DRIVE_OC -- open collector mode */ +} at32_tim_channel_t; + +/* TIM Operations */ + +struct at32_tim_ops_s +{ + /* Basic Timers */ + + int (*setmode)(struct at32_tim_dev_s *dev, at32_tim_mode_t mode); + int (*setclock)(struct at32_tim_dev_s *dev, uint32_t freq); + void (*setperiod)(struct at32_tim_dev_s *dev, uint32_t period); + uint32_t (*getcounter)(struct at32_tim_dev_s *dev); + void (*setcounter)(struct at32_tim_dev_s *dev, uint32_t count); + + /* General and Advanced Timers Adds */ + + int (*getwidth)(struct at32_tim_dev_s *dev); + int (*setchannel)(struct at32_tim_dev_s *dev, uint8_t channel, + at32_tim_channel_t mode); + int (*setcompare)(struct at32_tim_dev_s *dev, uint8_t channel, + uint32_t compare); + int (*getcapture)(struct at32_tim_dev_s *dev, uint8_t channel); + + /* Timer interrupts */ + + int (*setisr)(struct at32_tim_dev_s *dev, + xcpt_t handler, void * arg, int source); + void (*enableint)(struct at32_tim_dev_s *dev, int source); + void (*disableint)(struct at32_tim_dev_s *dev, int source); + void (*ackint)(struct at32_tim_dev_s *dev, int source); + int (*checkint)(struct at32_tim_dev_s *dev, int source); +}; + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +/* Power-up timer and get its structure */ + +struct at32_tim_dev_s *at32_tim_init(int timer); + +/* Power-down timer, mark it as unused */ + +int at32_tim_deinit(struct at32_tim_dev_s *dev); + +/**************************************************************************** + * Name: at32_timer_initialize + * + * Description: + * Bind the configuration timer to a timer lower half instance and + * register the timer drivers at 'devpath' + * + * Input Parameters: + * devpath - The full path to the timer device. + * This should be of the form /dev/timer0 + * timer - the timer number. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_TIMER +int at32_timer_initialize(const char *devpath, int timer); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_TIM_H */ diff --git a/arch/arm/src/at32/at32_tim_lowerhalf.c b/arch/arm/src/at32/at32_tim_lowerhalf.c new file mode 100644 index 0000000000..a0641ac771 --- /dev/null +++ b/arch/arm/src/at32/at32_tim_lowerhalf.c @@ -0,0 +1,581 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_tim_lowerhalf.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#include "at32_tim.h" + +#if defined(CONFIG_TIMER) && \ + (defined(CONFIG_AT32_TIM1) || defined(CONFIG_AT32_TIM2) || \ + defined(CONFIG_AT32_TIM3) || defined(CONFIG_AT32_TIM4) || \ + defined(CONFIG_AT32_TIM5) || defined(CONFIG_AT32_TIM6) || \ + defined(CONFIG_AT32_TIM7) || defined(CONFIG_AT32_TIM8) || \ + defined(CONFIG_AT32_TIM9) || defined(CONFIG_AT32_TIM10) || \ + defined(CONFIG_AT32_TIM11) || defined(CONFIG_AT32_TIM12) || \ + defined(CONFIG_AT32_TIM13) || defined(CONFIG_AT32_TIM14) || \ + defined(CONFIG_AT32_TIM20)) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define AT32_TIM1_RES 16 + +#define AT32_TIM2_RES 32 + +#define AT32_TIM3_RES 16 +#define AT32_TIM4_RES 16 + +#define AT32_TIM5_RES 32 + +#define AT32_TIM6_RES 16 +#define AT32_TIM7_RES 16 +#define AT32_TIM8_RES 16 +#define AT32_TIM9_RES 16 +#define AT32_TIM10_RES 16 +#define AT32_TIM11_RES 16 +#define AT32_TIM12_RES 16 +#define AT32_TIM13_RES 16 +#define AT32_TIM14_RES 16 +#define AT32_TIM20_RES 16 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure provides the private representation of the "lower-half" + * driver state structure. This structure must be cast-compatible with the + * timer_lowerhalf_s structure. + */ + +struct at32_lowerhalf_s +{ + const struct timer_ops_s *ops; /* Lower half operations */ + struct at32_tim_dev_s *tim; /* at32 timer driver */ + tccb_t callback; /* Current user interrupt callback */ + void *arg; /* Argument passed to upper half callback */ + bool started; /* True: Timer has been started */ + const uint8_t resolution; /* Number of bits in the timer (16 or 32 bits) */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int at32_timer_handler(int irq, void * context, void * arg); + +/* "Lower half" driver methods **********************************************/ + +static int at32_start(struct timer_lowerhalf_s *lower); +static int at32_stop(struct timer_lowerhalf_s *lower); +static int at32_settimeout(struct timer_lowerhalf_s *lower, + uint32_t timeout); +static void at32_setcallback(struct timer_lowerhalf_s *lower, + tccb_t callback, void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* "Lower half" driver methods */ + +static const struct timer_ops_s g_timer_ops = +{ + .start = at32_start, + .stop = at32_stop, + .getstatus = NULL, + .settimeout = at32_settimeout, + .setcallback = at32_setcallback, + .ioctl = NULL, +}; + +#ifdef CONFIG_AT32_TIM1 +static struct at32_lowerhalf_s g_tim1_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM1_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM2 +static struct at32_lowerhalf_s g_tim2_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM2_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM3 +static struct at32_lowerhalf_s g_tim3_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM3_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM4 +static struct at32_lowerhalf_s g_tim4_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM4_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM5 +static struct at32_lowerhalf_s g_tim5_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM5_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM6 +static struct at32_lowerhalf_s g_tim6_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM6_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM7 +static struct at32_lowerhalf_s g_tim7_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM7_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM8 +static struct at32_lowerhalf_s g_tim8_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM8_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM9 +static struct at32_lowerhalf_s g_tim9_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM9_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM10 +static struct at32_lowerhalf_s g_tim10_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM10_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM11 +static struct at32_lowerhalf_s g_tim11_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM11_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM12 +static struct at32_lowerhalf_s g_tim12_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM12_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM13 +static struct at32_lowerhalf_s g_tim13_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM13_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM14 +static struct at32_lowerhalf_s g_tim14_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM14_RES, +}; +#endif + +#ifdef CONFIG_AT32_TIM20 +static struct at32_lowerhalf_s g_tim20_lowerhalf = +{ + .ops = &g_timer_ops, + .resolution = AT32_TIM20_RES, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_timer_handler + * + * Description: + * timer interrupt handler + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +static int at32_timer_handler(int irq, void * context, void * arg) +{ + struct at32_lowerhalf_s *lower = (struct at32_lowerhalf_s *) arg; + uint32_t next_interval_us = 0; + + AT32_TIM_ACKINT(lower->tim, ATIM_DIER_UIE); + + if (lower->callback(&next_interval_us, lower->arg)) + { + if (next_interval_us > 0) + { + AT32_TIM_SETPERIOD(lower->tim, next_interval_us); + } + } + else + { + at32_stop((struct timer_lowerhalf_s *)lower); + } + + return OK; +} + +/**************************************************************************** + * Name: at32_start + * + * Description: + * Start the timer, resetting the time to the current timeout, + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_start(struct timer_lowerhalf_s *lower) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + + if (!priv->started) + { + AT32_TIM_SETMODE(priv->tim, AT32_TIM_MODE_UP); + + if (priv->callback != NULL) + { + AT32_TIM_SETISR(priv->tim, at32_timer_handler, priv, 0); + AT32_TIM_ENABLEINT(priv->tim, ATIM_DIER_UIE); + } + + priv->started = true; + return OK; + } + + /* Return EBUSY to indicate that the timer was already running */ + + return -EBUSY; +} + +/**************************************************************************** + * Name: at32_stop + * + * Description: + * Stop the timer + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_stop(struct timer_lowerhalf_s *lower) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + + if (priv->started) + { + AT32_TIM_SETMODE(priv->tim, AT32_TIM_MODE_DISABLED); + AT32_TIM_DISABLEINT(priv->tim, ATIM_DIER_UIE); + AT32_TIM_SETISR(priv->tim, NULL, NULL, 0); + priv->started = false; + return OK; + } + + /* Return ENODEV to indicate that the timer was not running */ + + return -ENODEV; +} + +/**************************************************************************** + * Name: at32_settimeout + * + * Description: + * Set a new timeout value (and reset the timer) + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * timeout - The new timeout value in microseconds. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_settimeout(struct timer_lowerhalf_s *lower, + uint32_t timeout) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + uint64_t maxtimeout; + + if (priv->started) + { + return -EPERM; + } + + maxtimeout = (1 << priv->resolution) - 1; + if (timeout > maxtimeout) + { + uint64_t freq = (maxtimeout * 1000000) / timeout; + AT32_TIM_SETCLOCK(priv->tim, freq); + AT32_TIM_SETPERIOD(priv->tim, maxtimeout); + } + else + { + AT32_TIM_SETCLOCK(priv->tim, 1000000); + AT32_TIM_SETPERIOD(priv->tim, timeout); + } + + return OK; +} + +/**************************************************************************** + * Name: at32_setcallback + * + * Description: + * Call this user provided timeout callback. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * callback - The new timer expiration function pointer. If this + * function pointer is NULL, then the reset-on-expiration + * behavior is restored, + * arg - Argument that will be provided in the callback + * + * Returned Value: + * The previous timer expiration function pointer or NULL is there was + * no previous function pointer. + * + ****************************************************************************/ + +static void at32_setcallback(struct timer_lowerhalf_s *lower, + tccb_t callback, void *arg) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + + irqstate_t flags = enter_critical_section(); + + /* Save the new callback */ + + priv->callback = callback; + priv->arg = arg; + + if (callback != NULL && priv->started) + { + AT32_TIM_SETISR(priv->tim, at32_timer_handler, priv, 0); + AT32_TIM_ENABLEINT(priv->tim, ATIM_DIER_UIE); + } + else + { + AT32_TIM_DISABLEINT(priv->tim, ATIM_DIER_UIE); + AT32_TIM_SETISR(priv->tim, NULL, NULL, 0); + } + + leave_critical_section(flags); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_timer_initialize + * + * Description: + * Bind the configuration timer to a timer lower half instance and + * register the timer drivers at 'devpath' + * + * Input Parameters: + * devpath - The full path to the timer device. This should be of the + * form /dev/timer0 + * timer - the timer's number. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int at32_timer_initialize(const char *devpath, int timer) +{ + struct at32_lowerhalf_s *lower; + + switch (timer) + { +#ifdef CONFIG_AT32_TIM1 + case 1: + lower = &g_tim1_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM2 + case 2: + lower = &g_tim2_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM3 + case 3: + lower = &g_tim3_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM4 + case 4: + lower = &g_tim4_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM5 + case 5: + lower = &g_tim5_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM6 + case 6: + lower = &g_tim6_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM7 + case 7: + lower = &g_tim7_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM8 + case 8: + lower = &g_tim8_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM9 + case 9: + lower = &g_tim9_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM10 + case 10: + lower = &g_tim10_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM11 + case 11: + lower = &g_tim11_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM12 + case 12: + lower = &g_tim12_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM13 + case 13: + lower = &g_tim13_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM14 + case 14: + lower = &g_tim14_lowerhalf; + break; +#endif +#ifdef CONFIG_AT32_TIM20 + case 20: + lower = &g_tim20_lowerhalf; + break; +#endif + default: + return -ENODEV; + } + + /* Initialize the elements of lower half state structure */ + + lower->started = false; + lower->callback = NULL; + lower->tim = at32_tim_init(timer); + + if (lower->tim == NULL) + { + return -EINVAL; + } + + /* Register the timer driver as /dev/timerX. The returned value from + * timer_register is a handle that could be used with timer_unregister(). + * REVISIT: The returned handle is discard here. + */ + + void *drvr = timer_register(devpath, + (struct timer_lowerhalf_s *)lower); + if (drvr == NULL) + { + /* The actual cause of the failure may have been a failure to allocate + * perhaps a failure to register the timer driver (such as if the + * 'depath' were not unique). We know here but we return EEXIST to + * indicate the failure (implying the non-unique devpath). + */ + + return -EEXIST; + } + + return OK; +} + +#endif /* CONFIG_TIMER */ diff --git a/arch/arm/src/at32/at32_timerisr.c b/arch/arm/src/at32/at32_timerisr.c new file mode 100644 index 0000000000..d4969caa77 --- /dev/null +++ b/arch/arm/src/at32/at32_timerisr.c @@ -0,0 +1,153 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_timerisr.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "nvic.h" +#include "clock/clock.h" +#include "arm_internal.h" +#include "systick.h" + +#include "chip.h" +#include "at32.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The desired timer interrupt frequency is provided by the definition + * CLK_TCK (see include/time.h). CLK_TCK defines the desired number of + * system clock ticks per second. That value is a user configurable setting + * that defaults to 100 (100 ticks per second = 10 MS interval). + * + * The RCC feeds the Cortex System Timer (SysTick) with the AHB clock (HCLK) + * divided by 8. The SysTick can work either with this clock or with the + * Cortex clock (HCLK), configurable in the SysTick Control and Status + * register. + */ + +#undef CONFIG_AT32_SYSTICK_HCLKd8 /* Power up default is HCLK, not HCLK/8 */ + /* And I don't know now to re-configure it yet */ + +#ifdef CONFIG_AT32_SYSTICK_HCLKd8 +# define SYSTICK_RELOAD ((AT32_HCLK_FREQUENCY / 8 / CLK_TCK) - 1) +#else +# define SYSTICK_RELOAD ((AT32_HCLK_FREQUENCY / CLK_TCK) - 1) +#endif + +/* The size of the reload field is 24 bits. Verify that the reload value + * will fit in the reload register. + */ + +#if SYSTICK_RELOAD > 0x00ffffff +# error SYSTICK_RELOAD exceeds the range of the RELOAD register +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: at32_timerisr + * + * Description: + * The timer ISR will perform a variety of services for various portions + * of the systems. + * + ****************************************************************************/ + +#if !defined(CONFIG_ARMV7M_SYSTICK) && !defined(CONFIG_TIMER_ARCH) +static int at32_timerisr(int irq, uint32_t *regs, void *arg) +{ + /* Process timer interrupt */ + + nxsched_process_timer(); + return 0; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: up_timer_initialize + * + * Description: + * This function is called during start-up to initialize + * the timer interrupt. + * + ****************************************************************************/ + +void up_timer_initialize(void) +{ + uint32_t regval; + + /* Set the SysTick interrupt to the default priority */ + + regval = getreg32(NVIC_SYSH12_15_PRIORITY); + regval &= ~NVIC_SYSH_PRIORITY_PR15_MASK; + regval |= (NVIC_SYSH_PRIORITY_DEFAULT << NVIC_SYSH_PRIORITY_PR15_SHIFT); + putreg32(regval, NVIC_SYSH12_15_PRIORITY); + + /* Make sure that the SYSTICK clock source is set correctly */ + +#if 0 /* Does not work. Comes up with HCLK source and I can't change it */ + regval = getreg32(NVIC_SYSTICK_CTRL); +#ifdef CONFIG_AT32_SYSTICK_HCLKd8 + regval &= ~NVIC_SYSTICK_CTRL_CLKSOURCE; +#else + regval |= NVIC_SYSTICK_CTRL_CLKSOURCE; +#endif + putreg32(regval, NVIC_SYSTICK_CTRL); +#endif + +#if defined(CONFIG_ARMV7M_SYSTICK) && defined(CONFIG_TIMER_ARCH) + up_timer_set_lowerhalf(systick_initialize(true, AT32_HCLK_FREQUENCY, -1)); +#else + /* Configure SysTick to interrupt at the requested rate */ + + putreg32(SYSTICK_RELOAD, NVIC_SYSTICK_RELOAD); + + /* Attach the timer interrupt vector */ + + irq_attach(AT32_IRQ_SYSTICK, (xcpt_t)at32_timerisr, NULL); + + /* Enable SysTick interrupts */ + + putreg32((NVIC_SYSTICK_CTRL_CLKSOURCE | NVIC_SYSTICK_CTRL_TICKINT | + NVIC_SYSTICK_CTRL_ENABLE), NVIC_SYSTICK_CTRL); + + /* And enable the timer interrupt */ + + up_enable_irq(AT32_IRQ_SYSTICK); +#endif +} diff --git a/arch/arm/src/at32/at32_uart.h b/arch/arm/src/at32/at32_uart.h new file mode 100644 index 0000000000..237984c34c --- /dev/null +++ b/arch/arm/src/at32/at32_uart.h @@ -0,0 +1,592 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_uart.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_STC_AT32_AT32_UART_H +#define __ARCH_ARM_STC_AT32_AT32_UART_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "chip.h" + +#if defined(CONFIG_AT32_AT32F43XX) +# include "hardware/at32f43xxx_uart.h" +#else +# error "Unsupported AT32 UART" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Make sure that we have not enabled more U[S]ARTs than are supported by the + * device. + */ + +#if AT32_NUSART < 8 || !defined(CONFIG_AT32_HAVE_UART8) +# undef CONFIG_AT32_UART8 +#endif +#if AT32_NUSART < 7 || !defined(CONFIG_AT32_HAVE_UART7) +# undef CONFIG_AT32_UART7 +#endif +#if AT32_NUSART < 6 || !defined(CONFIG_AT32_HAVE_USART6) +# undef CONFIG_AT32_USART6 +#endif +#if AT32_NUSART < 5 || !defined(CONFIG_AT32_HAVE_UART5) +# undef CONFIG_AT32_UART5 +#endif +#if AT32_NUSART < 4 || !defined(CONFIG_AT32_HAVE_UART4) +# undef CONFIG_AT32_UART4 +#endif +#if AT32_NUSART < 3 || !defined(CONFIG_AT32_HAVE_USART3) +# undef CONFIG_AT32_USART3 +#endif +#if AT32_NUSART < 2 +# undef CONFIG_AT32_USART2 +#endif +#if AT32_NUSART < 1 +# undef CONFIG_AT32_USART1 +#endif + +/* Sanity checks */ + +#if !defined(CONFIG_AT32_USART1) +# undef CONFIG_AT32_USART1_SERIALDRIVER +# undef CONFIG_AT32_USART1_1WIREDRIVER +#endif +#if !defined(CONFIG_AT32_USART2) +# undef CONFIG_AT32_USART2_SERIALDRIVER +# undef CONFIG_AT32_USART2_1WIREDRIVER +#endif +#if !defined(CONFIG_AT32_USART3) +# undef CONFIG_AT32_USART3_SERIALDRIVER +# undef CONFIG_AT32_USART3_1WIREDRIVER +#endif +#if !defined(CONFIG_AT32_UART4) +# undef CONFIG_AT32_UART4_SERIALDRIVER +# undef CONFIG_AT32_UART4_1WIREDRIVER +#endif +#if !defined(CONFIG_AT32_UART5) +# undef CONFIG_AT32_UART5_SERIALDRIVER +# undef CONFIG_AT32_UART5_1WIREDRIVER +#endif +#if !defined(CONFIG_AT32_USART6) +# undef CONFIG_AT32_USART6_SERIALDRIVER +# undef CONFIG_AT32_USART6_1WIREDRIVER +#endif +#if !defined(CONFIG_AT32_UART7) +# undef CONFIG_AT32_UART7_SERIALDRIVER +# undef CONFIG_AT32_UART7_1WIREDRIVER +#endif +#if !defined(CONFIG_AT32_UART8) +# undef CONFIG_AT32_UART8_SERIALDRIVER +# undef CONFIG_AT32_UART8_1WIREDRIVER +#endif + +/* Check 1-Wire and U(S)ART conflicts */ + +#if defined(CONFIG_AT32_USART1_1WIREDRIVER) && defined(CONFIG_AT32_USART1_SERIALDRIVER) +# error Both CONFIG_AT32_USART1_1WIREDRIVER and CONFIG_AT32_USART1_SERIALDRIVER defined +# undef CONFIG_AT32_USART1_1WIREDRIVER +#endif +#if defined(CONFIG_AT32_USART2_1WIREDRIVER) && defined(CONFIG_AT32_USART2_SERIALDRIVER) +# error Both CONFIG_AT32_USART2_1WIREDRIVER and CONFIG_AT32_USART2_SERIALDRIVER defined +# undef CONFIG_AT32_USART2_1WIREDRIVER +#endif +#if defined(CONFIG_AT32_USART3_1WIREDRIVER) && defined(CONFIG_AT32_USART3_SERIALDRIVER) +# error Both CONFIG_AT32_USART3_1WIREDRIVER and CONFIG_AT32_USART3_SERIALDRIVER defined +# undef CONFIG_AT32_USART3_1WIREDRIVER +#endif +#if defined(CONFIG_AT32_UART4_1WIREDRIVER) && defined(CONFIG_AT32_UART4_SERIALDRIVER) +# error Both CONFIG_AT32_UART4_1WIREDRIVER and CONFIG_AT32_UART4_SERIALDRIVER defined +# undef CONFIG_AT32_UART4_1WIREDRIVER +#endif +#if defined(CONFIG_AT32_UART5_1WIREDRIVER) && defined(CONFIG_AT32_UART5_SERIALDRIVER) +# error Both CONFIG_AT32_UART5_1WIREDRIVER and CONFIG_AT32_UART5_SERIALDRIVER defined +# undef CONFIG_AT32_UART5_1WIREDRIVER +#endif +#if defined(CONFIG_AT32_USART6_1WIREDRIVER) && defined(CONFIG_AT32_USART6_SERIALDRIVER) +# error Both CONFIG_AT32_USART6_1WIREDRIVER and CONFIG_AT32_USART6_SERIALDRIVER defined +# undef CONFIG_AT32_USART6_1WIREDRIVER +#endif +#if defined(CONFIG_AT32_UART7_1WIREDRIVER) && defined(CONFIG_AT32_UART7_SERIALDRIVER) +# error Both CONFIG_AT32_UART7_1WIREDRIVER and CONFIG_AT32_UART7_SERIALDRIVER defined +# undef CONFIG_AT32_UART7_1WIREDRIVER +#endif +#if defined(CONFIG_AT32_UART8_1WIREDRIVER) && defined(CONFIG_AT32_UART8_SERIALDRIVER) +# error Both CONFIG_AT32_UART8_1WIREDRIVER and CONFIG_AT32_UART8_SERIALDRIVER defined +# undef CONFIG_AT32_UART8_1WIREDRIVER +#endif + +/* Is the serial driver enabled? */ + +#if defined(CONFIG_AT32_USART1_SERIALDRIVER) || defined(CONFIG_AT32_USART2_SERIALDRIVER) || \ + defined(CONFIG_AT32_USART3_SERIALDRIVER) || defined(CONFIG_AT32_UART4_SERIALDRIVER) || \ + defined(CONFIG_AT32_UART5_SERIALDRIVER) || defined(CONFIG_AT32_USART6_SERIALDRIVER) || \ + defined(CONFIG_AT32_UART7_SERIALDRIVER) || defined(CONFIG_AT32_UART8_SERIALDRIVER) +# define HAVE_SERIALDRIVER 1 +#endif + +/* Is the 1-Wire driver? */ + +#if defined(CONFIG_AT32_USART1_1WIREDRIVER) || defined(CONFIG_AT32_USART2_1WIREDRIVER) || \ + defined(CONFIG_AT32_USART3_1WIREDRIVER) || defined(CONFIG_AT32_UART4_1WIREDRIVER) || \ + defined(CONFIG_AT32_UART5_1WIREDRIVER) || defined(CONFIG_AT32_USART6_1WIREDRIVER) || \ + defined(CONFIG_AT32_UART7_1WIREDRIVER) || defined(CONFIG_AT32_UART8_1WIREDRIVER) +# define HAVE_1WIREDRIVER 1 +#endif + +/* Is there a serial console? */ + +#if defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_AT32_USART1_SERIALDRIVER) +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# define CONSOLE_UART 1 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_AT32_USART2_SERIALDRIVER) +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# define CONSOLE_UART 2 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_AT32_USART3_SERIALDRIVER) +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# define CONSOLE_UART 3 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_AT32_UART4_SERIALDRIVER) +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# define CONSOLE_UART 4 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_UART5_SERIAL_CONSOLE) && defined(CONFIG_AT32_UART5_SERIALDRIVER) +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# define CONSOLE_UART 5 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_AT32_USART6_SERIALDRIVER) +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# define CONSOLE_UART 6 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_UART7_SERIAL_CONSOLE) && defined(CONFIG_AT32_UART7_SERIALDRIVER) +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# define CONSOLE_UART 7 +# define HAVE_CONSOLE 1 +#elif defined(CONFIG_UART8_SERIAL_CONSOLE) && defined(CONFIG_AT32_UART8_SERIALDRIVER) +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# define CONSOLE_UART 8 +# define HAVE_CONSOLE 1 +#else +# undef CONFIG_USART1_SERIAL_CONSOLE +# undef CONFIG_USART2_SERIAL_CONSOLE +# undef CONFIG_USART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_USART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# undef CONFIG_UART8_SERIAL_CONSOLE +# define CONSOLE_UART 0 +# undef HAVE_CONSOLE +#endif + +/* DMA support is only provided if CONFIG_ARCH_DMA is in the + * NuttX configuration + */ + +#if !defined(HAVE_SERIALDRIVER) || !defined(CONFIG_ARCH_DMA) +# undef CONFIG_USART1_RXDMA +# undef CONFIG_USART1_TXDMA +# undef CONFIG_USART2_RXDMA +# undef CONFIG_USART2_TXDMA +# undef CONFIG_USART3_RXDMA +# undef CONFIG_USART3_TXDMA +# undef CONFIG_UART4_RXDMA +# undef CONFIG_UART4_TXDMA +# undef CONFIG_UART5_RXDMA +# undef CONFIG_UART5_TXDMA +# undef CONFIG_USART6_RXDMA +# undef CONFIG_USART6_TXDMA +# undef CONFIG_UART7_RXDMA +# undef CONFIG_UART7_TXDMA +# undef CONFIG_UART8_RXDMA +# undef CONFIG_UART8_TXDMA +#endif + +/* Disable the DMA configuration on all unused USARTs */ + +#ifndef CONFIG_AT32_USART1_SERIALDRIVER +# undef CONFIG_USART1_RXDMA +# undef CONFIG_USART1_TXDMA +#endif + +#ifndef CONFIG_AT32_USART2_SERIALDRIVER +# undef CONFIG_USART2_RXDMA +# undef CONFIG_USART2_TXDMA +#endif + +#ifndef CONFIG_AT32_USART3_SERIALDRIVER +# undef CONFIG_USART3_RXDMA +# undef CONFIG_USART3_TXDMA +#endif + +#ifndef CONFIG_AT32_UART4_SERIALDRIVER +# undef CONFIG_UART4_RXDMA +# undef CONFIG_UART4_TXDMA +#endif + +#ifndef CONFIG_AT32_UART5_SERIALDRIVER +# undef CONFIG_UART5_RXDMA +# undef CONFIG_UART5_TXDMA +#endif + +#ifndef CONFIG_AT32_USART6_SERIALDRIVER +# undef CONFIG_USART6_RXDMA +# undef CONFIG_USART6_TXDMA +#endif + +#ifndef CONFIG_AT32_UART7_SERIALDRIVER +# undef CONFIG_UART7_RXDMA +# undef CONFIG_UART7_TXDMA +#endif + +#ifndef CONFIG_AT32_UART8_SERIALDRIVER +# undef CONFIG_UART8_RXDMA +# undef CONFIG_UART8_TXDMA +#endif + +/* Is DMA available on any (enabled) USART? */ + +#undef SERIAL_HAVE_RXDMA +#if defined(CONFIG_USART1_RXDMA) || defined(CONFIG_USART2_RXDMA) || \ + defined(CONFIG_USART3_RXDMA) || defined(CONFIG_UART4_RXDMA) || \ + defined(CONFIG_UART5_RXDMA) || defined(CONFIG_USART6_RXDMA) || \ + defined(CONFIG_UART7_RXDMA) || defined(CONFIG_UART8_RXDMA) +# define SERIAL_HAVE_RXDMA 1 +#endif + +/* Is TX DMA available on any (enabled) USART? */ + +#undef SERIAL_HAVE_TXDMA +#if defined(CONFIG_USART1_TXDMA) || defined(CONFIG_USART2_TXDMA) || \ + defined(CONFIG_USART3_TXDMA) || defined(CONFIG_UART4_TXDMA) || \ + defined(CONFIG_UART5_TXDMA) || defined(CONFIG_USART6_TXDMA) || \ + defined(CONFIG_UART7_TXDMA) || defined(CONFIG_UART8_TXDMA) +# define SERIAL_HAVE_TXDMA 1 +#endif + +/* Is RX DMA used on the console UART? */ + +#undef SERIAL_HAVE_CONSOLE_RXDMA +#if defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_USART1_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_USART2_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_USART3_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +#elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_UART4_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +#elif defined(CONFIG_UART5_SERIAL_CONSOLE) && defined(CONFIG_UART5_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_USART6_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +#elif defined(CONFIG_UART7_SERIAL_CONSOLE) && defined(CONFIG_UART7_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +#elif defined(CONFIG_UART8_SERIAL_CONSOLE) && defined(CONFIG_UART8_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +#endif + +/* Is TX DMA used on the console UART? */ + +#undef SERIAL_HAVE_CONSOLE_TXDMA +#if defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_USART1_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_USART2_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_USART3_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_UART4_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_UART5_SERIAL_CONSOLE) && defined(CONFIG_UART5_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_USART6_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_UART7_SERIAL_CONSOLE) && defined(CONFIG_UART7_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_UART8_SERIAL_CONSOLE) && defined(CONFIG_UART8_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#endif + +/* Is RX DMA used on all (enabled) USARTs */ + +#define SERIAL_HAVE_ONLY_RXDMA 1 +#if defined(CONFIG_AT32_USART1) && !defined(CONFIG_USART1_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_AT32_USART2) && !defined(CONFIG_USART2_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_AT32_USART3) && !defined(CONFIG_USART3_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_AT32_UART4) && !defined(CONFIG_UART4_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_AT32_UART5) && !defined(CONFIG_UART5_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_AT32_USART6) && !defined(CONFIG_USART6_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_AT32_UART7) && !defined(CONFIG_UART7_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_AT32_UART8) && !defined(CONFIG_UART8_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#endif + +/* Is TX DMA used on all (enabled) USARTs */ + +#define SERIAL_HAVE_ONLY_TXDMA 1 +#if defined(CONFIG_AT32_USART1) && !defined(CONFIG_USART1_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_AT32_USART2) && !defined(CONFIG_USART2_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_AT32_USART3) && !defined(CONFIG_USART3_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_AT32_UART4) && !defined(CONFIG_UART4_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_AT32_UART5) && !defined(CONFIG_UART5_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_AT32_USART6) && !defined(CONFIG_USART6_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_AT32_UART7) && !defined(CONFIG_UART7_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_AT32_UART8) && !defined(CONFIG_UART8_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#endif + +#undef SERIAL_HAVE_ONLY_DMA +#if defined(SERIAL_HAVE_ONLY_RXDMA) && defined(SERIAL_HAVE_ONLY_TXDMA) +# define SERIAL_HAVE_ONLY_DMA 1 +#endif + +/* No DMA ops */ + +#undef SERIAL_HAVE_NODMA_OPS +#if defined(CONFIG_AT32_USART1) && !defined(CONFIG_USART1_RXDMA) && \ + !defined(CONFIG_USART1_TXDMA) +# define SERIAL_HAVE_NODMA_OPS +#elif defined(CONFIG_AT32_USART2) && !defined(CONFIG_USART2_RXDMA) && \ + !defined(CONFIG_USART2_TXDMA) +# define SERIAL_HAVE_NODMA_OPS +#elif defined(CONFIG_AT32_USART3) && !defined(CONFIG_USART3_RXDMA) && \ + !defined(CONFIG_USART3_TXDMA) +# define SERIAL_HAVE_NODMA_OPS +#elif defined(CONFIG_AT32_UART4) && !defined(CONFIG_UART4_RXDMA) && \ + !defined(CONFIG_UART4_TXDMA) +# define SERIAL_HAVE_NODMA_OPS +#elif defined(CONFIG_AT32_UART5) && !defined(CONFIG_UART5_RXDMA) && \ + !defined(CONFIG_UART5_TXDMA) +# define SERIAL_HAVE_NODMA_OPS +#elif defined(CONFIG_AT32_USART6) && !defined(CONFIG_USART6_RXDMA) && \ + !defined(CONFIG_USART6_TXDMA) +# define SERIAL_HAVE_NODMA_OPS +#elif defined(CONFIG_AT32_UART7) && !defined(CONFIG_UART7_RXDMA) && \ + !defined(CONFIG_UART7_TXDMA) +# define SERIAL_HAVE_NODMA_OPS +#elif defined(CONFIG_AT32_UART8) && !defined(CONFIG_UART8_RXDMA) && \ + !defined(CONFIG_UART8_TXDMA) +# define SERIAL_HAVE_NODMA_OPS +#endif + +/* RX+TX DMA ops */ + +#undef SERIAL_HAVE_RXTXDMA_OPS +#if defined(CONFIG_USART1_RXDMA) && defined(CONFIG_USART1_TXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_USART2_RXDMA) && defined(CONFIG_USART2_TXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_USART3_RXDMA) && defined(CONFIG_USART3_TXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_UART4_RXDMA) && defined(CONFIG_UART4_TXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_UART5_RXDMA) && defined(CONFIG_UART5_TXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_USART6_RXDMA) && defined(CONFIG_USART6_TXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_UART7_RXDMA) && defined(CONFIG_UART7_TXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_UART8_RXDMA) && defined(CONFIG_UART8_TXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#endif + +/* TX DMA ops */ + +#undef SERIAL_HAVE_TXDMA_OPS +#if !defined(CONFIG_USART1_RXDMA) && defined(CONFIG_USART1_TXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_USART2_RXDMA) && defined(CONFIG_USART2_TXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_USART3_RXDMA) && defined(CONFIG_USART3_TXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_UART4_RXDMA) && defined(CONFIG_UART4_TXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_UART5_RXDMA) && defined(CONFIG_UART5_TXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_USART6_RXDMA) && defined(CONFIG_USART6_TXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_UART7_RXDMA) && defined(CONFIG_UART7_TXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_UART8_RXDMA) && defined(CONFIG_UART8_TXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#endif + +/* RX DMA ops */ + +#undef SERIAL_HAVE_RXDMA_OPS +#if defined(CONFIG_USART1_RXDMA) && !defined(CONFIG_USART1_TXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#elif defined(CONFIG_USART2_RXDMA) && !defined(CONFIG_USART2_TXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#elif defined(CONFIG_USART3_RXDMA) && !defined(CONFIG_USART3_TXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#elif defined(CONFIG_UART4_RXDMA) && !defined(CONFIG_UART4_TXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#elif defined(CONFIG_UART5_RXDMA) && !defined(CONFIG_UART5_TXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#elif defined(CONFIG_USART6_RXDMA) && !defined(CONFIG_USART6_TXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#elif defined(CONFIG_UART7_RXDMA) && !defined(CONFIG_UART7_TXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#elif defined(CONFIG_UART8_RXDMA) && !defined(CONFIG_UART8_TXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#endif + +/* Is RS-485 used? */ + +#if defined(CONFIG_USART1_RS485) || defined(CONFIG_USART2_RS485) || \ + defined(CONFIG_USART3_RS485) || defined(CONFIG_UART4_RS485) || \ + defined(CONFIG_UART5_RS485) || defined(CONFIG_USART6_RS485) || \ + defined(CONFIG_UART7_RS485) || defined(CONFIG_UART8_RS485) +# define HAVE_RS485 1 +#endif + +#ifdef HAVE_RS485 +# define USART_CR1_USED_INTS (USART_CTRL1_RDBFIEN | USART_CTRL1_TDBEIEN | USART_CTRL1_PERRIEN | USART_CTRL1_TDCIEN) +#else +# define USART_CR1_USED_INTS (USART_CTRL1_RDBFIEN | USART_CTRL1_TDBEIEN | USART_CTRL1_PERRIEN) +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_serial_get_uart + * + * Description: + * Get serial driver structure for AT32 USART + * + ****************************************************************************/ + +uart_dev_t *at32_serial_get_uart(int uart_num); + +/**************************************************************************** + * Name: at32_serial_dma_poll + * + * Description: + * Must be called periodically if any AT32 UART is configured for DMA. + * The DMA callback is triggered for each fifo size/2 bytes, but this can + * result in some bytes being transferred but not collected if the incoming + * data is not a whole multiple of half the FIFO size. + * + * May be safely called from either interrupt or thread context. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +void at32_serial_dma_poll(void); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_STC_AT32_AT32_UART_H */ diff --git a/arch/arm/src/at32/at32_uid.c b/arch/arm/src/at32/at32_uid.c new file mode 100644 index 0000000000..2bc2e50ddf --- /dev/null +++ b/arch/arm/src/at32/at32_uid.c @@ -0,0 +1,46 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_uid.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "hardware/at32_memorymap.h" +#include "at32_uid.h" + +#ifdef AT32_SYSMEM_UID + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void at32_get_uniqueid(uint8_t uniqueid[12]) +{ + int i; + + for (i = 0; i < 12; i++) + { + uniqueid[i] = *((uint8_t *)(AT32_SYSMEM_UID) + i); + } +} + +#endif /* AT32_SYSMEM_UID */ diff --git a/arch/arm/src/at32/at32_uid.h b/arch/arm/src/at32/at32_uid.h new file mode 100644 index 0000000000..1e225d5cb5 --- /dev/null +++ b/arch/arm/src/at32/at32_uid.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_uid.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_UID_H +#define __ARCH_ARM_SRC_AT32_AT32_UID_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +void at32_get_uniqueid(uint8_t uniqueid[12]); + +#endif /* __ARCH_ARM_SRC_AT32_AT32_UID_H */ diff --git a/arch/arm/src/at32/at32_usbhost.c b/arch/arm/src/at32/at32_usbhost.c new file mode 100644 index 0000000000..29e779c90e --- /dev/null +++ b/arch/arm/src/at32/at32_usbhost.c @@ -0,0 +1,415 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_usbhost.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "at32_usbhost.h" + +#ifdef HAVE_USBHOST_TRACE + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define TR_FMT1 false +#define TR_FMT2 true + +#define TRENTRY(id,fmt1,string) {string} + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct at32_usbhost_trace_s +{ +#if 0 + uint16_t id; + bool fmt2; +#endif + const char *string; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct at32_usbhost_trace_s g_trace1[TRACE1_NSTRINGS] = +{ +#ifdef CONFIG_AT32_OTGFS + + TRENTRY(OTGFS_TRACE1_DEVDISCONN, + TR_FMT1, + "OTGFS ERROR: Host Port %d. Device disconnected\n"), + TRENTRY(OTGFS_TRACE1_IRQATTACH, + TR_FMT1, + "OTGFS ERROR: Failed to attach IRQ\n"), + TRENTRY(OTGFS_TRACE1_TRNSFRFAILED, + TR_FMT1, + "OTGFS ERROR: Transfer Failed. ret=%d\n"), + TRENTRY(OTGFS_TRACE1_SENDSETUP, + TR_FMT1, + "OTGFS ERROR: ctrl_sendsetup() failed with: %d\n"), + TRENTRY(OTGFS_TRACE1_SENDDATA, + TR_FMT1, + "OTGFS ERROR: ctrl_senddata() failed with: %d\n"), + TRENTRY(OTGFS_TRACE1_RECVDATA, + TR_FMT1, + "OTGFS ERROR: ctrl_recvdata() failed with: %d\n"), + +# ifdef HAVE_USBHOST_TRACE_VERBOSE + + TRENTRY(OTGFS_VTRACE1_CONNECTED, + TR_FMT1, + "OTGFS Host Port %d connected.\n"), + TRENTRY(OTGFS_VTRACE1_DISCONNECTED, + TR_FMT1, + "OTGFS Host Port %d disconnected.\n"), + TRENTRY(OTGFS_VTRACE1_GINT, + TR_FMT1, + "OTGFS Handling Interrupt. Entry Point.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_SOF, + TR_FMT1, + "OTGFS Handle the start of frame interrupt.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_RXFLVL, + TR_FMT1, + "OTGFS Handle the RxFIFO non-empty interrupt.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_NPTXFE, + TR_FMT1, + "OTGFS Handle the non-periodic TxFIFO empty interrupt.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_PTXFE, + TR_FMT1, + "OTGFS Handle the periodic TxFIFO empty interrupt.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_HC, + TR_FMT1, + "OTGFS Handle the host channels interrupt.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_HPRT, + TR_FMT1, + "OTGFS Handle the host port interrupt.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_HPRT_POCCHNG, + TR_FMT1, + "OTGFS HPRT: Port Over-Current Change.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_HPRT_PCDET, + TR_FMT1, + "OTGFS HPRT: Port Connect Detect.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_HPRT_PENCHNG, + TR_FMT1, + "OTGFS HPRT: Port Enable Changed.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_HPRT_LSDEV, + TR_FMT1, + "OTGFS HPRT: Low Speed Device Connected.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_HPRT_FSDEV, + TR_FMT1, + "OTGFS HPRT: Full Speed Device Connected.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_HPRT_LSFSSW, + TR_FMT1, + "OTGFS HPRT: Host Switch: LS -> FS.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_HPRT_FSLSSW, + TR_FMT1, + "OTGFS HPRT: Host Switch: FS -> LS.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_DISC, + TR_FMT1, + "OTGFS Handle the disconnect detected interrupt.\n"), + TRENTRY(OTGFS_VTRACE1_GINT_IPXFR, + TR_FMT1, + "OTGFS Handle the incomplete periodic transfer.\n"), + +# endif +#endif + +#ifdef CONFIG_AT32_OTGHS + + TRENTRY(OTGHS_TRACE1_DEVDISCONN, + TR_FMT1, + "OTGHS ERROR: Host Port %d. Device disconnected\n"), + TRENTRY(OTGHS_TRACE1_IRQATTACH, + TR_FMT1, + "OTGHS ERROR: Failed to attach IRQ\n"), + TRENTRY(OTGHS_TRACE1_TRNSFRFAILED, + TR_FMT1, + "OTGHS ERROR: Transfer Failed. ret=%d\n"), + TRENTRY(OTGHS_TRACE1_SENDSETUP, + TR_FMT1, + "OTGHS ERROR: ctrl_sendsetup() failed with: %d\n"), + TRENTRY(OTGHS_TRACE1_SENDDATA, + TR_FMT1, + "OTGHS ERROR: ctrl_senddata() failed with: %d\n"), + TRENTRY(OTGHS_TRACE1_RECVDATA, + TR_FMT1, + "OTGHS ERROR: ctrl_recvdata() failed with: %d\n"), + +# ifdef HAVE_USBHOST_TRACE_VERBOSE + + TRENTRY(OTGHS_VTRACE1_CONNECTED, + TR_FMT1, + "OTGHS Host Port %d connected.\n"), + TRENTRY(OTGHS_VTRACE1_DISCONNECTED, + TR_FMT1, + "OTGHS Host Port %d disconnected.\n"), + TRENTRY(OTGHS_VTRACE1_GINT, + TR_FMT1, + "OTGHS Handling Interrupt. Entry Point.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_SOF, + TR_FMT1, + "OTGHS Handle the start of frame interrupt.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_RXFLVL, + TR_FMT1, + "OTGHS Handle the RxFIFO non-empty interrupt.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_NPTXFE, + TR_FMT1, + "OTGHS Handle the non-periodic TxFIFO empty interrupt.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_PTXFE, + TR_FMT1, + "OTGHS Handle the periodic TxFIFO empty interrupt.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_HC, + TR_FMT1, + "OTGHS Handle the host channels interrupt.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_HPRT, + TR_FMT1, + "OTGHS Handle the host port interrupt.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_HPRT_POCCHNG, + TR_FMT1, + "OTGHS HPRT: Port Over-Current Change.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_HPRT_PCDET, + TR_FMT1, + "OTGHS HPRT: Port Connect Detect.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_HPRT_PENCHNG, + TR_FMT1, + "OTGHS HPRT: Port Enable Changed.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_HPRT_LSDEV, + TR_FMT1, + "OTGHS HPRT: Low Speed Device Connected.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_HPRT_HSDEV, + TR_FMT1, + "OTGHS HPRT: Full Speed Device Connected.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_HPRT_LSHSSW, + TR_FMT1, + "OTGHS HPRT: Host Switch: LS -> HS.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_HPRT_HSLSSW, + TR_FMT1, + "OTGHS HPRT: Host Switch: HS -> LS.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_DISC, + TR_FMT1, + "OTGHS Handle the disconnect detected interrupt.\n"), + TRENTRY(OTGHS_VTRACE1_GINT_IPXFR, + TR_FMT1, + "OTGHS Handle the incomplete periodic transfer.\n"), +# endif +#endif +}; + +static const struct at32_usbhost_trace_s g_trace2[TRACE2_NSTRINGS] = +{ +#ifdef CONFIG_AT32_OTGFS + + TRENTRY(OTGFS_TRACE2_CLIP, + TR_FMT2, + "OTGFS CLIP: chidx: %d buflen: %d\n"), + +# ifdef HAVE_USBHOST_TRACE_VERBOSE + TRENTRY(OTGFS_VTRACE2_CHANWAKEUP_IN, + TR_FMT2, + "OTGFS EP%d(IN) wake up with result: %d\n"), + TRENTRY(OTGFS_VTRACE2_CHANWAKEUP_OUT, + TR_FMT2, + "OTGFS EP%d(OUT) wake up with result: %d\n"), + TRENTRY(OTGFS_VTRACE2_CTRLIN, + TR_FMT2, + "OTGFS CTRL_IN type: %02x req: %02x\n"), + TRENTRY(OTGFS_VTRACE2_CTRLOUT, + TR_FMT2, + "OTGFS CTRL_OUT type: %02x req: %02x\n"), + TRENTRY(OTGFS_VTRACE2_INTRIN, + TR_FMT2, + "OTGFS INTR_IN chidx: %02x len: %02x\n"), + TRENTRY(OTGFS_VTRACE2_INTROUT, + TR_FMT2, + "OTGFS INTR_OUT chidx: %02x len: %02x\n"), + TRENTRY(OTGFS_VTRACE2_BULKIN, + TR_FMT2, + "OTGFS BULK_IN chidx: %02x len: %02x\n"), + TRENTRY(OTGFS_VTRACE2_BULKOUT, + TR_FMT2, + "OTGFS BULK_OUT chidx: %02x len: %02x\n"), + TRENTRY(OTGFS_VTRACE2_ISOCIN, + TR_FMT2, + "OTGFS ISOC_IN chidx: %02x len: %04d\n"), + TRENTRY(OTGFS_VTRACE2_ISOCOUT, + TR_FMT2, + "OTGFS ISOC_OUT chidx: %02x req: %02x\n"), + TRENTRY(OTGFS_VTRACE2_STARTTRANSFER, + TR_FMT2, + "OTGFS Transfer chidx: %d buflen: %d\n"), + TRENTRY(OTGFS_VTRACE2_CHANCONF_CTRL_IN, + TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,IN ,CTRL)\n"), + TRENTRY(OTGFS_VTRACE2_CHANCONF_CTRL_OUT, + TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,OUT,CTRL)\n"), + TRENTRY(OTGFS_VTRACE2_CHANCONF_INTR_IN, + TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,IN ,INTR)\n"), + TRENTRY(OTGFS_VTRACE2_CHANCONF_INTR_OUT, + TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,OUT,INTR)\n"), + TRENTRY(OTGFS_VTRACE2_CHANCONF_BULK_IN, + TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,IN ,BULK)\n"), + TRENTRY(OTGFS_VTRACE2_CHANCONF_BULK_OUT, + TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,OUT,BULK)\n"), + TRENTRY(OTGFS_VTRACE2_CHANCONF_ISOC_IN, + TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,IN ,ISOC)\n"), + TRENTRY(OTGFS_VTRACE2_CHANCONF_ISOC_OUT, + TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,OUT,ISOC)\n"), + TRENTRY(OTGFS_VTRACE2_CHANHALT, + TR_FMT2, + "OTGFS Channel halted. chidx: %d, reason: %d\n"), + +# endif +#endif +#ifdef CONFIG_AT32_OTGHS + + TRENTRY(OTGHS_TRACE2_CLIP, + TR_FMT2, + "OTGHS CLIP: chidx: %d buflen: %d\n"), + +# ifdef HAVE_USBHOST_TRACE_VERBOSE + + TRENTRY(OTGHS_VTRACE2_CHANWAKEUP_IN, + TR_FMT2, + "OTGHS EP%d(IN) wake up with result: %d\n"), + TRENTRY(OTGHS_VTRACE2_CHANWAKEUP_OUT, + TR_FMT2, + "OTGHS EP%d(OUT) wake up with result: %d\n"), + TRENTRY(OTGHS_VTRACE2_CTRLIN, + TR_FMT2, + "OTGHS CTRL_IN type: %02x req: %02x\n"), + TRENTRY(OTGHS_VTRACE2_CTRLOUT, + TR_FMT2, + "OTGHS CTRL_OUT type: %02x req: %02x\n"), + TRENTRY(OTGHS_VTRACE2_INTRIN, + TR_FMT2, + "OTGHS INTR_IN chidx: %02x len: %02x\n"), + TRENTRY(OTGHS_VTRACE2_INTROUT, + TR_FMT2, + "OTGHS INTR_OUT chidx: %02x len: %02x\n"), + TRENTRY(OTGHS_VTRACE2_BULKIN, + TR_FMT2, + "OTGHS BULK_IN chidx: %02x len: %02x\n"), + TRENTRY(OTGHS_VTRACE2_BULKOUT, + TR_FMT2, + "OTGHS BULK_OUT chidx: %02x len: %02x\n"), + TRENTRY(OTGHS_VTRACE2_ISOCIN, + TR_FMT2, + "OTGHS ISOC_IN chidx: %02x len: %04d\n"), + TRENTRY(OTGHS_VTRACE2_ISOCOUT, + TR_FMT2, + "OTGHS ISOC_OUT chidx: %02x req: %02x\n"), + TRENTRY(OTGHS_VTRACE2_STARTTRANSFER, + TR_FMT2, + "OTGHS Transfer chidx: %d buflen: %d\n"), + TRENTRY(OTGHS_VTRACE2_CHANCONF_CTRL_IN, + TR_FMT2, + "OTGHS Channel configured. chidx: %d: (EP%d,IN ,CTRL)\n"), + TRENTRY(OTGHS_VTRACE2_CHANCONF_CTRL_OUT, + TR_FMT2, + "OTGHS Channel configured. chidx: %d: (EP%d,OUT,CTRL)\n"), + TRENTRY(OTGHS_VTRACE2_CHANCONF_INTR_IN, + TR_FMT2, + "OTGHS Channel configured. chidx: %d: (EP%d,IN ,INTR)\n"), + TRENTRY(OTGHS_VTRACE2_CHANCONF_INTR_OUT, + TR_FMT2, + "OTGHS Channel configured. chidx: %d: (EP%d,OUT,INTR)\n"), + TRENTRY(OTGHS_VTRACE2_CHANCONF_BULK_IN, + TR_FMT2, + "OTGHS Channel configured. chidx: %d: (EP%d,IN ,BULK)\n"), + TRENTRY(OTGHS_VTRACE2_CHANCONF_BULK_OUT, + TR_FMT2, + "OTGHS Channel configured. chidx: %d: (EP%d,OUT,BULK)\n"), + TRENTRY(OTGHS_VTRACE2_CHANCONF_ISOC_IN, + TR_FMT2, + "OTGHS Channel configured. chidx: %d: (EP%d,IN ,ISOC)\n"), + TRENTRY(OTGHS_VTRACE2_CHANCONF_ISOC_OUT, + TR_FMT2, + "OTGHS Channel configured. chidx: %d: (EP%d,OUT,ISOC)\n"), + TRENTRY(OTGHS_VTRACE2_CHANHALT, + TR_FMT2, + "OTGHS Channel halted. chidx: %d, reason: %d\n"), + +# endif +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usbhost_trformat1 and usbhost_trformat2 + * + * Description: + * This interface must be provided by platform specific logic that knows + * the HCDs encoding of USB trace data. + * + * Given an 9-bit index, return a format string suitable for use with, say, + * printf. The returned format is expected to handle two unsigned integer + * values. + * + ****************************************************************************/ + +const char *usbhost_trformat1(uint16_t id) +{ + int ndx = TRACE1_INDEX(id); + + if (ndx < TRACE1_NSTRINGS) + { + return g_trace1[ndx].string; + } + + return NULL; +} + +const char *usbhost_trformat2(uint16_t id) +{ + int ndx = TRACE2_INDEX(id); + + if (ndx < TRACE2_NSTRINGS) + { + return g_trace2[ndx].string; + } + + return NULL; +} + +#endif /* HAVE_USBHOST_TRACE */ diff --git a/arch/arm/src/at32/at32_usbhost.h b/arch/arm/src/at32/at32_usbhost.h new file mode 100644 index 0000000000..3723f9d97e --- /dev/null +++ b/arch/arm/src/at32/at32_usbhost.h @@ -0,0 +1,280 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_usbhost.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_USBHOST_H +#define __ARCH_ARM_SRC_AT32_AT32_USBHOST_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include "chip.h" +#include "hardware/at32fxxxxx_otgfs.h" + +#if (defined(CONFIG_AT32_OTGFS) || defined(CONFIG_AT32_OTGHS)) && \ + defined(CONFIG_AT32_USBHOST) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifdef HAVE_USBHOST_TRACE +enum usbhost_trace1codes_e +{ + __TRACE1_BASEVALUE = 0, /* This will force the first value to be 1 */ + +#ifdef CONFIG_AT32_OTGFS + + OTGFS_TRACE1_DEVDISCONN, /* OTGFS ERROR: Host Port Device disconnected */ + OTGFS_TRACE1_IRQATTACH, /* OTGFS ERROR: Failed to attach IRQ */ + OTGFS_TRACE1_TRNSFRFAILED, /* OTGFS ERROR: Host Port Transfer Failed */ + OTGFS_TRACE1_SENDSETUP, /* OTGFS ERROR: sendsetup() failed with: */ + OTGFS_TRACE1_SENDDATA, /* OTGFS ERROR: senddata() failed with: */ + OTGFS_TRACE1_RECVDATA, /* OTGFS ERROR: recvdata() failed with: */ + +# ifdef HAVE_USBHOST_TRACE_VERBOSE + + OTGFS_VTRACE1_CONNECTED, /* OTGFS Host Port connected */ + OTGFS_VTRACE1_DISCONNECTED, /* OTGFS Host Port disconnected */ + OTGFS_VTRACE1_GINT, /* OTGFS Handling Interrupt. Entry Point */ + OTGFS_VTRACE1_GINT_SOF, /* OTGFS Handle the start of frame interrupt */ + OTGFS_VTRACE1_GINT_RXFLVL, /* OTGFS Handle the RxFIFO non-empty interrupt */ + OTGFS_VTRACE1_GINT_NPTXFE, /* OTGFS Handle the non-periodic TxFIFO empty interrupt */ + OTGFS_VTRACE1_GINT_PTXFE, /* OTGFS Handle the periodic TxFIFO empty interrupt */ + OTGFS_VTRACE1_GINT_HC, /* OTGFS Handle the host channels interrupt */ + OTGFS_VTRACE1_GINT_HPRT, /* OTGFS Handle the host port interrupt */ + OTGFS_VTRACE1_GINT_HPRT_POCCHNG, /* OTGFS HPRT: Port Over-Current Change */ + OTGFS_VTRACE1_GINT_HPRT_PCDET, /* OTGFS HPRT: Port Connect Detect */ + OTGFS_VTRACE1_GINT_HPRT_PENCHNG, /* OTGFS HPRT: Port Enable Changed */ + OTGFS_VTRACE1_GINT_HPRT_LSDEV, /* OTGFS HPRT: Low Speed Device Connected */ + OTGFS_VTRACE1_GINT_HPRT_FSDEV, /* OTGFS HPRT: Full Speed Device Connected */ + OTGFS_VTRACE1_GINT_HPRT_LSFSSW, /* OTGFS HPRT: Host Switch: LS -> FS */ + OTGFS_VTRACE1_GINT_HPRT_FSLSSW, /* OTGFS HPRT: Host Switch: FS -> LS */ + OTGFS_VTRACE1_GINT_DISC, /* OTGFS Handle the disconnect detected interrupt */ + OTGFS_VTRACE1_GINT_IPXFR, /* OTGFS Handle the incomplete periodic transfer */ + +# endif +#endif + +#ifdef CONFIG_AT32_OTGHS + + OTGHS_TRACE1_DEVDISCONN, /* OTGHS ERROR: Host Port Device disconnected */ + OTGHS_TRACE1_IRQATTACH, /* OTGHS ERROR: Failed to attach IRQ */ + OTGHS_TRACE1_TRNSFRFAILED, /* OTGHS ERROR: Host Port Transfer Failed */ + OTGHS_TRACE1_SENDSETUP, /* OTGHS ERROR: sendsetup() failed with: */ + OTGHS_TRACE1_SENDDATA, /* OTGHS ERROR: senddata() failed with: */ + OTGHS_TRACE1_RECVDATA, /* OTGHS ERROR: recvdata() failed with: */ + +# ifdef HAVE_USBHOST_TRACE_VERBOSE + + OTGHS_VTRACE1_CONNECTED, /* OTGHS Host Port connected */ + OTGHS_VTRACE1_DISCONNECTED, /* OTGHS Host Port disconnected */ + OTGHS_VTRACE1_GINT, /* OTGHS Handling Interrupt. Entry Point */ + OTGHS_VTRACE1_GINT_SOF, /* OTGHS Handle the start of frame interrupt */ + OTGHS_VTRACE1_GINT_RXFLVL, /* OTGHS Handle the RxFIFO non-empty interrupt */ + OTGHS_VTRACE1_GINT_NPTXFE, /* OTGHS Handle the non-periodic TxFIFO empty interrupt */ + OTGHS_VTRACE1_GINT_PTXFE, /* OTGHS Handle the periodic TxFIFO empty interrupt */ + OTGHS_VTRACE1_GINT_HC, /* OTGHS Handle the host channels interrupt */ + OTGHS_VTRACE1_GINT_HPRT, /* OTGHS Handle the host port interrupt */ + OTGHS_VTRACE1_GINT_HPRT_POCCHNG, /* OTGHS HPRT: Port Over-Current Change */ + OTGHS_VTRACE1_GINT_HPRT_PCDET, /* OTGHS HPRT: Port Connect Detect */ + OTGHS_VTRACE1_GINT_HPRT_PENCHNG, /* OTGHS HPRT: Port Enable Changed */ + OTGHS_VTRACE1_GINT_HPRT_LSDEV, /* OTGHS HPRT: Low Speed Device Connected */ + OTGHS_VTRACE1_GINT_HPRT_FSDEV, /* OTGHS HPRT: Full Speed Device Connected */ + OTGHS_VTRACE1_GINT_HPRT_LSFSSW, /* OTGHS HPRT: Host Switch: LS -> FS */ + OTGHS_VTRACE1_GINT_HPRT_FSLSSW, /* OTGHS HPRT: Host Switch: FS -> LS */ + OTGHS_VTRACE1_GINT_DISC, /* OTGHS Handle the disconnect detected interrupt */ + OTGHS_VTRACE1_GINT_IPXFR, /* OTGHS Handle the incomplete periodic transfer */ + +# endif +#endif + + __TRACE1_NSTRINGS, /* Separates the format 1 from the format 2 strings */ + +#ifdef CONFIG_AT32_OTGFS + + OTGFS_TRACE2_CLIP, /* OTGFS CLIP: chidx: buflen: */ + +# ifdef HAVE_USBHOST_TRACE_VERBOSE + + OTGFS_VTRACE2_CHANWAKEUP_IN, /* OTGFS IN Channel wake up with result */ + OTGFS_VTRACE2_CHANWAKEUP_OUT, /* OTGFS OUT Channel wake up with result */ + OTGFS_VTRACE2_CTRLIN, /* OTGFS CTRLIN */ + OTGFS_VTRACE2_CTRLOUT, /* OTGFS CTRLOUT */ + OTGFS_VTRACE2_INTRIN, /* OTGFS INTRIN */ + OTGFS_VTRACE2_INTROUT, /* OTGFS INTROUT */ + OTGFS_VTRACE2_BULKIN, /* OTGFS BULKIN */ + OTGFS_VTRACE2_BULKOUT, /* OTGFS BULKOUT */ + OTGFS_VTRACE2_ISOCIN, /* OTGFS ISOCIN */ + OTGFS_VTRACE2_ISOCOUT, /* OTGFS ISOCOUT */ + OTGFS_VTRACE2_STARTTRANSFER, /* OTGFS EP buflen */ + OTGFS_VTRACE2_CHANCONF_CTRL_IN, + OTGFS_VTRACE2_CHANCONF_CTRL_OUT, + OTGFS_VTRACE2_CHANCONF_INTR_IN, + OTGFS_VTRACE2_CHANCONF_INTR_OUT, + OTGFS_VTRACE2_CHANCONF_BULK_IN, + OTGFS_VTRACE2_CHANCONF_BULK_OUT, + OTGFS_VTRACE2_CHANCONF_ISOC_IN, + OTGFS_VTRACE2_CHANCONF_ISOC_OUT, + OTGFS_VTRACE2_CHANHALT, /* Channel halted. chidx: , reason: */ + +# endif +#endif + +#ifdef CONFIG_AT32_OTGHS + + OTGHS_TRACE2_CLIP, /* OTGHS CLIP: chidx: buflen: */ + +# ifdef HAVE_USBHOST_TRACE_VERBOSE + + OTGHS_VTRACE2_CHANWAKEUP_IN, /* OTGHS IN Channel wake up with result */ + OTGHS_VTRACE2_CHANWAKEUP_OUT, /* OTGHS OUT Channel wake up with result */ + OTGHS_VTRACE2_CTRLIN, /* OTGHS CTRLIN */ + OTGHS_VTRACE2_CTRLOUT, /* OTGHS CTRLOUT */ + OTGHS_VTRACE2_INTRIN, /* OTGHS INTRIN */ + OTGHS_VTRACE2_INTROUT, /* OTGHS INTROUT */ + OTGHS_VTRACE2_BULKIN, /* OTGHS BULKIN */ + OTGHS_VTRACE2_BULKOUT, /* OTGHS BULKOUT */ + OTGHS_VTRACE2_ISOCIN, /* OTGHS ISOCIN */ + OTGHS_VTRACE2_ISOCOUT, /* OTGHS ISOCOUT */ + OTGHS_VTRACE2_STARTTRANSFER, /* OTGHS EP buflen */ + OTGHS_VTRACE2_CHANCONF_CTRL_IN, + OTGHS_VTRACE2_CHANCONF_CTRL_OUT, + OTGHS_VTRACE2_CHANCONF_INTR_IN, + OTGHS_VTRACE2_CHANCONF_INTR_OUT, + OTGHS_VTRACE2_CHANCONF_BULK_IN, + OTGHS_VTRACE2_CHANCONF_BULK_OUT, + OTGHS_VTRACE2_CHANCONF_ISOC_IN, + OTGHS_VTRACE2_CHANCONF_ISOC_OUT, + OTGHS_VTRACE2_CHANHALT, /* Channel halted. chidx: , reason: */ + +# endif +#endif + + __TRACE2_NSTRINGS /* Total number of enumeration values */ +}; + +# define TRACE1_FIRST ((int)__TRACE1_BASEVALUE + 1) +# define TRACE1_INDEX(id) ((int)(id) - TRACE1_FIRST) +# define TRACE1_NSTRINGS TRACE1_INDEX(__TRACE1_NSTRINGS) + +# define TRACE2_FIRST ((int)__TRACE1_NSTRINGS + 1) +# define TRACE2_INDEX(id) ((int)(id) - TRACE2_FIRST) +# define TRACE2_NSTRINGS TRACE2_INDEX(__TRACE2_NSTRINGS) + +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* AT32 USB OTG FS Host Driver Support + * + * Pre-requisites + * + * CONFIG_AT32_USBHOST - Enable general USB host support + * CONFIG_USBHOST - Enable general USB host support + * CONFIG_AT32_OTGFS - Enable the AT32 USB OTG FS block + * or + * CONFIG_AT32_OTGHS - Enable the AT32 USB OTG HS block + * CONFIG_AT32_SYSCFG - Needed + * + * Options: + * + * CONFIG_AT32_OTGFS_RXFIFO_SIZE - Size of the RX FIFO in 32-bit words. + * Default 128 (512 bytes) + * CONFIG_AT32_OTGFS_NPTXFIFO_SIZE - Size of the non-periodic Tx FIFO + * in 32-bit words. Default 96 (384 bytes) + * CONFIG_AT32_OTGFS_PTXFIFO_SIZE - Size of the periodic Tx FIFO in 32-bit + * words. Default 96 (384 bytes) + * CONFIG_AT32_OTGFS_SOFINTR - Enable SOF interrupts. Why would you ever + * want to do that? + * + * CONFIG_AT32_OTGHS_RXFIFO_SIZE - Size of the RX FIFO in 32-bit words. + * Default 128 (512 bytes) + * CONFIG_AT32_OTGHS_NPTXFIFO_SIZE - Size of the non-periodic Tx FIFO + * in 32-bit words. Default 96 (384 bytes) + * CONFIG_AT32_OTGHS_PTXFIFO_SIZE - Size of the periodic Tx FIFO in 32-bit + * words. Default 96 (384 bytes) + * CONFIG_AT32_OTGHS_SOFINTR - Enable SOF interrupts. Why would you ever + * want to do that? + * + * CONFIG_AT32_USBHOST_REGDEBUG - Enable very low-level register access + * debug. Depends on CONFIG_DEBUG_FEATURES. + */ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: at32_usbhost_vbusdrive + * + * Description: + * Enable/disable driving of VBUS 5V output. This function must be + * provided be each platform that implements the AT32 OTG FS host + * interface. + * + * "On-chip 5 V VBUS generation is not supported. For this reason, a + * charge pump or, if 5 V are available on the application board, a basic + * power switch, must be added externally to drive the 5 V VBUS line. The + * external charge pump can be driven by any GPIO output. When the + * application decides to power on VBUS using the chosen GPIO, it must + * also set the port power bit in the host port control and status + * register (PPWR bit in OTG_FS_HPRT). + * + * "The application uses this field to control power to this port, and the + * core clears this bit on an overcurrent condition." + * + * Input Parameters: + * iface - For future growth to handle multiple USB host interface. + * Should be zero. + * enable - true: enable VBUS power; false: disable VBUS power + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_AT32_OTGFS_VBUS_CONTROL) || \ + defined(CONFIG_AT32_OTGHS_VBUS_CONTROL) +void at32_usbhost_vbusdrive(int iface, bool enable); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_AT32_OTGFS && CONFIG_AT32_USBHOST */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_USBHOST_H */ diff --git a/arch/arm/src/at32/at32_userspace.c b/arch/arm/src/at32/at32_userspace.c new file mode 100644 index 0000000000..ceb565bba7 --- /dev/null +++ b/arch/arm/src/at32/at32_userspace.c @@ -0,0 +1,103 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_userspace.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include "at32_mpuinit.h" +#include "at32_userspace.h" + +#ifdef CONFIG_BUILD_PROTECTED + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_userspace + * + * Description: + * For the case of the separate user-/kernel-space build, perform whatever + * platform specific initialization of the user memory is required. + * Normally this just means initializing the user space .data and .bss + * segments. + * + ****************************************************************************/ + +void at32_userspace(void) +{ + uint8_t *src; + uint8_t *dest; + uint8_t *end; + + /* Clear all of user-space .bss */ + + DEBUGASSERT(USERSPACE->us_bssstart != 0 && USERSPACE->us_bssend != 0 && + USERSPACE->us_bssstart <= USERSPACE->us_bssend); + + dest = (uint8_t *)USERSPACE->us_bssstart; + end = (uint8_t *)USERSPACE->us_bssend; + + while (dest != end) + { + *dest++ = 0; + } + + /* Initialize all of user-space .data */ + + DEBUGASSERT(USERSPACE->us_datasource != 0 && + USERSPACE->us_datastart != 0 && USERSPACE->us_dataend != 0 && + USERSPACE->us_datastart <= USERSPACE->us_dataend); + + src = (uint8_t *)USERSPACE->us_datasource; + dest = (uint8_t *)USERSPACE->us_datastart; + end = (uint8_t *)USERSPACE->us_dataend; + + while (dest != end) + { + *dest++ = *src++; + } + + /* Configure the MPU to permit user-space access to its FLASH and RAM */ + + at32_mpuinitialize(); +} + +#endif /* CONFIG_BUILD_PROTECTED */ diff --git a/arch/arm/src/at32/at32_userspace.h b/arch/arm/src/at32/at32_userspace.h new file mode 100644 index 0000000000..45984e3572 --- /dev/null +++ b/arch/arm/src/at32/at32_userspace.h @@ -0,0 +1,61 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_userspace.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_USERSPACE_H +#define __ARCH_ARM_SRC_AT32_AT32_USERSPACE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_userspace + * + * Description: + * For the case of the separate user-/kernel-space build, perform whatever + * platform specific initialization of the user memory is required. + * Normally this just means initializing the user space .data and .bss + * segments. + * + ****************************************************************************/ + +#ifdef CONFIG_BUILD_PROTECTED +void at32_userspace(void); +#endif + +#endif /* __ARCH_ARM_SRC_AT32_AT32_USERSPACE_H */ diff --git a/arch/arm/src/at32/at32_waste.c b/arch/arm/src/at32/at32_waste.c new file mode 100644 index 0000000000..8e1812af35 --- /dev/null +++ b/arch/arm/src/at32/at32_waste.c @@ -0,0 +1,42 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_waste.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "at32_waste.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +uint32_t g_waste_counter = 0; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void at32_waste(void) +{ + g_waste_counter++; +} diff --git a/arch/arm/src/at32/at32_waste.h b/arch/arm/src/at32/at32_waste.h new file mode 100644 index 0000000000..3f83cfe716 --- /dev/null +++ b/arch/arm/src/at32/at32_waste.h @@ -0,0 +1,64 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_waste.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_WASTE_H +#define __ARCH_ARM_SRC_AT32_AT32_WASTE_H + +/* Waste CPU Time */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/** Waste CPU Time + * + * at32_waste() is the logic that will be executed when portions of kernel + * or user-app is polling some register or similar, waiting for desired + * status. This time is wasted away. This function offers a measure of + * badly written piece of software or some undesired behavior. + * + * At the same time this function adds to some IDLE time which portion + * cannot be used for other purposes (yet). + **/ + +void at32_waste(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_WASTE_H */ diff --git a/arch/arm/src/at32/at32_wdg.h b/arch/arm/src/at32/at32_wdg.h new file mode 100644 index 0000000000..a37deb592a --- /dev/null +++ b/arch/arm/src/at32/at32_wdg.h @@ -0,0 +1,104 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_wdg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32_WDG_H +#define __ARCH_ARM_SRC_AT32_AT32_WDG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" +#include "hardware/at32_wdg.h" + +#ifdef CONFIG_WATCHDOG + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_iwdginitialize + * + * Description: + * Initialize the IWDG watchdog time. The watchdog timer is initialized + * and registers as 'devpath. The initial state of the watchdog time is + * disabled. + * + * Input Parameters: + * devpath - The full path to the watchdog. This should be of the form + * /dev/watchdog0 + * lsifreq - The calibrated LSI clock frequency + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_IWDG +void at32_iwdginitialize(const char *devpath, uint32_t lsifreq); +#endif + +/**************************************************************************** + * Name: at32_wwdginitialize + * + * Description: + * Initialize the WWDG watchdog time. The watchdog timer is initializeed + * and registers as 'devpath. The initial state of the watchdog time is + * disabled. + * + * Input Parameters: + * devpath - The full path to the watchdog. This should be of the form + * /dev/watchdog0 + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_WWDG +void at32_wwdginitialize(const char *devpath); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_WATCHDOG */ +#endif /* __ARCH_ARM_SRC_AT32_AT32_WDG_H */ diff --git a/arch/arm/src/at32/at32_wwdg.c b/arch/arm/src/at32/at32_wwdg.c new file mode 100644 index 0000000000..58ddd69be7 --- /dev/null +++ b/arch/arm/src/at32/at32_wwdg.c @@ -0,0 +1,794 @@ +/**************************************************************************** + * arch/arm/src/at32/at32_wwdg.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "arm_internal.h" +#include "hardware/at32_dbgmcu.h" +#include "at32_wdg.h" + +#if defined(CONFIG_WATCHDOG) && defined(CONFIG_AT32_WWDG) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Clocking *****************************************************************/ + +/* The minimum frequency of the WWDG clock is: + * + * Fmin = PCLK1 / 4096 / 8 + * + * So the maximum delay (in milliseconds) is then: + * + * 1000 * (WWDG_CR_T_MAX+1) / Fmin + * + * For example, if PCLK1 = 42MHz, then the maximum delay is: + * + * Fmin = 1281.74 + * 1000 * 64 / Fmin = 49.93 msec + */ + +#define WWDG_FMIN (AT32_PCLK1_FREQUENCY / 4096 / 8) +#define WWDG_MAXTIMEOUT (1000 * (WWDG_CR_T_MAX+1) / WWDG_FMIN) + +/* Configuration ************************************************************/ + +#ifndef CONFIG_AT32_WWDG_DEFTIMOUT +# define CONFIG_AT32_WWDG_DEFTIMOUT WWDG_MAXTIMEOUT +#endif + +#ifndef CONFIG_DEBUG_WATCHDOG_INFO +# undef CONFIG_AT32_WWDG_REGDEBUG +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure provides the private representation of the "lower-half" + * driver state structure. This structure must be cast-compatible with the + * well-known watchdog_lowerhalf_s structure. + */ + +struct at32_lowerhalf_s +{ + const struct watchdog_ops_s *ops; /* Lower half operations */ + xcpt_t handler; /* Current EWI interrupt handler */ + uint32_t timeout; /* The actual timeout value */ + uint32_t fwwdg; /* WWDG clock frequency */ + bool started; /* The timer has been started */ + uint8_t reload; /* The 7-bit reload field reset value */ + uint8_t window; /* The 7-bit window (W) field value */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register operations ******************************************************/ + +#ifdef CONFIG_AT32_WWDG_REGDEBUG +static uint16_t at32_getreg(uint32_t addr); +static void at32_putreg(uint16_t val, uint32_t addr); +#else +# define at32_getreg(addr) getreg32(addr) +# define at32_putreg(val,addr) putreg32(val,addr) +#endif +static void at32_setwindow(struct at32_lowerhalf_s *priv, + uint8_t window); + +/* Interrupt handling *******************************************************/ + +static int at32_interrupt(int irq, void *context, void *arg); + +/* "Lower half" driver methods **********************************************/ + +static int at32_start(struct watchdog_lowerhalf_s *lower); +static int at32_stop(struct watchdog_lowerhalf_s *lower); +static int at32_keepalive(struct watchdog_lowerhalf_s *lower); +static int at32_getstatus(struct watchdog_lowerhalf_s *lower, + struct watchdog_status_s *status); +static int at32_settimeout(struct watchdog_lowerhalf_s *lower, + uint32_t timeout); +static xcpt_t at32_capture(struct watchdog_lowerhalf_s *lower, + xcpt_t handler); +static int at32_ioctl(struct watchdog_lowerhalf_s *lower, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* "Lower half" driver methods */ + +static const struct watchdog_ops_s g_wdgops = +{ + .start = at32_start, + .stop = at32_stop, + .keepalive = at32_keepalive, + .getstatus = at32_getstatus, + .settimeout = at32_settimeout, + .capture = at32_capture, + .ioctl = at32_ioctl, +}; + +/* "Lower half" driver state */ + +static struct at32_lowerhalf_s g_wdgdev; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_getreg + * + * Description: + * Get the contents of an AT32 register + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_WWDG_REGDEBUG +static uint16_t at32_getreg(uint32_t addr) +{ + static uint32_t prevaddr = 0; + static uint32_t count = 0; + static uint16_t preval = 0; + + /* Read the value from the register */ + + uint16_t val = getreg16(addr); + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (addr == prevaddr && val == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + wdinfo("...\n"); + } + + return val; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + wdinfo("[repeats %d more times]\n", count - 3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + preval = val; + count = 1; + } + + /* Show the register value read */ + + wdinfo("%08x->%04x\n", addr, val); + return val; +} +#endif + +/**************************************************************************** + * Name: at32_putreg + * + * Description: + * Set the contents of an AT32 register to a value + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_WWDG_REGDEBUG +static void at32_putreg(uint16_t val, uint32_t addr) +{ + /* Show the register value being written */ + + wdinfo("%08x<-%04x\n", addr, val); + + /* Write the value */ + + putreg16(val, addr); +} +#endif + +/**************************************************************************** + * Name: at32_setwindow + * + * Description: + * Set the CFR window value. The window value is compared to the down- + * counter when the counter is updated. The WWDG counter should be updated + * only when the counter is below this window value (and greater than 64) + * otherwise a reset will be generated + * + ****************************************************************************/ + +static void at32_setwindow(struct at32_lowerhalf_s *priv, + uint8_t window) +{ + uint16_t regval; + + /* Set W[6:0] bits according to selected window value */ + + regval = at32_getreg(AT32_WWDG_CFR); + regval &= ~WWDG_CFR_W_MASK; + regval |= window << WWDG_CFR_W_SHIFT; + at32_putreg(regval, AT32_WWDG_CFR); + + /* Remember the window setting */ + + priv->window = window; +} + +/**************************************************************************** + * Name: at32_interrupt + * + * Description: + * WWDG early warning interrupt + * + * Input Parameters: + * Usual interrupt handler arguments. + * + * Returned Value: + * Always returns OK. + * + ****************************************************************************/ + +static int at32_interrupt(int irq, void *context, void *arg) +{ + struct at32_lowerhalf_s *priv = &g_wdgdev; + uint16_t regval; + + /* Check if the EWI interrupt is really pending */ + + regval = at32_getreg(AT32_WWDG_SR); + if ((regval & WWDG_SR_EWIF) != 0) + { + /* Is there a registered handler? */ + + if (priv->handler) + { + /* Yes... NOTE: This interrupt service routine (ISR) must reload + * the WWDG counter to prevent the reset. Otherwise, we will reset + * upon return. + */ + + priv->handler(irq, context, arg); + } + + /* The EWI interrupt is cleared by writing '0' to the EWIF bit in the + * WWDG_SR register. + */ + + regval &= ~WWDG_SR_EWIF; + at32_putreg(regval, AT32_WWDG_SR); + } + + return OK; +} + +/**************************************************************************** + * Name: at32_start + * + * Description: + * Start the watchdog timer, resetting the time to the current timeout, + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower- + * half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_start(struct watchdog_lowerhalf_s *lower) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + + wdinfo("Entry\n"); + DEBUGASSERT(priv); + + /* The watchdog is always disabled after a reset. It is enabled by setting + * the WDGA bit in the WWDG_CR register, then it cannot be disabled again + * except by a reset. + */ + + at32_putreg(WWDG_CR_WDGA | WWDG_CR_T_RESET | priv->reload, AT32_WWDG_CR); + priv->started = true; + return OK; +} + +/**************************************************************************** + * Name: at32_stop + * + * Description: + * Stop the watchdog timer + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower- + * half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_stop(struct watchdog_lowerhalf_s *lower) +{ + /* The watchdog is always disabled after a reset. It is enabled by setting + * the WDGA bit in the WWDG_CR register, then it cannot be disabled again + * except by a reset. + */ + + wdinfo("Entry\n"); + return -ENOSYS; +} + +/**************************************************************************** + * Name: at32_keepalive + * + * Description: + * Reset the watchdog timer to the current timeout value, prevent any + * imminent watchdog timeouts. This is sometimes referred as "pinging" + * the watchdog timer or "petting the dog". + * + * The application program must write in the WWDG_CR register at regular + * intervals during normal operation to prevent an MCU reset. This + * operation must occur only when the counter value is lower than the + * window register value. The value to be stored in the WWDG_CR register + * must be between 0xff and 0xC0: + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower- + * half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_keepalive(struct watchdog_lowerhalf_s *lower) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + + wdinfo("Entry\n"); + DEBUGASSERT(priv); + + /* Write to T[6:0] bits to configure the counter value, no need to do + * a read-modify-write; writing a 0 to WDGA bit does nothing. + */ + + at32_putreg((WWDG_CR_T_RESET | priv->reload), AT32_WWDG_CR); + return OK; +} + +/**************************************************************************** + * Name: at32_getstatus + * + * Description: + * Get the current watchdog timer status + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower- + * half" driver state structure. + * status - The location to return the watchdog status information. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_getstatus(struct watchdog_lowerhalf_s *lower, + struct watchdog_status_s *status) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + uint32_t elapsed; + uint16_t reload; + + wdinfo("Entry\n"); + DEBUGASSERT(priv); + + /* Return the status bit */ + + status->flags = WDFLAGS_RESET; + if (priv->started) + { + status->flags |= WDFLAGS_ACTIVE; + } + + if (priv->handler) + { + status->flags |= WDFLAGS_CAPTURE; + } + + /* Return the actual timeout is milliseconds */ + + status->timeout = priv->timeout; + + /* Get the time remaining until the watchdog expires (in milliseconds) */ + + reload = (at32_getreg(AT32_WWDG_CR) >> WWDG_CR_T_SHIFT) & 0x7f; + elapsed = priv->reload - reload; + status->timeleft = (priv->timeout * elapsed) / (priv->reload + 1); + + wdinfo("Status :\n"); + wdinfo(" flags : %08x\n", (unsigned)status->flags); + wdinfo(" timeout : %u\n", (unsigned)status->timeout); + wdinfo(" timeleft : %u\n", (unsigned)status->flags); + return OK; +} + +/**************************************************************************** + * Name: at32_settimeout + * + * Description: + * Set a new timeout value (and reset the watchdog timer) + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * timeout - The new timeout value in milliseconds. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_settimeout(struct watchdog_lowerhalf_s *lower, + uint32_t timeout) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + uint32_t fwwdg; + uint32_t reload; + uint16_t regval; + int wdgtb; + + DEBUGASSERT(priv); + wdinfo("Entry: timeout=%u\n", (unsigned)timeout); + + /* Can this timeout be represented? */ + + if (timeout < 1 || timeout > WWDG_MAXTIMEOUT) + { + wderr("ERROR: Cannot represent timeout=%u > %lu\n", + (unsigned)timeout, WWDG_MAXTIMEOUT); + return -ERANGE; + } + + /* Determine prescaler value. + * + * Fwwdg = PCLK1/4096/prescaler. + * + * Where + * Fwwwdg is the frequency of the WWDG clock + * wdgtb is one of {1, 2, 4, or 8} + */ + + /* Select the smallest prescaler that will result in a reload field value + * that is less than the maximum. + */ + + for (wdgtb = 0; ; wdgtb++) + { + /* WDGTB = 0 -> Divider = 1 = 1 << 0 + * WDGTB = 1 -> Divider = 2 = 1 << 1 + * WDGTB = 2 -> Divider = 4 = 1 << 2 + * WDGTB = 3 -> Divider = 8 = 1 << 3 + */ + + /* Get the WWDG counter frequency in Hz. */ + + fwwdg = (AT32_PCLK1_FREQUENCY / 4096) >> wdgtb; + + /* The formula to calculate the timeout value is given by: + * + * timeout = 1000 * (reload + 1) / Fwwdg, OR + * reload = timeout * Fwwdg / 1000 - 1 + * + * Where + * timeout is the desired timeout in milliseconds + * reload is the contents of T{5:0] + * Fwwdg is the frequency of the WWDG clock + */ + + reload = timeout * fwwdg / 1000 - 1; + + /* If this reload valid is less than the maximum or we are not ready + * at the prescaler value, then break out of the loop to use these + * settings. + */ + +#if 0 + wdinfo("wdgtb=%d fwwdg=%d reload=%d timeout=%d\n", + wdgtb, fwwdg, reload, 1000 * (reload + 1) / fwwdg); +#endif + if (reload <= WWDG_CR_T_MAX || wdgtb == 3) + { + /* Note that we explicitly break out of the loop rather than using + * the 'for' loop termination logic because we do not want the + * value of wdgtb to be incremented. + */ + + break; + } + } + + /* Make sure that the final reload value is within range */ + + if (reload > WWDG_CR_T_MAX) + { + reload = WWDG_CR_T_MAX; + } + + /* Calculate and save the actual timeout value in milliseconds: + * + * timeout = 1000 * (reload + 1) / Fwwdg + */ + + priv->timeout = 1000 * (reload + 1) / fwwdg; + + /* Remember the selected values */ + + priv->fwwdg = fwwdg; + priv->reload = reload; + + wdinfo("wdgtb=%d fwwdg=%u reload=%u timeout=%u\n", + wdgtb, (unsigned)fwwdg, (unsigned)reload, (unsigned)priv->timeout); + + /* Set WDGTB[1:0] bits according to calculated value */ + + regval = at32_getreg(AT32_WWDG_CFR); + regval &= ~WWDG_CFR_WDGTB_MASK; + regval |= (uint16_t)wdgtb << WWDG_CFR_WDGTB_SHIFT; + at32_putreg(regval, AT32_WWDG_CFR); + + /* Reset the 7-bit window value to the maximum value.. essentially + * disabling the lower limit of the watchdog reset time. + */ + + at32_setwindow(priv, 0x7f); + return OK; +} + +/**************************************************************************** + * Name: at32_capture + * + * Description: + * Don't reset on watchdog timer timeout; instead, call this user provider + * timeout handler. NOTE: Providing handler==NULL will restore the reset + * behavior. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * newhandler - The new watchdog expiration function pointer. If this + * function pointer is NULL, then the reset-on-expiration + * behavior is restored, + * + * Returned Value: + * The previous watchdog expiration function pointer or NULL is there was + * no previous function pointer, i.e., if the previous behavior was + * reset-on-expiration (NULL is also returned if an error occurs). + * + ****************************************************************************/ + +static xcpt_t at32_capture(struct watchdog_lowerhalf_s *lower, + xcpt_t handler) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + irqstate_t flags; + xcpt_t oldhandler; + uint16_t regval; + + DEBUGASSERT(priv); + wdinfo("Entry: handler=%p\n", handler); + + /* Get the old handler return value */ + + flags = enter_critical_section(); + oldhandler = priv->handler; + + /* Save the new handler */ + + priv->handler = handler; + + /* Are we attaching or detaching the handler? */ + + regval = at32_getreg(AT32_WWDG_CFR); + if (handler) + { + /* Attaching... Enable the EWI interrupt */ + + regval |= WWDG_CFR_EWI; + at32_putreg(regval, AT32_WWDG_CFR); + + up_enable_irq(AT32_IRQ_WWDG); + } + else + { + /* Detaching... Disable the EWI interrupt */ + + regval &= ~WWDG_CFR_EWI; + at32_putreg(regval, AT32_WWDG_CFR); + + up_disable_irq(AT32_IRQ_WWDG); + } + + leave_critical_section(flags); + return oldhandler; +} + +/**************************************************************************** + * Name: at32_ioctl + * + * Description: + * Any ioctl commands that are not recognized by the "upper-half" driver + * are forwarded to the lower half driver through this method. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower- + * half" driver state structure. + * cmd - The ioctl command value + * arg - The optional argument that accompanies the 'cmd'. The + * interpretation of this argument depends on the particular + * command. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int at32_ioctl(struct watchdog_lowerhalf_s *lower, int cmd, + unsigned long arg) +{ + struct at32_lowerhalf_s *priv = (struct at32_lowerhalf_s *)lower; + int ret = -ENOTTY; + + DEBUGASSERT(priv); + wdinfo("Entry: cmd=%d arg=%ld\n", cmd, arg); + + /* WDIOC_MINTIME: Set the minimum ping time. If two keepalive ioctls + * are received within this time, a reset event will be generated. + * Argument: A 32-bit time value in milliseconds. + */ + + if (cmd == WDIOC_MINTIME) + { + uint32_t mintime = (uint32_t)arg; + + /* The minimum time should be strictly less than the total delay + * which, in turn, will be less than or equal to WWDG_CR_T_MAX + */ + + ret = -EINVAL; + if (mintime < priv->timeout) + { + uint32_t window = (priv->timeout - mintime) * priv->fwwdg / + 1000 - 1; + DEBUGASSERT(window < priv->reload); + at32_setwindow(priv, window | WWDG_CR_T_RESET); + ret = OK; + } + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_wwdginitialize + * + * Description: + * Initialize the WWDG watchdog timer. The watchdog timer is initialized + * and registers as 'devpath'. The initial state of the watchdog timer is + * disabled. + * + * Input Parameters: + * devpath - The full path to the watchdog. This should be of the form + * /dev/watchdog0 + * + * Returned Value: + * None + * + ****************************************************************************/ + +void at32_wwdginitialize(const char *devpath) +{ + struct at32_lowerhalf_s *priv = &g_wdgdev; + + wdinfo("Entry: devpath=%s\n", devpath); + + /* NOTE we assume that clocking to the WWDG has already been provided by + * the RCC initialization logic. + */ + + /* Initialize the driver state structure. Here we assume: (1) the state + * structure lies in .bss and was zeroed at reset time. (2) This function + * is only called once so it is never necessary to re-zero the structure. + */ + + priv->ops = &g_wdgops; + + /* Attach our EWI interrupt handler (But don't enable it yet) */ + + irq_attach(AT32_IRQ_WWDG, at32_interrupt, NULL); + + /* Select an arbitrary initial timeout value. But don't start the watchdog + * yet. NOTE: If the "Hardware watchdog" feature is enabled through the + * device option bits, the watchdog is automatically enabled at power-on. + */ + + at32_settimeout((struct watchdog_lowerhalf_s *)priv, + CONFIG_AT32_WWDG_DEFTIMOUT); + + /* Register the watchdog driver as /dev/watchdog0 */ + + watchdog_register(devpath, (struct watchdog_lowerhalf_s *)priv); + + /* When the microcontroller enters debug mode (Cortex-M core halted), + * the WWDG counter either continues to work normally or stops, depending + * on DBG_WWDG_STOP configuration bit in DBG module. + */ + +#if defined(CONFIG_AT32_JTAG_FULL_ENABLE) || \ + defined(CONFIG_AT32_JTAG_NOJNTRST_ENABLE) || \ + defined(CONFIG_AT32_JTAG_SW_ENABLE) + { +#if defined(CONFIG_AT32_AT32F43XX) + uint32_t cr = getreg32(AT32_DEBUG_APB1_PAUSE); + cr |= DEBUG_APB1_APUSE_WWDT_PAUSE; + putreg32(cr, AT32_DEBUG_APB1_PAUSE); +#endif + } +#endif +} + +#endif /* CONFIG_WATCHDOG && CONFIG_AT32_WWDG */ diff --git a/arch/arm/src/at32/at32f43xx_flash.c b/arch/arm/src/at32/at32f43xx_flash.c new file mode 100644 index 0000000000..dac79b1cf3 --- /dev/null +++ b/arch/arm/src/at32/at32f43xx_flash.c @@ -0,0 +1,410 @@ +/**************************************************************************** + * arch/arm/src/at32/at32f43xx_flash.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Provides standard flash access functions, to be used by the flash mtd + * driver. The interface is defined in the include/nuttx/progmem.h + * + * Requirements during write/erase operations on FLASH: + * - HSI must be ON. + * - Low Power Modes are not permitted during write/erase + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include "at32_flash.h" +#include "at32_rcc.h" +#include "at32_waste.h" +#include "arm_internal.h" + +/* Only for the AT32F43xx family. */ + +#if defined (CONFIG_AT32_AT32F43XX) + +#if defined(CONFIG_AT32_FLASH_CONFIG_DEFAULT) +# warning "Default Flash Configuration Used - See Override Flash Size Designator" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define FLASH_KEY1 0x45670123 +#define FLASH_KEY2 0xcdef89ab +#define FLASH_OPTKEY1 0x08192a3b +#define FLASH_OPTKEY2 0x4c5d6e7f +#define FLASH_ERASEDVALUE 0xff + +/**************************************************************************** + * Private Data + ****************************************************************************/ + + static mutex_t g_lock = NXMUTEX_INITIALIZER; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void flash_unlock(void) +{ + while (getreg32(AT32_FLASH_STS) & FLASH_STS_OBF) + { + at32_waste(); + } + + if (getreg32(AT32_FLASH_CTRL) & FLASH_CTRL_OPLK) + { + /* Unlock sequence */ + + putreg32(FLASH_KEY1, AT32_FLASH_UNLOCK); + putreg32(FLASH_KEY2, AT32_FLASH_UNLOCK); + } + +#ifdef AT32_FLASH_BANK2_START + if (AT32_FLASH_BANK2_START < AT32_FLASH_NPAGES) + { + while (getreg32(AT32_FLASH_STS2) & FLASH_STS_OBF) + { + at32_waste(); + } + + if (getreg32(AT32_FLASH_CTRL2) & FLASH_CTRL_OPLK) + { + /* Unlock sequence */ + + putreg32(FLASH_KEY1, AT32_FLASH_UNLOCK2); + putreg32(FLASH_KEY2, AT32_FLASH_UNLOCK2); + } + } +#endif +} + +static void flash_lock(void) +{ + modifyreg32(AT32_FLASH_CTRL, 0, FLASH_CTRL_OPLK); + +#ifdef AT32_FLASH_BANK2_START + if (AT32_FLASH_BANK2_START < AT32_FLASH_NPAGES) + modifyreg32(AT32_FLASH_CTRL2, 0, FLASH_CTRL_OPLK); +#endif +} + +#if defined(CONFIG_AT32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) +static void data_cache_disable(void) +{ + modifyreg32(AT32_FLASH_PSR, FLASH_PSR_NZW_BST, 0); +} + +static void data_cache_enable(void) +{ + /* Enable data cache */ + + modifyreg32(AT32_FLASH_PSR, 0, FLASH_PSR_NZW_BST); +} +#endif /* defined(CONFIG_AT32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int at32_flash_unlock(void) +{ + int ret; + + ret = nxmutex_lock(&g_lock); + if (ret < 0) + { + return ret; + } + + flash_unlock(); + nxmutex_unlock(&g_lock); + + return ret; +} + +int at32_flash_lock(void) +{ + int ret; + + ret = nxmutex_lock(&g_lock); + if (ret < 0) + { + return ret; + } + + flash_lock(); + nxmutex_unlock(&g_lock); + + return ret; +} + +size_t up_progmem_pagesize(size_t page) +{ + return AT32_FLASH_PAGESIZE; +} + +size_t up_progmem_erasesize(size_t block) +{ + return up_progmem_pagesize(block); +} + +ssize_t up_progmem_getpage(size_t addr) +{ + size_t page_end = 0; + size_t i; + + if (addr >= AT32_FLASH_BASE) + { + addr -= AT32_FLASH_BASE; + } + + if (addr >= AT32_FLASH_SIZE) + { + return -EFAULT; + } + + for (i = 0; i < AT32_FLASH_NPAGES; ++i) + { + page_end += up_progmem_pagesize(i); + if (page_end > addr) + { + return i; + } + } + + return -EFAULT; +} + +size_t up_progmem_getaddress(size_t page) +{ + size_t base_address = AT32_FLASH_BASE; + size_t i; + + if (page >= AT32_FLASH_NPAGES) + { + return SIZE_MAX; + } + + for (i = 0; i < page; ++i) + { + base_address += up_progmem_pagesize(i); + } + + return base_address; +} + +size_t up_progmem_neraseblocks(void) +{ + return AT32_FLASH_NPAGES; +} + +bool up_progmem_isuniform(void) +{ +#ifdef AT32_FLASH_PAGESIZE + return true; +#else + return false; +#endif +} + +ssize_t up_progmem_ispageerased(size_t page) +{ + size_t addr; + size_t count; + size_t bwritten = 0; + + if (page >= AT32_FLASH_NPAGES) + { + return -EFAULT; + } + + /* Verify */ + + for (addr = up_progmem_getaddress(page), count = up_progmem_pagesize(page); + count; count--, addr++) + { + if (getreg8(addr) != FLASH_ERASEDVALUE) + { + bwritten++; + } + } + + return bwritten; +} + +ssize_t up_progmem_eraseblock(size_t block) +{ + unsigned int flash_ctrl; + unsigned int flash_addr; + unsigned int flash_sts; + + if (block >= AT32_FLASH_NPAGES) + { + return -EFAULT; + } + +#ifdef AT32_FLASH_BANK2_START + flash_ctrl = (block < AT32_FLASH_BANK2_START) ? \ + AT32_FLASH_CTRL : AT32_FLASH_CTRL2; + flash_addr = (block < AT32_FLASH_BANK2_START) ? \ + AT32_FLASH_ADDR : AT32_FLASH_ADDR2; + flash_sts = (block < AT32_FLASH_BANK2_START) ? \ + AT32_FLASH_STS : AT32_FLASH_STS2; +#else + flash_ctrl = AT32_FLASH_CTRL; + flash_addr = AT32_FLASH_ADDR; + flash_sts = AT32_FLASH_STS; +#endif + + nxmutex_lock(&g_lock); + + /* Get flash ready and begin erasing single block */ + + flash_unlock(); + + modifyreg32(flash_ctrl, 0, FLASH_CTRL_SECERS); + modifyreg32(flash_addr, 0, block * AT32_FLASH_PAGESIZE); + modifyreg32(flash_ctrl, 0, FLASH_CTRL_ERSTR); + + while (getreg32(flash_sts) & FLASH_STS_OBF) + { + at32_waste(); + } + + modifyreg32(flash_ctrl, FLASH_CTRL_SECERS, 0); + + nxmutex_unlock(&g_lock); + + /* Verify */ + + if (up_progmem_ispageerased(block) == 0) + { + return up_progmem_pagesize(block); /* success */ + } + else + { + return -EIO; /* failure */ + } +} + +ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) +{ + uint16_t *hword = (uint16_t *)buf; + size_t written = count; + unsigned int flash_sts; + + /* AT32 requires half-word access */ + + if (count & 1) + { + return -EINVAL; + } + + /* Check for valid address range */ + + if (addr >= AT32_FLASH_BASE) + { + addr -= AT32_FLASH_BASE; + } + + if ((addr + count) > AT32_FLASH_SIZE) + { + return -EFAULT; + } + + nxmutex_lock(&g_lock); + + /* Get flash ready and begin flashing */ + + flash_unlock(); + +#if defined(CONFIG_AT32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) + data_cache_disable(); +#endif + + modifyreg32(AT32_FLASH_CTRL, 0, FLASH_CTRL_FPRGM); + modifyreg32(AT32_FLASH_CTRL2, 0, FLASH_CTRL_FPRGM); + + for (addr += AT32_FLASH_BASE; count; count -= 2, hword++, addr += 2) + { + /* Write half-word and wait to complete */ + + putreg16(*hword, addr); + + #ifdef AT32_FLASH_BANK2_START + flash_sts = (addr < AT32_FLASH_BANK2_START *AT32_FLASH_PAGESIZE) ? \ + AT32_FLASH_STS : AT32_FLASH_STS2; + #else + flash_sts = AT32_FLASH_STS; + #endif + + while (getreg32(flash_sts) & FLASH_STS_OBF) + { + at32_waste(); + } + + /* Verify */ + + if (getreg32(flash_sts) & FLASH_STS_PRGMERR) + { + modifyreg32(AT32_FLASH_CTRL, FLASH_CTRL_FPRGM, 0); + modifyreg32(AT32_FLASH_CTRL2, FLASH_CTRL_FPRGM, 0); + nxmutex_unlock(&g_lock); + + return -EROFS; + } + + if (getreg16(addr) != *hword) + { + modifyreg32(AT32_FLASH_CTRL, FLASH_CTRL_FPRGM, 0); + modifyreg32(AT32_FLASH_CTRL2, FLASH_CTRL_FPRGM, 0); + nxmutex_unlock(&g_lock); + + return -EIO; + } + } + + modifyreg32(AT32_FLASH_CTRL, FLASH_CTRL_FPRGM, 0); + modifyreg32(AT32_FLASH_CTRL2, FLASH_CTRL_FPRGM, 0); + +#if defined(CONFIG_AT32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) + data_cache_enable(); +#endif + + nxmutex_unlock(&g_lock); + return written; +} + +uint8_t up_progmem_erasestate(void) +{ + return FLASH_ERASEDVALUE; +} + +#endif /* defined(CONFIG_AT32_AT32F43XX) */ diff --git a/arch/arm/src/at32/at32f43xxx_alarm.h b/arch/arm/src/at32/at32f43xxx_alarm.h new file mode 100644 index 0000000000..591f860168 --- /dev/null +++ b/arch/arm/src/at32/at32f43xxx_alarm.h @@ -0,0 +1,122 @@ +/**************************************************************************** + * arch/arm/src/at32/at32f43xxx_alarm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_AT32F43XXX_ALARM_H +#define __ARCH_ARM_SRC_AT32_AT32F43XXX_ALARM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifdef CONFIG_RTC_ALARM + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef void (*alm_callback_t)(void *arg, unsigned int alarmid); + +/* These features are known to map to AT32 RTC from at32F4xx and appear to + * map to beyond at32F4xx and at32L0xx there appears to be a small variant + * with at32F3 but do not map to at32F0, F1, F2 + */ + +enum alm_id_e +{ + RTC_ALARMA = 0, /* RTC ALARM A */ + RTC_ALARMB, /* RTC ALARM B */ + RTC_ALARM_LAST +}; + +/* Structure used to pass parameters to set an alarm */ + +struct alm_setalarm_s +{ + int as_id; /* enum alm_id_e */ + struct tm as_time; /* Alarm expiration time */ + alm_callback_t as_cb; /* Callback (if non-NULL) */ + void *as_arg; /* Argument for callback */ +}; + +/* Structure used to pass parameters to query an alarm */ + +struct alm_rdalarm_s +{ + int ar_id; /* enum alm_id_e */ + struct rtc_time *ar_time; /* Argument for storing ALARM RTC time */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_rtc_setalarm + * + * Description: + * Set an alarm to an absolute time using associated hardware. + * + * Input Parameters: + * alminfo - Information about the alarm configuration. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int at32_rtc_setalarm(struct alm_setalarm_s *alminfo); + +/**************************************************************************** + * Name: at32_rtc_rdalarm + * + * Description: + * Query an alarm configured in hardware. + * + * Input Parameters: + * alminfo - Information about the alarm configuration. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int at32_rtc_rdalarm(struct alm_rdalarm_s *alminfo); + +/**************************************************************************** + * Name: at32_rtc_cancelalarm + * + * Description: + * Cancel an alarm. + * + * Input Parameters: + * alarmid - Identifies the alarm to be cancelled + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int at32_rtc_cancelalarm(enum alm_id_e alarmid); + +#endif /* CONFIG_RTC_ALARM */ +#endif /* __ARCH_ARM_SRC_AT32_AT32F40XXX_ALARM_H */ diff --git a/arch/arm/src/at32/at32f43xxx_rcc.c b/arch/arm/src/at32/at32f43xxx_rcc.c new file mode 100644 index 0000000000..66710d7dc2 --- /dev/null +++ b/arch/arm/src/at32/at32f43xxx_rcc.c @@ -0,0 +1,755 @@ +/**************************************************************************** + * arch/arm/src/at32/at32f43xxx_rcc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "chip.h" +#include "at32_pwr.h" +#include "hardware/at32f43xxx_rcc.h" +#include "itm_syslog.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Allow up to 100 milliseconds for the high speed clock to become ready. + * that is a very long delay, but if the clock does not become ready we are + * hosed anyway. Normally this is very fast, but I have seen at least one + * board that required this long, long timeout for the HSE to be ready. + */ + +#define HSERDY_TIMEOUT (100 * CONFIG_BOARD_LOOPSPERMSEC) + +/* Same for HSI */ + +#define HSIRDY_TIMEOUT HSERDY_TIMEOUT + +/* HSE divisor to yield ~1MHz RTC clock */ + +#define HSE_DIVISOR (AT32_HSE_FREQUENCY + 500000) / 1000000 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rcc_reset + * + * Description: + * Reset the RCC clock configuration to the default reset state + * + ****************************************************************************/ + +static inline void rcc_reset(void) +{ + uint32_t regval; + + /* enable pwc clock */ + + regval = getreg32(AT32_CRM_APB1EN); + regval |= CRM_APB1EN_PWCEN; + putreg32(regval, AT32_CRM_APB1EN); + + /* set ldo output 1.3V */ + + regval = getreg32(AT32_PWC_LDOOV); + regval &= ~PWC_LDOOV_SEL_MASK; + regval |= PWC_LDOOV_1V3; + putreg32(regval, AT32_PWC_LDOOV); + + /* set flash div 3 */ + + regval = getreg32(AT32_FLASH_DIVR); + regval &= ~FLASH_DIVR_FDIV_MASK; + regval |= FLASH_DIVR_FDIV_3; + putreg32(regval, AT32_FLASH_DIVR); + +#if (AT32_SYSCLK_FREQUENCY <= 192000000ul) + /* enable Flash non-zero wait area boost */ + + regval = getreg32(AT32_FLASH_PSR); + regval |= FLASH_PSR_NZW_BST; + putreg32(regval, AT32_FLASH_PSR); +#endif + + /* Flash continue read enable */ + + regval = getreg32(AT32_FLASH_CONTR); + regval |= FLASH_CONTR_EN; + putreg32(regval, AT32_FLASH_CONTR); + + /* reset the crm clock configuration to the default reset state */ + + /* set hicken bit */ + + regval = getreg32(AT32_CRM_CTRL); + regval |= CRM_CTRL_HICKEN; + putreg32(regval, AT32_CRM_CTRL); + + /* Wait High speed internal crystal stable */ + + while ((getreg32(AT32_CRM_CTRL) & CRM_CTRL_HICKSTBL) != \ + CRM_CTRL_HICKSTBL); + + /* reset hexten, hextbyps, cfden and pllen bits */ + + regval = getreg32(AT32_CRM_CTRL); + regval &= ~CRM_CTRL_HEXTEN; + regval &= ~CRM_CTRL_HEXTBYPS; + regval &= ~CRM_CTRL_CFDEN; + regval &= ~CRM_CTRL_PLLEN; + putreg32(regval, AT32_CRM_CTRL); + + /* reset cfg register, include sclk switch, ahbdiv, + * apb1div, apb2div, adcdiv, clkout bits + */ + + regval = 0; + putreg32(regval, AT32_CRM_CFG); + + /* reset pllms pllns pllfr pllrcs bits */ + + regval = 0x00033002ul; + putreg32(regval, AT32_CRM_PLL_CFG); + + /* reset clkout[3], usbbufs, hickdiv, clkoutdiv */ + + regval = 0; + putreg32(regval, AT32_CRM_MISC1); + + /* disable all interrupts enable and clear pending bits */ + + regval = 0x009f0000ul; + putreg32(regval, AT32_CRM_CLKINT); +} + +/**************************************************************************** + * Name: rcc_enableahb1 + * + * Description: + * Enable selected AHB1 peripherals + * + ****************************************************************************/ + +static inline void rcc_enableahb1(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the AHB1ENR register to enabled the + * selected AHB1 peripherals. + */ + + regval = getreg32(AT32_CRM_AHBEN1); + + /* Enable GPIOA, GPIOB, .... GPIOH */ + +#if AT32_NGPIO_PORTS > 0 + regval |= (CRM_AHBEN1_GPIOAEN +#if AT32_NGPIO_PORTS > 1 + | CRM_AHBEN1_GPIOBEN +#endif +#if AT32_NGPIO_PORTS > 2 + | CRM_AHBEN1_GPIOCEN +#endif +#if AT32_NGPIO_PORTS > 3 + | CRM_AHBEN1_GPIODEN +#endif +#if AT32_NGPIO_PORTS > 4 + | CRM_AHBEN1_GPIOEEN +#endif +#if AT32_NGPIO_PORTS > 5 + | CRM_AHBEN1_GPIOFEN +#endif +#if AT32_NGPIO_PORTS > 6 + | CRM_AHBEN1_GPIOGEN +#endif +#if AT32_NGPIO_PORTS > 7 + | CRM_AHBEN1_GPIOHEN +#endif + ); +#endif + +#ifdef CONFIG_AT32_CRC + /* CRC clock enable */ + + regval |= CRM_AHBEN1_CRCEN; +#endif + +#ifdef CONFIG_AT32_EDMA + /* EDMA clock enable */ + + regval |= CRM_AHBEN1_EDMAEN; +#endif + +#ifdef CONFIG_AT32_DMA1 + /* DMA 1 clock enable */ + + regval |= CRM_AHBEN1_DMA1EN; +#endif + +#ifdef CONFIG_AT32_DMA2 + /* DMA 2 clock enable */ + + regval |= CRM_AHBEN1_DMA2EN; +#endif + +#ifdef CONFIG_AT32_ETHMAC + /* Ethernet MAC clocking */ + + regval |= (CRM_AHBEN1_EMACEN | CRM_AHBEN1_EMACTXEN + | CRM_AHBEN1_EMACRXEN); + +#ifdef CONFIG_AT32_ETH_PTP + /* Precision Time Protocol (PTP) */ + + regval |= CRM_AHBEN1_EMACPTPEN; + +#endif +#endif + +#ifdef CONFIG_AT32_OTGFS2 + regval |= CRM_AHBEN1_OTGFS2EN; +#endif + + putreg32(regval, AT32_CRM_AHBEN1); /* Enable peripherals */ +} + +/**************************************************************************** + * Name: rcc_enableahb2 + * + * Description: + * Enable selected AHB2 peripherals + * + ****************************************************************************/ + +static inline void rcc_enableahb2(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the AHB2ENR register to enabled the + * selected AHB2 peripherals. + */ + + regval = getreg32(AT32_CRM_AHBEN2); + +#ifdef CONFIG_AT32_DVP + /* Camera interface enable */ + + regval |= CRM_AHBEN2_DVPEN; +#endif + +#ifdef CONFIG_AT32_OTGFS + /* USBOTG FS1 modules clock enable */ + + regval |= CRM_AHBEN2_OTGFS1EN; +#endif + +#ifdef CONFIG_AT32_SDIO + /* SDIO1 clock enable */ + + regval |= CRM_AHBEN2_SDIO1EN; +#endif + + putreg32(regval, AT32_CRM_AHBEN2); /* Enable peripherals */ +} + +/**************************************************************************** + * Name: rcc_enableahb3 + * + * Description: + * Enable selected AHB3 peripherals + * + ****************************************************************************/ + +static inline void rcc_enableahb3(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the AHB3ENR register to enabled the + * selected AHB3 peripherals. + */ + + regval = getreg32(AT32_CRM_AHBEN3); + +#ifdef CONFIG_AT32_XMC + /* Flexible static memory controller module clock enable */ + + regval |= CRM_AHBEN3_XMCEN; + +#endif + +#ifdef CONFIG_AT32_QSPI1 + /* QSPI1 clock enable */ + + regval |= CRM_AHBEN3_QSPI1EN; +#endif + +#ifdef CONFIG_AT32_QSPI2 + /* QSPI2 clock enable */ + + regval |= CRM_AHBEN3_QSPI2EN; +#endif + +#ifdef CONFIG_AT32_SDIO2 + /* SDIO2 clock enable */ + + regval |= CRM_AHBEN3_SDIO2EN; +#endif + + putreg32(regval, AT32_CRM_AHBEN3); /* Enable peripherals */ +} + +/**************************************************************************** + * Name: rcc_enableapb1 + * + * Description: + * Enable selected APB1 peripherals + * + ****************************************************************************/ + +static inline void rcc_enableapb1(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the APB1ENR register to enabled the + * selected APB1 peripherals. + */ + + regval = getreg32(AT32_CRM_APB1EN); + +#ifdef CONFIG_AT32_TRM2 + /* TRM2 clock enable */ + + regval |= CRM_APB1EN_TMR2EN; +#endif + +#ifdef CONFIG_AT32_TRM3 + /* TRM3 clock enable */ + + regval |= CRM_APB1EN_TMR3EN; +#endif + +#ifdef CONFIG_AT32_TRM4 + /* TRM4 clock enable */ + + regval |= CRM_APB1EN_TMR4EN; +#endif + +#ifdef CONFIG_AT32_TRM5 + /* TRM5 clock enable */ + + regval |= CRM_APB1EN_TMR5EN; +#endif + +#ifdef CONFIG_AT32_TRM6 + /* TRM6 clock enable */ + + regval |= CRM_APB1EN_TMR6EN; +#endif + +#ifdef CONFIG_AT32_TRM7 + /* TRM7 clock enable */ + + regval |= CRM_APB1EN_TMR7EN; +#endif + +#ifdef CONFIG_AT32_TRM12 + /* TRM12 clock enable */ + + regval |= CRM_APB1EN_TMR12EN; +#endif + +#ifdef CONFIG_AT32_TRM13 + /* TRM13 clock enable */ + + regval |= CRM_APB1EN_TMR13EN; +#endif + +#ifdef CONFIG_AT32_TRM14 + /* TRM14 clock enable */ + + regval |= CRM_APB1EN_TMR14EN; +#endif + +#ifdef CONFIG_AT32_WWDT + /* Window watchdog clock enable */ + + regval |= CRM_APB1EN_WWDTEN; +#endif + +#ifdef CONFIG_AT32_SPI2 + /* SPI2 clock enable */ + + regval |= CRM_APB1EN_SPI2EN; +#endif + +#ifdef CONFIG_AT32_SPI3 + /* SPI3 clock enable */ + + regval |= CRM_APB1EN_SPI3EN; +#endif + +#ifdef CONFIG_AT32_USART2 + /* USART 2 clock enable */ + + regval |= CRM_APB1EN_USART2EN; +#endif + +#ifdef CONFIG_AT32_USART3 + /* USART3 clock enable */ + + regval |= CRM_APB1EN_USART3EN; +#endif + +#ifdef CONFIG_AT32_UART4 + /* UART4 clock enable */ + + regval |= CRM_APB1EN_UART4EN; +#endif + +#ifdef CONFIG_AT32_UART5 + /* UART5 clock enable */ + + regval |= CRM_APB1EN_UART5EN; +#endif + +#ifdef CONFIG_AT32_I2C1 + /* I2C1 clock enable */ + + regval |= CRM_APB1EN_I2C1EN; +#endif + +#ifdef CONFIG_AT32_I2C2 + /* I2C2 clock enable */ + + regval |= CRM_APB1EN_I2C2EN; +#endif + +#ifdef CONFIG_AT32_I2C3 + /* I2C3 clock enable */ + + regval |= CRM_APB1EN_I2C3EN; +#endif + +#ifdef CONFIG_AT32_CAN1 + /* CAN 1 clock enable */ + + regval |= CRM_APB1EN_CAN1EN; +#endif + +#ifdef CONFIG_AT32_CAN2 + /* CAN2 clock enable */ + + regval |= CRM_APB1EN_CAN2EN ; +#endif + + /* Power interface clock enable. The PWR block is always enabled so that + * we can set the internal voltage regulator for maximum performance. + */ + + regval |= CRM_APB1EN_PWCEN; + +#if defined (CONFIG_AT32_DAC) + /* DAC interface clock enable */ + + regval |= CRM_APB1EN_DACEN; +#endif + +#ifdef CONFIG_AT32_UART7 + /* UART7 clock enable */ + + regval |= CRM_APB1EN_UART7EN; +#endif + +#ifdef CONFIG_AT32_UART8 + /* UART8 clock enable */ + + regval |= CRM_APB1EN_UART8EN; +#endif + + putreg32(regval, AT32_CRM_APB1EN); /* Enable peripherals */ +} + +/**************************************************************************** + * Name: rcc_enableapb2 + * + * Description: + * Enable selected APB2 peripherals + * + ****************************************************************************/ + +static inline void rcc_enableapb2(void) +{ + uint32_t regval; + + /* Set the appropriate bits in the APB2ENR register to enabled the + * selected APB2 peripherals. + */ + + regval = getreg32(AT32_CRM_APB2EN); + +#ifdef CONFIG_AT32_TRM1 + /* TRM1 clock enable */ + + regval |= CRM_APB2EN_TMR1EN; +#endif + +#ifdef CONFIG_AT32_TRM8 + /* TRM8 clock enable */ + + regval |= CRM_APB2EN_TMR8EN; +#endif + +#ifdef CONFIG_AT32_USART1 + /* USART1 clock enable */ + + regval |= CRM_APB2EN_USART1EN; +#endif + +#ifdef CONFIG_AT32_USART6 + /* USART6 clock enable */ + + regval |= CRM_APB2EN_USART6EN; +#endif + +#ifdef CONFIG_AT32_ADC1 + /* ADC1 clock enable */ + + regval |= CRM_APB2EN_ADC1EN; +#endif + +#ifdef CONFIG_AT32_ADC2 + /* ADC2 clock enable */ + + regval |= CRM_APB2EN_ADC2EN; +#endif + +#ifdef CONFIG_AT32_ADC3 + /* ADC3 clock enable */ + + regval |= CRM_APB2EN_ADC3EN; +#endif + +#ifdef CONFIG_AT32_SPI1 + /* SPI1 clock enable */ + + regval |= CRM_APB2EN_SPI1EN; +#endif + +#ifdef CONFIG_AT32_SPI4 + /* SPI4 clock enable */ + + regval |= CRM_APB2EN_SPI4EN; +#endif + +#ifdef CONFIG_AT32_SYSCFG + /* System configuration controller clock enable */ + + regval |= CRM_APB2EN_SCFGEN; +#endif + +#ifdef CONFIG_AT32_TRM9 + /* TRM9 clock enable */ + + regval |= CRM_APB2EN_TMR9EN; +#endif + +#ifdef CONFIG_AT32_TRM10 + /* TRM10 clock enable */ + + regval |= CRM_APB2EN_TMR10EN; +#endif + +#ifdef CONFIG_AT32_TRM11 + /* TRM11 clock enable */ + + regval |= CRM_APB2EN_TMR11EN; +#endif + +#ifdef CONFIG_AT32_TRM20 + /* TRM20 clock enable */ + + regval |= CRM_APB2EN_TMR20EN; +#endif + +#ifdef CONFIG_AT32_ACC + /* ACC clock enable */ + + regval |= CRM_APB2EN_ACCEN; +#endif + + putreg32(regval, AT32_CRM_APB2EN); /* Enable peripherals */ +} + +/**************************************************************************** + * Name: at32_stdclockconfig + * + * Description: + * Called to change to new clock based on settings in board.h + * + * NOTE: This logic would need to be extended if you need to select low- + * power clocking modes! + ****************************************************************************/ + +#ifndef CONFIG_ARCH_BOARD_AT32_CUSTOM_CLOCKCONFIG +static void at32_stdclockconfig(void) +{ + uint32_t regval; + + /* config external crystal as clock source */ + + regval = getreg32(AT32_CRM_CTRL); + regval &= ~CRM_CTRL_HICKEN; + regval |= CRM_CTRL_HEXTEN; + putreg32(regval, AT32_CRM_CTRL); + + /* Wait High speed external crystal stable */ + + while ((getreg32(AT32_CRM_CTRL) & CRM_CTRL_HEXTSTBL) != \ + CRM_CTRL_HEXTSTBL); + + regval = getreg32(AT32_CRM_CFG); + regval &= ~CRM_CFG_SCLKSEL_MASK; + regval |= CRM_CFG_SEL_HEXT; + putreg32(regval, AT32_CRM_CFG); + + /* config PLL */ + + regval = getreg32(AT32_CRM_PLL_CFG); + regval |= CRM_PLL_CFG_PLLRCS; + regval &= ~CRM_PLL_CFG_PLL_MS_MASK; + regval |= AT32_PLLCFG_PLLM; + + regval &= ~CRM_PLL_CFG_PLL_NS_MASK; + regval |= AT32_PLLCFG_PLLN; + + regval &= ~CRM_PLL_CFG_PLL_FR_MASK; + regval |= AT32_PLLCFG_PLLP; + putreg32(regval, AT32_CRM_PLL_CFG); + + /* enable pll */ + + regval = getreg32(AT32_CRM_CTRL); + regval |= CRM_CTRL_PLLEN; + putreg32(regval, AT32_CRM_CTRL); + while ((getreg32(AT32_CRM_CTRL) & CRM_CTRL_PLLSTBL) != \ + CRM_CTRL_PLLSTBL); + + regval = getreg32(AT32_CRM_CFG); + regval &= ~CRM_CFG_AHBDIV_MASK; + regval |= CRM_CFG_AHBDIV_NONE; /* ahb div 1 */ + regval &= ~CRM_CFG_APB1DIV_MASK; + regval |= CRM_CFG_APB1DIV_2; /* apb1 div 2 */ + regval &= ~CRM_CFG_APB2DIV_MASK; + regval |= CRM_CFG_APB2DIV_2; /* apb2 div 2 */ + putreg32(regval, AT32_CRM_CFG); + + /* entry step mode */ + + regval = getreg32(AT32_CRM_MISC2); + regval &= ~CRM_MISC2_AUTO_STEP_EN_MASK; + regval |= CRM_MISC2_AUTO_STEP_EN_ENABLE; + putreg32(regval, AT32_CRM_MISC2); + + /* config pll as system clock */ + + regval = getreg32(AT32_CRM_CFG); + regval &= ~CRM_CFG_SCLKSEL_MASK; + regval |= CRM_CFG_SEL_PLL; + putreg32(regval, AT32_CRM_CFG); + + while ((getreg32(AT32_CRM_CFG) & CRM_CFG_SCLKSTSL_MASK) != \ + CRM_CFG_STS_PLL); + + /* exit step mode */ + + regval = getreg32(AT32_CRM_MISC2); + regval &= ~CRM_MISC2_AUTO_STEP_EN_MASK; + regval |= CRM_MISC2_AUTO_STEP_EN_DISABLE; + putreg32(regval, AT32_CRM_MISC2); + +#if defined(CONFIG_AT32_OTGFS) || defined(CONFIG_AT32_OTGFS2) + + /* set usbfs clock use pll */ + + regval = getreg32(AT32_CRM_MISC1); + regval &= ~CRM_MISC1_HICK_TO_USB; + putreg32(regval, AT32_CRM_MISC1); + + /* usbfs clock div */ + + regval = getreg32(AT32_CRM_MISC2); + regval &= ~CRM_MISC2_USBDIV_MASK; + regval |= USB_CONFIG_USBDIV; + putreg32(regval, AT32_CRM_MISC2); + +#endif +} +#endif + +/**************************************************************************** + * Name: efm32_itm_syslog + * + * Description: + * Enable Serial wire output pin, configure debug clocking, and enable + * ITM syslog support. + * + ****************************************************************************/ + +#ifdef CONFIG_ARMV7M_ITMSYSLOG +static inline void rcc_itm_syslog(void) +{ + uint32_t regval; + + regval = getreg32(AT32_DEBUG_CTRL); + regval &= ~DEBUG_CTRL_SLEEP_DEBUG; + putreg32(regval, AT32_DEBUG_CTRL); +} +#else +# define rcc_itm_syslog() +#endif + +/**************************************************************************** + * Name: rcc_enableperiphals + ****************************************************************************/ + +static inline void rcc_enableperipherals(void) +{ + rcc_enableahb1(); + rcc_enableahb2(); + rcc_enableahb3(); + rcc_enableapb1(); + rcc_enableapb2(); + rcc_itm_syslog(); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ diff --git a/arch/arm/src/at32/at32f43xxx_rtcc.c b/arch/arm/src/at32/at32f43xxx_rtcc.c new file mode 100644 index 0000000000..5cea33a4bc --- /dev/null +++ b/arch/arm/src/at32/at32f43xxx_rtcc.c @@ -0,0 +1,1626 @@ +/**************************************************************************** + * arch/arm/src/at32/at32f43xxx_rtcc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arm_internal.h" +#include "at32_rcc.h" +#include "at32_pwr.h" +#include "at32_exti.h" +#include "at32_rtc.h" + +#include + +#ifdef CONFIG_AT32_RTC + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* This RTC implementation supports + * - date/time RTC hardware + * - extended functions Alarm A and B for AT32F4xx and onwards + * */ + +#ifndef CONFIG_RTC_DATETIME +# error "CONFIG_RTC_DATETIME must be set to use this driver" +#endif + +#ifdef CONFIG_RTC_HIRES +# error "CONFIG_RTC_HIRES must NOT be set with this driver" +#endif + +#ifndef CONFIG_AT32_PWR +# error "CONFIG_AT32_PWR must selected to use this driver" +#endif + +/* Constants ****************************************************************/ + +#define SYNCHRO_TIMEOUT (0x00020000) +#define INITMODE_TIMEOUT (0x00010000) + +/* Proxy definitions to make the same code work for all the AT32 series *****/ + +# define AT32_RCC_XXX AT32_CRM_BPDC +# define RCC_XXX_YYYRST CRM_BPDC_BPDRST +# define RCC_XXX_RTCEN CRM_BPDC_ERTCEN +# define RCC_XXX_RTCSEL_MASK CRM_BPDC_ERTCSEL_MASK +# define RCC_XXX_RTCSEL_LSE CRM_BPDC_ERTCSEL_LEXT +# define RCC_XXX_RTCSEL_LSI CRM_BPDC_ERTCSEL_LICK +# define RCC_XXX_RTCSEL_HSE CRM_BPDC_ERTCSEL_HEXT + +/* Time conversions */ + +#define MINUTES_IN_HOUR 60 +#define HOURS_IN_DAY 24 + +#define hours_add(parm_hrs) \ + time->tm_hour += parm_hrs;\ + if ((HOURS_IN_DAY-1) < (time->tm_hour))\ + {\ + time->tm_hour = (parm_hrs - HOURS_IN_DAY);\ + } + +#define RTC_ALRMR_DIS_MASK (RTC_ALRMR_MSK4 | RTC_ALRMR_MSK3 | \ + RTC_ALRMR_MSK2 | RTC_ALRMR_MSK1) +#define RTC_ALRMR_DIS_DATE_MASK (RTC_ALRMR_MSK4) +#define RTC_ALRMR_ENABLE (0) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +typedef unsigned int rtc_alarmreg_t; + +struct alm_cbinfo_s +{ + volatile alm_callback_t ac_cb; /* Client callback function */ + volatile void *ac_arg; /* Argument to pass with the callback function */ +}; +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +/* Callback to use when an EXTI is activated */ + +static struct alm_cbinfo_s g_alarmcb[RTC_ALARM_LAST]; +static bool g_alarm_enabled; /* True: Alarm interrupts are enabled */ +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* g_rtc_enabled is set true after the RTC has successfully initialized */ + +volatile bool g_rtc_enabled = false; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int rtchw_check_alrawf(void); +static int rtchw_set_alrmar(rtc_alarmreg_t alarmreg); +#if CONFIG_RTC_NALARMS > 1 +static int rtchw_check_alrbwf(void); +static int rtchw_set_alrmbr(rtc_alarmreg_t alarmreg); +#endif +static inline void rtc_enable_alarm(void); +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rtc_dumpregs + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_RTC_INFO +static void rtc_dumpregs(const char *msg) +{ + int rtc_state; + + rtcinfo("%s:\n", msg); + rtcinfo(" TR: %08x\n", getreg32(AT32_RTC_TR)); + rtcinfo(" DR: %08x\n", getreg32(AT32_RTC_DR)); + rtcinfo(" CR: %08x\n", getreg32(AT32_RTC_CR)); + rtcinfo(" ISR: %08x\n", getreg32(AT32_RTC_ISR)); + rtcinfo(" PRER: %08x\n", getreg32(AT32_RTC_PRER)); + rtcinfo(" WUTR: %08x\n", getreg32(AT32_RTC_WUTR)); + rtcinfo(" ALRMAR: %08x\n", getreg32(AT32_RTC_ALRMAR)); + rtcinfo(" ALRMBR: %08x\n", getreg32(AT32_RTC_ALRMBR)); + rtcinfo(" SHIFTR: %08x\n", getreg32(AT32_RTC_SHIFTR)); + rtcinfo(" TSTR: %08x\n", getreg32(AT32_RTC_TSTR)); + rtcinfo(" TSDR: %08x\n", getreg32(AT32_RTC_TSDR)); + rtcinfo(" TSSSR: %08x\n", getreg32(AT32_RTC_TSSSR)); + rtcinfo(" CALR: %08x\n", getreg32(AT32_RTC_CALR)); + rtcinfo(" TAFCR: %08x\n", getreg32(AT32_RTC_TAFCR)); + rtcinfo("ALRMASSR: %08x\n", getreg32(AT32_RTC_ALRMASSR)); + rtcinfo("ALRMBSSR: %08x\n", getreg32(AT32_RTC_ALRMBSSR)); + rtcinfo("MAGICREG: %08x\n", getreg32(RTC_MAGIC_REG)); + + rtc_state = + ((getreg32(AT32_EXTI_RTSR) & EXTI_RTC_ALARM) ? 0x1000 : 0) | + ((getreg32(AT32_EXTI_FTSR) & EXTI_RTC_ALARM) ? 0x0100 : 0) | + ((getreg32(AT32_EXTI_IMR) & EXTI_RTC_ALARM) ? 0x0010 : 0) | + ((getreg32(AT32_EXTI_EMR) & EXTI_RTC_ALARM) ? 0x0001 : 0); + rtcinfo("EXTI (RTSR FTSR ISR EVT): %01x\n", rtc_state); +} +#else +# define rtc_dumpregs(msg) +#endif + +/**************************************************************************** + * Name: rtc_dumptime + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_RTC_INFO +static void rtc_dumptime(const struct tm *tp, const char *msg) +{ + rtcinfo("%s:\n", msg); + rtcinfo(" tm_sec: %08x\n", tp->tm_sec); + rtcinfo(" tm_min: %08x\n", tp->tm_min); + rtcinfo(" tm_hour: %08x\n", tp->tm_hour); + rtcinfo(" tm_mday: %08x\n", tp->tm_mday); + rtcinfo(" tm_mon: %08x\n", tp->tm_mon); + rtcinfo(" tm_year: %08x\n", tp->tm_year); +} +#else +# define rtc_dumptime(tp, msg) +#endif + +/**************************************************************************** + * Name: rtc_wprunlock + * + * Description: + * Disable RTC write protection + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void rtc_wprunlock(void) +{ + /* Enable write access to the backup domain (RTC registers, RTC backup data + * registers and backup SRAM). + */ + + at32_pwr_enablebkp(true); + + /* The following steps are required to unlock the write protection on all + * the RTC registers (except for RTC_ISR[13:8], RTC_TAFCR, and RTC_BKPxR): + * + * 1. Write 0xCA into the RTC_WPR register. + * 2. Write 0x53 into the RTC_WPR register. + * + * Writing a wrong key re-activates the write protection. + */ + + putreg32(0xca, AT32_RTC_WPR); + putreg32(0x53, AT32_RTC_WPR); +} + +/**************************************************************************** + * Name: rtc_wprlock + * + * Description: + * Enable RTC write protection + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void rtc_wprlock(void) +{ + /* Writing any wrong key re-activates the write protection. */ + + putreg32(0xff, AT32_RTC_WPR); + + /* Disable write access to the backup domain (RTC registers, RTC backup + * data registers and backup SRAM). + */ + + at32_pwr_enablebkp(false); +} + +/**************************************************************************** + * Name: rtc_synchwait + * + * Description: + * Waits until the RTC Time and Date registers (RTC_TR and RTC_DR) are + * synchronized with RTC APB clock. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +static int rtc_synchwait(void) +{ + volatile uint32_t timeout; + uint32_t regval; + int ret; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Clear Registers synchronization flag (RSF) */ + + regval = getreg32(AT32_RTC_ISR); + regval &= ~RTC_ISR_RSF; + putreg32(regval, AT32_RTC_ISR); + + /* Now wait the registers to become synchronised */ + + ret = -ETIMEDOUT; + for (timeout = 0; timeout < SYNCHRO_TIMEOUT; timeout++) + { + regval = getreg32(AT32_RTC_ISR); + if ((regval & RTC_ISR_RSF) != 0) + { + /* Synchronized */ + + ret = OK; + break; + } + } + + /* Re-enable the write protection for RTC registers */ + + rtc_wprlock(); + return ret; +} + +/**************************************************************************** + * Name: rtc_enterinit + * + * Description: + * Enter RTC initialization mode. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +static int rtc_enterinit(void) +{ + volatile uint32_t timeout; + uint32_t regval; + int ret; + + /* Check if the Initialization mode is already set */ + + regval = getreg32(AT32_RTC_ISR); + + ret = OK; + if ((regval & RTC_ISR_INITF) == 0) + { + /* Set the Initialization mode */ + + putreg32(RTC_ISR_INIT, AT32_RTC_ISR); + + /* Wait until the RTC is in the INIT state (or a timeout occurs) */ + + ret = -ETIMEDOUT; + for (timeout = 0; timeout < INITMODE_TIMEOUT; timeout++) + { + regval = getreg32(AT32_RTC_ISR); + if ((regval & RTC_ISR_INITF) != 0) + { + ret = OK; + break; + } + } + } + + return ret; +} + +/**************************************************************************** + * Name: rtc_exitinit + * + * Description: + * Exit RTC initialization mode. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +static void rtc_exitinit(void) +{ + uint32_t regval; + + regval = getreg32(AT32_RTC_ISR); + regval &= ~(RTC_ISR_INIT); + putreg32(regval, AT32_RTC_ISR); +} + +/**************************************************************************** + * Name: rtc_bin2bcd + * + * Description: + * Converts a 2 digit binary to BCD format + * + * Input Parameters: + * value - The byte to be converted. + * + * Returned Value: + * The value in BCD representation + * + ****************************************************************************/ + +static uint32_t rtc_bin2bcd(int value) +{ + uint32_t msbcd = 0; + + while (value >= 10) + { + msbcd++; + value -= 10; + } + + return (msbcd << 4) | value; +} + +/**************************************************************************** + * Name: rtc_bin2bcd + * + * Description: + * Convert from 2 digit BCD to binary. + * + * Input Parameters: + * value - The BCD value to be converted. + * + * Returned Value: + * The value in binary representation + * + ****************************************************************************/ + +static int rtc_bcd2bin(uint32_t value) +{ + uint32_t tens = (value >> 4) * 10; + return (int)(tens + (value & 0x0f)); +} + +/**************************************************************************** + * Name: rtc_setup + * + * Description: + * Performs first time configuration of the RTC. A special value written + * into back-up register 0 will prevent this function from being called on + * sub-sequent resets or power up. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +static int rtc_setup(void) +{ + uint32_t regval; + int ret; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Set Initialization mode */ + + ret = rtc_enterinit(); + if (ret == OK) + { + /* Set the 24 hour format by clearing the FMT bit in the RTC + * control register + */ + + regval = getreg32(AT32_RTC_CR); + regval &= ~RTC_CR_FMT; + putreg32(regval, AT32_RTC_CR); + + /* Configure RTC pre-scaler with the required values */ + +#ifdef CONFIG_AT32_RTC_HSECLOCK + + putreg32(((uint32_t)7999 << RTC_PRER_PREDIV_S_SHIFT) | + ((uint32_t)124 << RTC_PRER_PREDIV_A_SHIFT), + AT32_RTC_PRER); +#else + /* Correct values for 32.768 KHz LSE clock and inaccurate LSI clock */ + + putreg32(((uint32_t)0xff << RTC_PRER_PREDIV_S_SHIFT) | + ((uint32_t)0x7f << RTC_PRER_PREDIV_A_SHIFT), + AT32_RTC_PRER); +#endif + + /* Exit RTC initialization mode */ + + rtc_exitinit(); + } + + /* Re-enable the write protection for RTC registers */ + + rtc_wprlock(); + + return ret; +} + +/**************************************************************************** + * Name: rtc_resume + * + * Description: + * Called when the RTC was already initialized on a previous power cycle. + * This just brings the RTC back into full operation. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +static void rtc_resume(void) +{ +#ifdef CONFIG_RTC_ALARM + uint32_t regval; + + /* Clear the RTC alarm flags */ + + regval = getreg32(AT32_RTC_ISR); + regval &= ~(RTC_ISR_ALRAF | RTC_ISR_ALRBF); + putreg32(regval, AT32_RTC_ISR); + + /* Clear the RTC Alarm Pending bit */ + + putreg32(EXTI_RTC_ALARM, AT32_EXTI_PR); +#endif +} + +/**************************************************************************** + * Name: at32_rtc_alarm_handler + * + * Description: + * RTC ALARM interrupt service routine through the EXTI line + * + * Input Parameters: + * irq - The IRQ number that generated the interrupt + * context - Architecture specific register save information. + * + * Returned Value: + * Zero (OK) on success; A negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int at32_rtc_alarm_handler(int irq, void *context, void *arg) +{ + struct alm_cbinfo_s *cbinfo; + alm_callback_t cb; + void *cb_arg; + uint32_t isr; + uint32_t cr; + int ret = OK; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + isr = getreg32(AT32_RTC_ISR); + + /* Check for EXTI from Alarm A or B and handle according */ + + if ((isr & RTC_ISR_ALRAF) != 0) + { + cr = getreg32(AT32_RTC_CR); + if ((cr & RTC_CR_ALRAIE) != 0) + { + cbinfo = &g_alarmcb[RTC_ALARMA]; + if (cbinfo->ac_cb != NULL) + { + /* Alarm A callback */ + + cb = cbinfo->ac_cb; + cb_arg = (void *)cbinfo->ac_arg; + + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + + cb(cb_arg, RTC_ALARMA); + } + + isr = getreg32(AT32_RTC_ISR) & ~RTC_ISR_ALRAF; + putreg32(isr, AT32_RTC_ISR); + } + } + +#if CONFIG_RTC_NALARMS > 1 + if ((isr & RTC_ISR_ALRBF) != 0) + { + cr = getreg32(AT32_RTC_CR); + if ((cr & RTC_CR_ALRBIE) != 0) + { + cbinfo = &g_alarmcb[RTC_ALARMB]; + if (cbinfo->ac_cb != NULL) + { + /* Alarm B callback */ + + cb = cbinfo->ac_cb; + cb_arg = (void *)cbinfo->ac_arg; + + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + + cb(cb_arg, RTC_ALARMB); + } + + isr = getreg32(AT32_RTC_ISR) & ~RTC_ISR_ALRBF; + putreg32(isr, AT32_RTC_ISR); + } + } +#endif + + /* Re-enable the write protection for RTC registers */ + + rtc_wprlock(); + return ret; +} +#endif + +/**************************************************************************** + * Name: rtchw_check_alrXwf X= a or B + * + * Description: + * Check registers + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int rtchw_check_alrawf(void) +{ + volatile uint32_t timeout; + uint32_t regval; + int ret = -ETIMEDOUT; + + /* Check RTC_ISR ALRAWF for access to alarm register, + * Can take 2 RTCCLK cycles or timeout + * CubeMX use GetTick. + */ + + for (timeout = 0; timeout < INITMODE_TIMEOUT; timeout++) + { + regval = getreg32(AT32_RTC_ISR); + if ((regval & RTC_ISR_ALRAWF) != 0) + { + ret = OK; + break; + } + } + + return ret; +} +#endif + +#if defined(CONFIG_RTC_ALARM) && CONFIG_RTC_NALARMS > 1 +static int rtchw_check_alrbwf(void) +{ + volatile uint32_t timeout; + uint32_t regval; + int ret = -ETIMEDOUT; + + /* Check RTC_ISR ALRBWF for access to alarm register, + * can take 2 RTCCLK cycles or timeout + * CubeMX use GetTick. + */ + + for (timeout = 0; timeout < INITMODE_TIMEOUT; timeout++) + { + regval = getreg32(AT32_RTC_ISR); + if ((regval & RTC_ISR_ALRBWF) != 0) + { + ret = OK; + break; + } + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: at32_rtchw_set_alrmXr X is a or b + * + * Description: + * Set the alarm (A or B) hardware registers, using the required hardware + * access protocol + * + * Input Parameters: + * alarmreg - the register + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int rtchw_set_alrmar(rtc_alarmreg_t alarmreg) +{ + int ret = -EBUSY; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Disable RTC alarm & Interrupt */ + + modifyreg32(AT32_RTC_CR, (RTC_CR_ALRAE | RTC_CR_ALRAIE), 0); + + ret = rtchw_check_alrawf(); + if (ret != OK) + { + goto errout_with_wprunlock; + } + + /* Set the RTC Alarm register */ + + putreg32(alarmreg, AT32_RTC_ALRMAR); + rtcinfo(" ALRMAR: %08" PRIx32 "\n", getreg32(AT32_RTC_ALRMAR)); + + /* Enable RTC alarm */ + + modifyreg32(AT32_RTC_CR, 0, (RTC_CR_ALRAE | RTC_CR_ALRAIE)); + +errout_with_wprunlock: + rtc_wprlock(); + return ret; +} +#endif + +#if defined(CONFIG_RTC_ALARM) && CONFIG_RTC_NALARMS > 1 +static int rtchw_set_alrmbr(rtc_alarmreg_t alarmreg) +{ + int ret = -EBUSY; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Disable RTC alarm B & Interrupt B */ + + modifyreg32(AT32_RTC_CR, (RTC_CR_ALRBE | RTC_CR_ALRBIE), 0); + + ret = rtchw_check_alrbwf(); + if (ret != OK) + { + goto rtchw_set_alrmbr_exit; + } + + /* Set the RTC Alarm register */ + + putreg32(alarmreg, AT32_RTC_ALRMBR); + rtcinfo(" ALRMBR: %08x\n", getreg32(AT32_RTC_ALRMBR)); + + /* Enable RTC alarm B */ + + modifyreg32(AT32_RTC_CR, 0, (RTC_CR_ALRBE | RTC_CR_ALRBIE)); + +rtchw_set_alrmbr_exit: + rtc_wprlock(); + return ret; +} +#endif + +/**************************************************************************** + * Name: rtc_enable_alarm + * + * Description: + * Enable ALARM interrupts + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static inline void rtc_enable_alarm(void) +{ + /* Is the alarm already enabled? */ + + if (!g_alarm_enabled) + { + /* Configure RTC interrupt to catch alarm interrupts. All RTC + * interrupts are connected to the EXTI controller. To enable the + * RTC Alarm interrupt, the following sequence is required: + * + * 1. Configure and enable the EXTI Line 17 RTC ALARM in interrupt + * mode and select the rising edge sensitivity. + * For AT32F43xx + * EXTI line 21 RTC Tamper & Timestamp + * EXTI line 22 RTC Wakeup + * 2. Configure and enable the RTC_Alarm IRQ channel in the NVIC. + * 3. Configure the RTC to generate RTC alarms (Alarm A or Alarm B). + */ + + at32_exti_alarm(true, false, true, at32_rtc_alarm_handler, NULL); + g_alarm_enabled = true; + } +} +#endif + +/**************************************************************************** + * Name: at32_rtc_getalarmdatetime + * + * Description: + * Get the current date and time for a RTC alarm. + * + * Input Parameters: + * reg - RTC alarm register + * tp - The location to return the high resolution time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int at32_rtc_getalarmdatetime(rtc_alarmreg_t reg, struct tm *tp) +{ + uint32_t data; + uint32_t tmp; + + DEBUGASSERT(tp != NULL); + + /* Sample the data time register. */ + + data = getreg32(reg); + + /* Convert the RTC time to fields in struct tm format. All of the AT32 + * ranges of values correspond between struct tm and the time register. + */ + + tmp = (data & (RTC_ALRMR_SU_MASK | RTC_ALRMR_ST_MASK)) >> + RTC_ALRMR_SU_SHIFT; + tp->tm_sec = rtc_bcd2bin(tmp); + + tmp = (data & (RTC_ALRMR_MNU_MASK | RTC_ALRMR_MNT_MASK)) >> + RTC_ALRMR_MNU_SHIFT; + tp->tm_min = rtc_bcd2bin(tmp); + + tmp = (data & (RTC_ALRMR_HU_MASK | RTC_ALRMR_HT_MASK)) >> + RTC_ALRMR_HU_SHIFT; + tp->tm_hour = rtc_bcd2bin(tmp); + + tmp = (data & (RTC_ALRMR_DU_MASK | RTC_ALRMR_DT_MASK)) >> + RTC_ALRMR_DU_SHIFT; + tp->tm_mday = rtc_bcd2bin(tmp); + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_rtc_initialize + * + * Description: + * Initialize the hardware RTC per the selected configuration. This + * function is called once during the OS initialization sequence + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int up_rtc_initialize(void) +{ + uint32_t regval; + uint32_t tr_bkp; + uint32_t dr_bkp; + int ret; + int maxretry = 10; + int nretry = 0; + + /* Clocking for the PWR block must be provided. However, this is done + * unconditionally in at32f40xxx_rcc.c on power up. This done + * unconditionally because the PWR block is also needed to set the + * internal voltage regulator for maximum performance. + */ + + /* Select the clock source */ + + /* Save the token before losing it when resetting */ + + regval = getreg32(RTC_MAGIC_REG); + + at32_pwr_enablebkp(true); + + if (regval != RTC_MAGIC && regval != RTC_MAGIC_TIME_SET) + { + /* Some boards do not have the external 32khz oscillator installed, + * for those boards we must fallback to the crummy internal RC clock + * or the external high rate clock + */ + +#ifdef CONFIG_AT32_RTC_HSECLOCK + /* Use the HSE clock as the input to the RTC block */ + + rtc_dumpregs("On reset HSE"); + modifyreg32(AT32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_HSE); + +#elif defined(CONFIG_AT32_RTC_LSICLOCK) + /* Use the LSI clock as the input to the RTC block */ + + rtc_dumpregs("On reset LSI"); + modifyreg32(AT32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_LSI); + +#elif defined(CONFIG_AT32_RTC_LSECLOCK) + /* Use the LSE clock as the input to the RTC block */ + + rtc_dumpregs("On reset LSE"); + modifyreg32(AT32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_LSE); + +#endif + /* Enable the RTC Clock by setting the RTCEN bit in the RCC register */ + + modifyreg32(AT32_RCC_XXX, 0, RCC_XXX_RTCEN); + } + else /* The RTC is already in use: check if the clock source is changed */ + { +#if defined(CONFIG_AT32_RTC_HSECLOCK) || defined(CONFIG_AT32_RTC_LSICLOCK) || \ + defined(CONFIG_AT32_RTC_LSECLOCK) + + uint32_t clksrc = getreg32(AT32_RCC_XXX); + + rtc_dumpregs("On reset warm"); + +#if defined(CONFIG_AT32_RTC_HSECLOCK) + if ((clksrc & RCC_XXX_RTCSEL_MASK) != RCC_XXX_RTCSEL_HSE) +#elif defined(CONFIG_AT32_RTC_LSICLOCK) + if ((clksrc & RCC_XXX_RTCSEL_MASK) != RCC_XXX_RTCSEL_LSI) +#elif defined(CONFIG_AT32_RTC_LSECLOCK) + if ((clksrc & RCC_XXX_RTCSEL_MASK) != RCC_XXX_RTCSEL_LSE) +#endif +#endif + { + tr_bkp = getreg32(AT32_RTC_TR); + dr_bkp = getreg32(AT32_RTC_DR); + modifyreg32(AT32_RCC_XXX, 0, RCC_XXX_YYYRST); + modifyreg32(AT32_RCC_XXX, RCC_XXX_YYYRST, 0); + +#if defined(CONFIG_AT32_RTC_HSECLOCK) + /* Change to the new clock as the input to the RTC block */ + + modifyreg32(AT32_RCC_XXX, RCC_XXX_RTCSEL_MASK, + RCC_XXX_RTCSEL_HSE); + +#elif defined(CONFIG_AT32_RTC_LSICLOCK) + modifyreg32(AT32_RCC_XXX, RCC_XXX_RTCSEL_MASK, + RCC_XXX_RTCSEL_LSI); + +#elif defined(CONFIG_AT32_RTC_LSECLOCK) + modifyreg32(AT32_RCC_XXX, RCC_XXX_RTCSEL_MASK, + RCC_XXX_RTCSEL_LSE); +#endif + + putreg32(tr_bkp, AT32_RTC_TR); + putreg32(dr_bkp, AT32_RTC_DR); + + /* Remember that the RTC is initialized */ + + putreg32(RTC_MAGIC, RTC_MAGIC_REG); + + /* Enable the RTC Clock by setting the RTCEN bit in the RCC + * register + */ + + modifyreg32(AT32_RCC_XXX, 0, RCC_XXX_RTCEN); + } + } + + at32_pwr_enablebkp(false); + + /* Loop, attempting to initialize/resume the RTC. This loop is necessary + * because it seems that occasionally it takes longer to initialize the RTC + * (the actual failure is in rtc_synchwait()). + */ + + do + { + /* Wait for the RTC Time and Date registers to be synchronized with RTC + * APB clock. + */ + + ret = rtc_synchwait(); + + /* Check that rtc_syncwait() returned successfully */ + + switch (ret) + { + case OK: + { + rtcinfo("rtc_syncwait() okay\n"); + break; + } + + default: + { + rtcerr("ERROR: rtc_syncwait() failed (%d)\n", ret); + break; + } + } + } + while (ret != OK && ++nretry < maxretry); + + /* Check if the one-time initialization of the RTC has already been + * performed. We can determine this by checking if the magic number + * has been written to the back-up date register DR0. + */ + + if (regval != RTC_MAGIC && regval != RTC_MAGIC_TIME_SET) + { + rtcinfo("Do setup\n"); + + /* Perform the one-time setup of the LSE clocking to the RTC */ + + ret = rtc_setup(); + + /* Enable write access to the backup domain (RTC registers, RTC + * backup data registers and backup SRAM). + */ + + at32_pwr_enablebkp(true); + + /* Remember that the RTC is initialized */ + + putreg32(RTC_MAGIC, RTC_MAGIC_REG); + + /* Disable write access to the backup domain (RTC registers, RTC + * backup data registers and backup SRAM). + */ + + at32_pwr_enablebkp(false); + } + else + { + rtcinfo("Do resume\n"); + + /* RTC already set-up, just resume normal operation */ + + rtc_resume(); + rtc_dumpregs("Did resume"); + } + + if (ret != OK && nretry > 0) + { + rtcinfo("setup/resume ran %d times and failed with %d\n", + nretry, ret); + return -ETIMEDOUT; + } + + rtc_dumpregs("After Initialization"); + + g_rtc_enabled = true; + return OK; +} + +/**************************************************************************** + * Name: at32_rtc_irqinitialize + * + * Description: + * Initialize IRQs for RTC, not possible during up_rtc_initialize because + * up_irqinitialize is called later. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int at32_rtc_irqinitialize(void) +{ + /* Nothing to do */ + + return OK; +} + +/**************************************************************************** + * Name: at32_rtc_getdatetime_with_subseconds + * + * Description: + * Get the current date and time from the date/time RTC. This interface + * is only supported by the date/time RTC hardware implementation. + * It is used to replace the system timer. It is only used by the RTOS + * during initialization to set up the system time when CONFIG_RTC and + * CONFIG_RTC_DATETIME are selected (and CONFIG_RTC_HIRES is not). + * + * NOTE: Some date/time RTC hardware is capability of sub-second accuracy. + * That sub-second accuracy is returned through 'nsec'. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * nsec - The location to return the subsecond time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_HAVE_RTC_SUBSECONDS +int at32_rtc_getdatetime_with_subseconds(struct tm *tp, long *nsec) +#else +int up_rtc_getdatetime(struct tm *tp) +#endif +{ +#ifdef CONFIG_AT32_HAVE_RTC_SUBSECONDS + uint32_t ssr; +#endif + uint32_t dr; + uint32_t tr; + uint32_t tmp; + + /* Sample the data time registers. There is a race condition here... If + * we sample the time just before midnight on December 31, the date could + * be wrong because the day rolled over while were sampling. Thus loop for + * checking overflow here is needed. There is a race condition with + * subseconds too. If we sample TR register just before second rolling + * and subseconds are read at wrong second, we get wrong time. + */ + + do + { + dr = getreg32(AT32_RTC_DR); + tr = getreg32(AT32_RTC_TR); +#ifdef CONFIG_AT32_HAVE_RTC_SUBSECONDS + ssr = getreg32(AT32_RTC_SSR); + tmp = getreg32(AT32_RTC_TR); + if (tmp != tr) + { + continue; + } +#endif + + tmp = getreg32(AT32_RTC_DR); + if (tmp == dr) + { + break; + } + } + while (1); + + rtc_dumpregs("Reading Time"); + + /* Convert the RTC time to fields in struct tm format. All of the AT32 + * ranges of values correspond between struct tm and the time register. + */ + + tmp = (tr & (RTC_TR_SU_MASK | RTC_TR_ST_MASK)) >> RTC_TR_SU_SHIFT; + tp->tm_sec = rtc_bcd2bin(tmp); + + tmp = (tr & (RTC_TR_MNU_MASK | RTC_TR_MNT_MASK)) >> RTC_TR_MNU_SHIFT; + tp->tm_min = rtc_bcd2bin(tmp); + + tmp = (tr & (RTC_TR_HU_MASK | RTC_TR_HT_MASK)) >> RTC_TR_HU_SHIFT; + tp->tm_hour = rtc_bcd2bin(tmp); + + /* Now convert the RTC date to fields in struct tm format: + * Days: 1-31 match in both cases. + * Month: AT32 is 1-12, struct tm is 0-11. + * Years: AT32 is 00-99, struct tm is years since 1900. + * WeekDay: AT32 is 1 = Mon - 7 = Sun + * + * Issue: I am not sure what the AT32 years mean. Are these the + * years 2000-2099? I'll assume so. + */ + + tmp = (dr & (RTC_DR_DU_MASK | RTC_DR_DT_MASK)) >> RTC_DR_DU_SHIFT; + tp->tm_mday = rtc_bcd2bin(tmp); + + tmp = (dr & (RTC_DR_MU_MASK | RTC_DR_MT)) >> RTC_DR_MU_SHIFT; + tp->tm_mon = rtc_bcd2bin(tmp) - 1; + + tmp = (dr & (RTC_DR_YU_MASK | RTC_DR_YT_MASK)) >> RTC_DR_YU_SHIFT; + tp->tm_year = rtc_bcd2bin(tmp) + 100; + + tmp = (dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT; + tp->tm_wday = tmp % 7; + tp->tm_yday = tp->tm_mday - 1 + + clock_daysbeforemonth(tp->tm_mon, + clock_isleapyear(tp->tm_year + 1900)); + tp->tm_isdst = 0; + +#ifdef CONFIG_AT32_HAVE_RTC_SUBSECONDS + /* Return RTC sub-seconds if no configured and if a non-NULL value + * of nsec has been provided to receive the sub-second value. + */ + + if (nsec) + { + uint32_t prediv_s; + uint32_t usecs; + + prediv_s = getreg32(AT32_RTC_PRER) & RTC_PRER_PREDIV_S_MASK; + prediv_s >>= RTC_PRER_PREDIV_S_SHIFT; + + ssr &= RTC_SSR_MASK; + + /* Maximum prediv_s is 0x7fff, thus we can multiply by 100000 and + * still fit 32-bit unsigned integer. + */ + + usecs = (((prediv_s - ssr) * 100000) / (prediv_s + 1)) * 10; + *nsec = usecs * 1000; + } +#endif /* CONFIG_AT32_HAVE_RTC_SUBSECONDS */ + + rtc_dumptime((const struct tm *)tp, "Returning"); + return OK; +} + +/**************************************************************************** + * Name: up_rtc_getdatetime + * + * Description: + * Get the current date and time from the date/time RTC. This interface + * is only supported by the date/time RTC hardware implementation. + * It is used to replace the system timer. It is only used by the RTOS + * during initialization to set up the system time when CONFIG_RTC and + * CONFIG_RTC_DATETIME are selected (and CONFIG_RTC_HIRES is not). + * + * NOTE: Some date/time RTC hardware is capability of sub-second accuracy. + * That sub-second accuracy is lost in this interface. However, since the + * system time is reinitialized on each power-up/reset, there will be no + * timing inaccuracy in the long run. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_HAVE_RTC_SUBSECONDS +int up_rtc_getdatetime(struct tm *tp) +{ + return at32_rtc_getdatetime_with_subseconds(tp, NULL); +} +#endif + +/**************************************************************************** + * Name: at32_rtc_setdatetime + * + * Description: + * Set the RTC to the provided time. RTC implementations which provide + * up_rtc_getdatetime() (CONFIG_RTC_DATETIME is selected) should provide + * this function. + * + * Input Parameters: + * tp - the time to use + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int at32_rtc_setdatetime(const struct tm *tp) +{ + uint32_t tr; + uint32_t dr; + int ret; + + rtc_dumptime(tp, "Setting time"); + + /* Then write the broken out values to the RTC */ + + /* Convert the struct tm format to RTC time register fields. + * All of the ranges of values correspond between struct tm and the time + * register. + */ + + tr = (rtc_bin2bcd(tp->tm_sec) << RTC_TR_SU_SHIFT) | + (rtc_bin2bcd(tp->tm_min) << RTC_TR_MNU_SHIFT) | + (rtc_bin2bcd(tp->tm_hour) << RTC_TR_HU_SHIFT); + + /* Now convert the fields in struct tm format to the RTC date register + * fields: + * + * Days: 1-31 match in both cases. + * Month: AT32 is 1-12, struct tm is 0-11. + * Years: AT32 is 00-99, struct tm is years since 1900. + * WeekDay: AT32 is 1 = Mon - 7 = Sun + * + * Issue: I am not sure what the AT32 years mean. Are these the + * years 2000-2099? I'll assume so. + */ + + dr = (rtc_bin2bcd(tp->tm_mday) << RTC_DR_DU_SHIFT) | + ((rtc_bin2bcd(tp->tm_mon + 1)) << RTC_DR_MU_SHIFT) | + ((tp->tm_wday == 0 ? 7 : (tp->tm_wday & 7)) << RTC_DR_WDU_SHIFT) | + ((rtc_bin2bcd(tp->tm_year - 100)) << RTC_DR_YU_SHIFT); + + dr &= ~RTC_DR_RESERVED_BITS; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Set Initialization mode */ + + ret = rtc_enterinit(); + if (ret == OK) + { + /* Set the RTC TR and DR registers */ + + putreg32(tr, AT32_RTC_TR); + putreg32(dr, AT32_RTC_DR); + + /* Exit Initialization mode and wait for the RTC Time and Date + * registers to be synchronized with RTC APB clock. + */ + + rtc_exitinit(); + ret = rtc_synchwait(); + } + + /* Remember that the RTC is initialized and had its time set. */ + + if (getreg32(RTC_MAGIC_REG) != RTC_MAGIC_TIME_SET) + { + at32_pwr_enablebkp(true); + putreg32(RTC_MAGIC_TIME_SET, RTC_MAGIC_REG); + at32_pwr_enablebkp(false); + } + + /* Re-enable the write protection for RTC registers */ + + rtc_wprlock(); + rtc_dumpregs("New time setting"); + return ret; +} + +/**************************************************************************** + * Name: up_rtc_settime + * + * Description: + * Set the RTC to the provided time. All RTC implementations must be able + * to set their time based on a standard timespec. + * + * Input Parameters: + * tp - the time to use + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int up_rtc_settime(const struct timespec *tp) +{ + struct tm newtime; + + /* Break out the time values (not that the time is set only to units of + * seconds) + */ + + gmtime_r(&tp->tv_sec, &newtime); + return at32_rtc_setdatetime(&newtime); +} + +/**************************************************************************** + * Name: at32_rtc_setalarm + * + * Description: + * Set an alarm to an absolute time using associated hardware. + * + * Input Parameters: + * alminfo - Information about the alarm configuration. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int at32_rtc_setalarm(struct alm_setalarm_s *alminfo) +{ + struct alm_cbinfo_s *cbinfo; + rtc_alarmreg_t alarmreg; + int ret = -EINVAL; + + DEBUGASSERT(alminfo != NULL); + DEBUGASSERT(RTC_ALARM_LAST > alminfo->as_id); + + /* Make sure the alarm interrupt is enabled at the NVIC */ + + rtc_enable_alarm(); + + /* REVISIT: Should test that the time is in the future */ + + rtc_dumptime(&alminfo->as_time, "New alarm time"); + + /* Break out the values to the HW alarm register format. The values in + * all AT32 fields match the fields of struct tm in this case. Notice + * that the alarm is limited to one month. + */ + + alarmreg = (rtc_bin2bcd(alminfo->as_time.tm_sec) << RTC_ALRMR_SU_SHIFT) | + (rtc_bin2bcd(alminfo->as_time.tm_min) << RTC_ALRMR_MNU_SHIFT) | + (rtc_bin2bcd(alminfo->as_time.tm_hour) << RTC_ALRMR_HU_SHIFT) | + (rtc_bin2bcd(alminfo->as_time.tm_mday) << RTC_ALRMR_DU_SHIFT); + + /* Set the alarm in hardware and enable interrupts from the RTC */ + + switch (alminfo->as_id) + { + case RTC_ALARMA: + { + cbinfo = &g_alarmcb[RTC_ALARMA]; + cbinfo->ac_cb = alminfo->as_cb; + cbinfo->ac_arg = alminfo->as_arg; + + ret = rtchw_set_alrmar(alarmreg | RTC_ALRMR_ENABLE); + if (ret < 0) + { + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + } + + rtc_dumpregs("Set AlarmA"); + } + break; + +#if CONFIG_RTC_NALARMS > 1 + case RTC_ALARMB: + { + cbinfo = &g_alarmcb[RTC_ALARMB]; + cbinfo->ac_cb = alminfo->as_cb; + cbinfo->ac_arg = alminfo->as_arg; + + ret = rtchw_set_alrmbr(alarmreg | RTC_ALRMR_ENABLE); + if (ret < 0) + { + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + } + + rtc_dumpregs("Set AlarmB"); + } + break; +#endif + + default: + rtcerr("ERROR: Invalid ALARM%d\n", alminfo->as_id); + break; + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: at32_rtc_cancelalarm + * + * Description: + * Cancel an alarm. + * + * Input Parameters: + * alarmid - Identifies the alarm to be cancelled + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int at32_rtc_cancelalarm(enum alm_id_e alarmid) +{ + int ret = -EINVAL; + + DEBUGASSERT(RTC_ALARM_LAST > alarmid); + + /* Cancel the alarm in hardware and disable interrupts */ + + switch (alarmid) + { + case RTC_ALARMA: + { + /* Cancel the global callback function */ + + g_alarmcb[alarmid].ac_cb = NULL; + g_alarmcb[alarmid].ac_arg = NULL; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Disable RTC alarm and interrupt */ + + modifyreg32(AT32_RTC_CR, (RTC_CR_ALRAE | RTC_CR_ALRAIE), 0); + + ret = rtchw_check_alrawf(); + if (ret < 0) + { + goto errout_with_wprunlock; + } + + /* Unset the alarm */ + + putreg32(-1, AT32_RTC_ALRMAR); + rtc_wprlock(); + ret = OK; + } + break; + +#if CONFIG_RTC_NALARMS > 1 + case RTC_ALARMB: + { + /* Cancel the global callback function */ + + g_alarmcb[alarmid].ac_cb = NULL; + g_alarmcb[alarmid].ac_arg = NULL; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Disable RTC alarm and interrupt */ + + modifyreg32(AT32_RTC_CR, (RTC_CR_ALRBE | RTC_CR_ALRBIE), 0); + + ret = rtchw_check_alrbwf(); + if (ret < 0) + { + goto errout_with_wprunlock; + } + + /* Unset the alarm */ + + putreg32(-1, AT32_RTC_ALRMBR); + rtc_wprlock(); + ret = OK; + } + break; +#endif + + default: + rtcerr("ERROR: Invalid ALARM%d\n", alarmid); + break; + } + + return ret; + +errout_with_wprunlock: + rtc_wprlock(); + return ret; +} +#endif + +/**************************************************************************** + * Name: at32_rtc_rdalarm + * + * Description: + * Query an alarm configured in hardware. + * + * Input Parameters: + * alminfo - Information about the alarm configuration. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int at32_rtc_rdalarm(struct alm_rdalarm_s *alminfo) +{ + rtc_alarmreg_t alarmreg; + int ret = -EINVAL; + + DEBUGASSERT(alminfo != NULL); + DEBUGASSERT(RTC_ALARM_LAST > alminfo->ar_id); + + switch (alminfo->ar_id) + { + case RTC_ALARMA: + { + alarmreg = AT32_RTC_ALRMAR; + ret = at32_rtc_getalarmdatetime(alarmreg, + (struct tm *)alminfo->ar_time); + } + break; + +#if CONFIG_RTC_NALARMS > 1 + case RTC_ALARMB: + { + alarmreg = AT32_RTC_ALRMBR; + ret = at32_rtc_getalarmdatetime(alarmreg, + (struct tm *)alminfo->ar_time); + } + break; +#endif + + default: + rtcerr("ERROR: Invalid ALARM%d\n", alminfo->ar_id); + break; + } + + return ret; +} +#endif + +#endif /* CONFIG_AT32_RTC */ diff --git a/arch/arm/src/at32/chip.h b/arch/arm/src/at32/chip.h new file mode 100644 index 0000000000..58a78fb026 --- /dev/null +++ b/arch/arm/src/at32/chip.h @@ -0,0 +1,57 @@ +/**************************************************************************** + * arch/arm/src/at32/chip.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_CHIP_H +#define __ARCH_ARM_SRC_AT32_CHIP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/* Include the chip capabilities file */ + +#include + +/* Include the chip interrupt definition file */ + +#include + +/* Include the chip memory map */ + +#include "hardware/at32_memorymap.h" + +/* Include the chip pinmap */ + +#include "hardware/at32_pinmap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Provide the required number of peripheral interrupt vector definitions as + * well. The definition AT32_IRQ_NEXTINT simply comes from the chip-specific + * IRQ header file included by arch/at32/irq.h. + */ + +#define ARMV7M_PERIPHERAL_INTERRUPTS AT32_IRQ_NEXTINT + +#endif /* __ARCH_ARM_SRC_AT32_CHIP_H */ diff --git a/arch/arm/src/at32/hardware/at32_adc.h b/arch/arm/src/at32/hardware/at32_adc.h new file mode 100644 index 0000000000..70e60aca0e --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_adc.h @@ -0,0 +1,39 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_adc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_ADC_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_ADC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +#if defined(CONFIG_AT32_HAVE_IP_ADC_V1) && \ + defined(CONFIG_AT32_HAVE_IP_ADC_V2) +# error Only one AT32 ADC IP version must be selected +#endif + +#include "at32_adc_v1.h" + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_ADC_H */ diff --git a/arch/arm/src/at32/hardware/at32_adc_v1.h b/arch/arm/src/at32/hardware/at32_adc_v1.h new file mode 100644 index 0000000000..ba60c9d30e --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_adc_v1.h @@ -0,0 +1,633 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_adc_v1.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_ADC_V1_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_ADC_V1_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* This is implementation for AT32 ADC IPv1 - F1, F2, F37x, F4, F7. + * NOTE: L1 use modified IPv1 (look at chip/at32_adc_v1l1.h). + */ + +#define HAVE_IP_ADC_V1 +#undef HAVE_IP_ADC_V2 /* No ADC IPv2 */ +#undef HAVE_ADC_CLOCK_HSI /* No ADC clock from HSI */ +#undef HAVE_ADC_POWERDOWN /* No ADC power down */ + +/* F1 and F37x have basic version of ADC hardware + * - no common ADC registers + * - ADCs are not coupled in single ADC block (no common ADC base address) + * - no configurable resolution + * - no overrun + * - ... + */ + +#if defined(CONFIG_AT32_HAVE_IP_ADC_V1_BASIC) +# define HAVE_BASIC_ADC +#else +# undef HAVE_BASIC_ADC +#endif + +/* VBAT channel support only if no basic ADC */ + +#ifndef HAVE_BASIC_ADC +# define HAVE_ADC_VBAT +#else +# undef HAVE_ADC_VBAT +#endif + +/* Base addresses ***********************************************************/ + +/* For the basic ADC IPv1, + * the ADCx_BASE definitions are defined in chip/at32xxx_memorymap.h files + */ + +#ifndef HAVE_BASIC_ADC +# define AT32_ADC1_OFFSET 0x0000 +# define AT32_ADC2_OFFSET 0x0100 +# define AT32_ADC3_OFFSET 0x0200 +# define AT32_ADC_CMN_OFFSET 0x0300 + +# define AT32_ADC1_BASE (AT32_ADC1_OFFSET + AT32_ADC_BASE) /* ADC1 ADC */ +# define AT32_ADC2_BASE (AT32_ADC2_OFFSET + AT32_ADC_BASE) /* ADC2 ADC */ +# define AT32_ADC3_BASE (AT32_ADC3_OFFSET + AT32_ADC_BASE) /* ADC3 ADC */ + +# define AT32_ADCCMN_BASE (AT32_ADC_CMN_OFFSET + AT32_ADC_BASE) /* ADC1, ADC2, ADC3 common */ +#endif + +/* Register Offsets *********************************************************/ + +#define AT32_ADC_SR_OFFSET 0x0000 /* ADC status register (32-bit) */ +#define AT32_ADC_CR1_OFFSET 0x0004 /* ADC control register 1 (32-bit) */ +#define AT32_ADC_CR2_OFFSET 0x0008 /* ADC control register 2 (32-bit) */ +#define AT32_ADC_SMPR1_OFFSET 0x000c /* ADC sample time register 1 (32-bit) */ +#define AT32_ADC_SMPR2_OFFSET 0x0010 /* ADC sample time register 2 (32-bit) */ +#define AT32_ADC_JOFR1_OFFSET 0x0014 /* ADC injected channel data offset register 1 (32-bit) */ +#define AT32_ADC_JOFR2_OFFSET 0x0018 /* ADC injected channel data offset register 2 (32-bit) */ +#define AT32_ADC_JOFR3_OFFSET 0x001c /* ADC injected channel data offset register 3 (32-bit) */ +#define AT32_ADC_JOFR4_OFFSET 0x0020 /* ADC injected channel data offset register 4 (32-bit) */ +#define AT32_ADC_HTR_OFFSET 0x0024 /* ADC watchdog high threshold register (32-bit) */ +#define AT32_ADC_LTR_OFFSET 0x0028 /* ADC watchdog low threshold register (32-bit) */ +#define AT32_ADC_SQR1_OFFSET 0x002c /* ADC regular sequence register 1 (32-bit) */ +#define AT32_ADC_SQR2_OFFSET 0x0030 /* ADC regular sequence register 2 (32-bit) */ +#define AT32_ADC_SQR3_OFFSET 0x0034 /* ADC regular sequence register 3 (32-bit) */ +#define AT32_ADC_JSQR_OFFSET 0x0038 /* ADC injected sequence register (32-bit) */ +#define AT32_ADC_JDR1_OFFSET 0x003c /* ADC injected data register 1 (32-bit) */ +#define AT32_ADC_JDR2_OFFSET 0x0040 /* ADC injected data register 1 (32-bit) */ +#define AT32_ADC_JDR3_OFFSET 0x0044 /* ADC injected data register 1 (32-bit) */ +#define AT32_ADC_JDR4_OFFSET 0x0048 /* ADC injected data register 1 (32-bit) */ +#define AT32_ADC_DR_OFFSET 0x004c /* ADC regular data register (32-bit) */ + +#ifndef HAVE_BASIC_ADC +# define AT32_ADC_CSR_OFFSET 0x0000 /* Common status register */ +# define AT32_ADC_CCR_OFFSET 0x0004 /* Common control register */ +# define AT32_ADC_CDR_OFFSET 0x0008 /* Data register for dual and triple modes */ +#endif + +/* Register Addresses *******************************************************/ + +#if AT32_NADC > 0 +# define AT32_ADC1_SR (AT32_ADC1_BASE + AT32_ADC_SR_OFFSET) +# define AT32_ADC1_CR1 (AT32_ADC1_BASE + AT32_ADC_CR1_OFFSET) +# define AT32_ADC1_CR2 (AT32_ADC1_BASE + AT32_ADC_CR2_OFFSET) +# define AT32_ADC1_SMPR1 (AT32_ADC1_BASE + AT32_ADC_SMPR1_OFFSET) +# define AT32_ADC1_SMPR2 (AT32_ADC1_BASE + AT32_ADC_SMPR2_OFFSET) +# define AT32_ADC1_JOFR1 (AT32_ADC1_BASE + AT32_ADC_JOFR1_OFFSET) +# define AT32_ADC1_JOFR2 (AT32_ADC1_BASE + AT32_ADC_JOFR2_OFFSET) +# define AT32_ADC1_JOFR3 (AT32_ADC1_BASE + AT32_ADC_JOFR3_OFFSET) +# define AT32_ADC1_JOFR4 (AT32_ADC1_BASE + AT32_ADC_JOFR4_OFFSET) +# define AT32_ADC1_HTR (AT32_ADC1_BASE + AT32_ADC_HTR_OFFSET) +# define AT32_ADC1_LTR (AT32_ADC1_BASE + AT32_ADC_LTR_OFFSET) +# define AT32_ADC1_SQR1 (AT32_ADC1_BASE + AT32_ADC_SQR1_OFFSET) +# define AT32_ADC1_SQR2 (AT32_ADC1_BASE + AT32_ADC_SQR2_OFFSET) +# define AT32_ADC1_SQR3 (AT32_ADC1_BASE + AT32_ADC_SQR3_OFFSET) +# define AT32_ADC1_JSQR (AT32_ADC1_BASE + AT32_ADC_JSQR_OFFSET) +# define AT32_ADC1_JDR1 (AT32_ADC1_BASE + AT32_ADC_JDR1_OFFSET) +# define AT32_ADC1_JDR2 (AT32_ADC1_BASE + AT32_ADC_JDR2_OFFSET) +# define AT32_ADC1_JDR3 (AT32_ADC1_BASE + AT32_ADC_JDR3_OFFSET) +# define AT32_ADC1_JDR4 (AT32_ADC1_BASE + AT32_ADC_JDR4_OFFSET) +# define AT32_ADC1_DR (AT32_ADC1_BASE + AT32_ADC_DR_OFFSET) +#endif + +#if AT32_NADC > 1 +# define AT32_ADC2_SR (AT32_ADC2_BASE + AT32_ADC_SR_OFFSET) +# define AT32_ADC2_CR1 (AT32_ADC2_BASE + AT32_ADC_CR1_OFFSET) +# define AT32_ADC2_CR2 (AT32_ADC2_BASE + AT32_ADC_CR2_OFFSET) +# define AT32_ADC2_SMPR1 (AT32_ADC2_BASE + AT32_ADC_SMPR1_OFFSET) +# define AT32_ADC2_SMPR2 (AT32_ADC2_BASE + AT32_ADC_SMPR2_OFFSET) +# define AT32_ADC2_JOFR1 (AT32_ADC2_BASE + AT32_ADC_JOFR1_OFFSET) +# define AT32_ADC2_JOFR2 (AT32_ADC2_BASE + AT32_ADC_JOFR2_OFFSET) +# define AT32_ADC2_JOFR3 (AT32_ADC2_BASE + AT32_ADC_JOFR3_OFFSET) +# define AT32_ADC2_JOFR4 (AT32_ADC2_BASE + AT32_ADC_JOFR4_OFFSET) +# define AT32_ADC2_HTR (AT32_ADC2_BASE + AT32_ADC_HTR_OFFSET) +# define AT32_ADC2_LTR (AT32_ADC2_BASE + AT32_ADC_LTR_OFFSET) +# define AT32_ADC2_SQR1 (AT32_ADC2_BASE + AT32_ADC_SQR1_OFFSET) +# define AT32_ADC2_SQR2 (AT32_ADC2_BASE + AT32_ADC_SQR2_OFFSET) +# define AT32_ADC2_SQR3 (AT32_ADC2_BASE + AT32_ADC_SQR3_OFFSET) +# define AT32_ADC2_JSQR (AT32_ADC2_BASE + AT32_ADC_JSQR_OFFSET) +# define AT32_ADC2_JDR1 (AT32_ADC2_BASE + AT32_ADC_JDR1_OFFSET) +# define AT32_ADC2_JDR2 (AT32_ADC2_BASE + AT32_ADC_JDR2_OFFSET) +# define AT32_ADC2_JDR3 (AT32_ADC2_BASE + AT32_ADC_JDR3_OFFSET) +# define AT32_ADC2_JDR4 (AT32_ADC2_BASE + AT32_ADC_JDR4_OFFSET) +# define AT32_ADC2_DR (AT32_ADC2_BASE + AT32_ADC_DR_OFFSET) +#endif + +#if AT32_NADC > 2 +# define AT32_ADC3_SR (AT32_ADC3_BASE + AT32_ADC_SR_OFFSET) +# define AT32_ADC3_CR1 (AT32_ADC3_BASE + AT32_ADC_CR1_OFFSET) +# define AT32_ADC3_CR2 (AT32_ADC3_BASE + AT32_ADC_CR2_OFFSET) +# define AT32_ADC3_SMPR1 (AT32_ADC3_BASE + AT32_ADC_SMPR1_OFFSET) +# define AT32_ADC3_SMPR2 (AT32_ADC3_BASE + AT32_ADC_SMPR2_OFFSET) +# define AT32_ADC3_JOFR1 (AT32_ADC3_BASE + AT32_ADC_JOFR1_OFFSET) +# define AT32_ADC3_JOFR2 (AT32_ADC3_BASE + AT32_ADC_JOFR2_OFFSET) +# define AT32_ADC3_JOFR3 (AT32_ADC3_BASE + AT32_ADC_JOFR3_OFFSET) +# define AT32_ADC3_JOFR4 (AT32_ADC3_BASE + AT32_ADC_JOFR4_OFFSET) +# define AT32_ADC3_HTR (AT32_ADC3_BASE + AT32_ADC_HTR_OFFSET) +# define AT32_ADC3_LTR (AT32_ADC3_BASE + AT32_ADC_LTR_OFFSET) +# define AT32_ADC3_SQR1 (AT32_ADC3_BASE + AT32_ADC_SQR1_OFFSET) +# define AT32_ADC3_SQR2 (AT32_ADC3_BASE + AT32_ADC_SQR2_OFFSET) +# define AT32_ADC3_SQR3 (AT32_ADC3_BASE + AT32_ADC_SQR3_OFFSET) +# define AT32_ADC3_JSQR (AT32_ADC3_BASE + AT32_ADC_JSQR_OFFSET) +# define AT32_ADC3_JDR1 (AT32_ADC3_BASE + AT32_ADC_JDR1_OFFSET) +# define AT32_ADC3_JDR2 (AT32_ADC3_BASE + AT32_ADC_JDR2_OFFSET) +# define AT32_ADC3_JDR3 (AT32_ADC3_BASE + AT32_ADC_JDR3_OFFSET) +# define AT32_ADC3_JDR4 (AT32_ADC3_BASE + AT32_ADC_JDR4_OFFSET) +# define AT32_ADC3_DR (AT32_ADC3_BASE + AT32_ADC_DR_OFFSET) +#endif + +#ifndef HAVE_BASIC_ADC +# define AT32_ADC_CSR (AT32_ADCCMN_BASE + AT32_ADC_CSR_OFFSET) +# define AT32_ADC_CCR (AT32_ADCCMN_BASE + AT32_ADC_CCR_OFFSET) +# define AT32_ADC_CDR (AT32_ADCCMN_BASE + AT32_ADC_CDR_OFFSET) +#endif + +/* Register Bitfield Definitions ********************************************/ + +/* ADC status register */ + +#define ADC_SR_AWD (1 << 0) /* Bit 0 : Analog watchdog flag */ +#define ADC_SR_EOC (1 << 1) /* Bit 1 : End of conversion */ +#define ADC_SR_JEOC (1 << 2) /* Bit 2 : Injected channel end of conversion */ +#define ADC_SR_JSTRT (1 << 3) /* Bit 3 : Injected channel Start flag */ +#define ADC_SR_STRT (1 << 4) /* Bit 4 : Regular channel Start flag */ +#define ADC_SR_OVR (1 << 5) /* Bit 5 : Overrun */ +#define ADC_SR_RDY (1 << 6) /* Bit 6 : ADC ready to conversion flag */ + +/* ADC control register 1 */ + +#define ADC_CR1_AWDCH_SHIFT (0) /* Bits 4-0: Analog watchdog channel select bits */ +#define ADC_CR1_AWDCH_MASK (0x1f << ADC_CR1_AWDCH_SHIFT) + +#define ADC_CR1_EOCIE (1 << 5) /* Bit 5: Interrupt enable for EOC */ +#define ADC_CR1_AWDIE (1 << 6) /* Bit 6: Analog Watchdog interrupt enable */ +#define ADC_CR1_JEOCIE (1 << 7) /* Bit 7: Interrupt enable for injected channels */ +#define ADC_CR1_SCAN (1 << 8) /* Bit 8: Scan mode */ +#define ADC_CR1_AWDSGL (1 << 9) /* Bit 9: Enable the watchdog on a single channel in scan mode */ +#define ADC_CR1_JAUTO (1 << 10) /* Bit 10: Automatic Injected Group conversion */ +#define ADC_CR1_DISCEN (1 << 11) /* Bit 11: Discontinuous mode on regular channels */ +#define ADC_CR1_JDISCEN (1 << 12) /* Bit 12: Discontinuous mode on injected channels */ +#define ADC_CR1_DISCNUM_SHIFT (13) /* Bits 15-13: Discontinuous mode channel count */ +#define ADC_CR1_DISCNUM_MASK (0x07 << ADC_CR1_DISCNUM_SHIFT) +#define ADC_CR1_JAWDEN (1 << 22) /* Bit 22: Analog watchdog enable on injected channels */ +#define ADC_CR1_AWDEN (1 << 23) /* Bit 23: Analog watchdog enable on regular channels */ +#ifndef HAVE_BASIC_ADC +# define ADC_CR1_RES_SHIFT (24) /* Bits 24-25: Resolution */ +# define ADC_CR1_RES_MASK (3 << ADC_CR1_RES_SHIFT) +# define ADC_CR1_RES_12BIT (0 << ADC_CR1_RES_SHIFT) /* 15 ADCCLK cycles */ +# define ADC_CR1_RES_10BIT (1 << ADC_CR1_RES_SHIFT) /* 13 ADCCLK cycles */ +# define ADC_CR1_RES_8BIT (2 << ADC_CR1_RES_SHIFT) /* 11 ADCCLK cycles */ +# define ADC_CR1_RES_6BIT (3 << ADC_CR1_RES_SHIFT) /* 9 ADCCLK cycles */ +# define ADC_CR1_OVRIE (1 << 26) /* Bit 26: Overrun interrupt enable */ +# define ADC_CR1_RESERVED (0xfb3f0000) +#endif + +/* ADC control register 2 */ + +#define ADC_CR2_ADON (1 << 0) /* Bit 0: A/D Converter ON / OFF */ +#define ADC_CR2_CONT (1 << 1) /* Bit 1: Continuous Conversion */ + +#define ADC_CR2_CAL (1 << 2) /* Bit 2: A/D Calibration */ +#define ADC_CR2_RSTCAL (1 << 3) /* Bit 3: Reset Calibration */ +#define ADC_CR2_ADABRT (1 << 4) /* Bit 4: ADC conversion abort */ +#define ADC_CR2_DMA (1 << 8) /* Bit 8: Direct Memory access mode */ +#define ADC_CR2_DDS (1 << 9) /* Bit 9: DMA disable selection (for single ADC mode) */ +#define ADC_CR2_EOCS (1 << 10) /* Bit 10: End of conversion selection */ +#define ADC_CR2_ALIGN (1 << 11) /* Bit 11: Data Alignment */ + /* Bits 12-15: Reserved */ +#define ADC_CR2_JEXTSEL_SHIFT (16) /* Bits 23/16-19: External event select for injected group */ +#define ADC_CR2_JEXTSEL_MASK (0x8F << ADC_CR2_JEXTSEL_SHIFT) +# define ADC_CR2_JEXTSEL_T1CC4 (0x00 << ADC_CR2_JEXTSEL_SHIFT) /* 0000: Timer 1 CC4 event */ +# define ADC_CR2_JEXTSEL_T1TRGO (0x01 << ADC_CR2_JEXTSEL_SHIFT) /* 0001: Timer 1 TRGO event */ +# define ADC_CR2_JEXTSEL_T2CC1 (0x02 << ADC_CR2_JEXTSEL_SHIFT) /* 0010: Timer 2 CC1 event */ +# define ADC_CR2_JEXTSEL_T2TRGO (0x03 << ADC_CR2_JEXTSEL_SHIFT) /* 0011: Timer 2 TRGO event */ +# define ADC_CR2_JEXTSEL_T3CC2 (0x04 << ADC_CR2_JEXTSEL_SHIFT) /* 0100: Timer 3 CC2 event */ +# define ADC_CR2_JEXTSEL_T3CC4 (0x05 << ADC_CR2_JEXTSEL_SHIFT) /* 0101: Timer 3 CC4 event */ +# define ADC_CR2_JEXTSEL_T4CC1 (0x06 << ADC_CR2_JEXTSEL_SHIFT) /* 0110: Timer 4 CC1 event */ +# define ADC_CR2_JEXTSEL_T4CC2 (0x07 << ADC_CR2_JEXTSEL_SHIFT) /* 0111: Timer 4 CC2 event */ +# define ADC_CR2_JEXTSEL_T4CC3 (0x08 << ADC_CR2_JEXTSEL_SHIFT) /* 1000: Timer 4 CC3 event */ +# define ADC_CR2_JEXTSEL_T4TRGO (0x09 << ADC_CR2_JEXTSEL_SHIFT) /* 1001: Timer 4 TRGO event */ +# define ADC_CR2_JEXTSEL_T5CC4 (0x0A << ADC_CR2_JEXTSEL_SHIFT) /* 1010: Timer 5 CC4 event */ +# define ADC_CR2_JEXTSEL_T5TRGO (0x0B << ADC_CR2_JEXTSEL_SHIFT) /* 1011: Timer 5 TRGO event */ +# define ADC_CR2_JEXTSEL_T8CC2 (0x0C << ADC_CR2_JEXTSEL_SHIFT) /* 1100: Timer 8 CC2 event */ +# define ADC_CR2_JEXTSEL_T8CC3 (0x0D << ADC_CR2_JEXTSEL_SHIFT) /* 1101: Timer 8 CC3 event */ +# define ADC_CR2_JEXTSEL_T8CC4 (0x0E << ADC_CR2_JEXTSEL_SHIFT) /* 1110: Timer 8 CC4 event */ +# define ADC_CR2_JEXTSEL_EXTI15 (0x0F << ADC_CR2_JEXTSEL_SHIFT) /* 1111: EXTI line 15 */ +# define ADC_CR2_JEXTSEL_T20TRGO (0x80 << ADC_CR2_JEXTSEL_SHIFT) /* 10000000: Timer 20 TRGO1 event */ +# define ADC_CR2_JEXTSEL_T20TRGO2 (0x81 << ADC_CR2_JEXTSEL_SHIFT) /* 10000001: Timer 20 TRGO2 event */ +# define ADC_CR2_JEXTSEL_T20CC4 (0x82 << ADC_CR2_JEXTSEL_SHIFT) /* 10000002: Timer 20 CC4 event */ +# define ADC_CR2_JEXTSEL_T1TRGO2 (0x83 << ADC_CR2_JEXTSEL_SHIFT) /* 10000011: Timer 1 TRGO2 event */ +# define ADC_CR2_JEXTSEL_T8TRGO (0x84 << ADC_CR2_JEXTSEL_SHIFT) /* 10000100: Timer 8 TRGO event */ +# define ADC_CR2_JEXTSEL_T8TRGO2 (0x85 << ADC_CR2_JEXTSEL_SHIFT) /* 10000101: Timer 8 TRGO2 event */ +# define ADC_CR2_JEXTSEL_T3CC3 (0x86 << ADC_CR2_JEXTSEL_SHIFT) /* 10000110: Timer 3 CC3 event */ +# define ADC_CR2_JEXTSEL_T3TRGO (0x87 << ADC_CR2_JEXTSEL_SHIFT) /* 10000111: Timer 3 TRGO event */ +# define ADC_CR2_JEXTSEL_T3CC1 (0x88 << ADC_CR2_JEXTSEL_SHIFT) /* 10001000: Timer 3 CC1 event */ +# define ADC_CR2_JEXTSEL_T6TRGO (0x89 << ADC_CR2_JEXTSEL_SHIFT) /* 10001001: Timer 6 TRGO event */ +# define ADC_CR2_JEXTSEL_T4CC4 (0x8a << ADC_CR2_JEXTSEL_SHIFT) /* 10001010: Timer 4 CC4 event */ +# define ADC_CR2_JEXTSEL_T1CC3 (0x8b << ADC_CR2_JEXTSEL_SHIFT) /* 10001011: Timer 1 CC3 event */ +# define ADC_CR2_JEXTSEL_T20CC2 (0x8c << ADC_CR2_JEXTSEL_SHIFT) /* 10001100: Timer 20 CC2 event */ +# define ADC_CR2_JEXTSEL_T7TRGO (0x8e << ADC_CR2_JEXTSEL_SHIFT) /* 10001110: Timer 7 TRGO event */ + +#define ADC_CR2_JEXTEN_SHIFT (20) /* Bits 20-21: External trigger enable for injected channels */ +#define ADC_CR2_JEXTEN_MASK (3 << ADC_CR2_JEXTEN_SHIFT) +# define ADC_CR2_JEXTEN_NONE (0 << ADC_CR2_JEXTEN_SHIFT) /* 00: Trigger detection disabled */ +# define ADC_CR2_JEXTEN_RISING (1 << ADC_CR2_JEXTEN_SHIFT) /* 01: Trigger detection on the rising edge */ +# define ADC_CR2_JEXTEN_FALLING (2 << ADC_CR2_JEXTEN_SHIFT) /* 10: Trigger detection on the falling edge */ +# define ADC_CR2_JEXTEN_BOTH (3 << ADC_CR2_JEXTEN_SHIFT) /* 11: Trigger detection on both the rising and falling edges */ + +#define ADC_CR2_JSWSTART (1 << 22) /* Bit 22: Start Conversion of injected channels */ + /* Bit 23: Reserved, must be kept at reset value. */ +#define ADC_CR2_EXTSEL_SHIFT (24) /* Bits 31/24-27: External Event Select for regular group */ +#define ADC_CR2_EXTSEL_MASK (0x8F << ADC_CR2_EXTSEL_SHIFT) +# define ADC_CR2_EXTSEL_T1CC1 (0x0 << ADC_CR2_EXTSEL_SHIFT) /* 0000: Timer 1 CC1 event */ +# define ADC_CR2_EXTSEL_T1CC2 (0x01 << ADC_CR2_EXTSEL_SHIFT) /* 0001: Timer 1 CC2 event */ +# define ADC_CR2_EXTSEL_T1CC3 (0x02 << ADC_CR2_EXTSEL_SHIFT) /* 0010: Timer 1 CC3 event */ +# define ADC_CR2_EXTSEL_T2CC2 (0x03 << ADC_CR2_EXTSEL_SHIFT) /* 0011: Timer 2 CC2 event */ +# define ADC_CR2_EXTSEL_T2CC3 (0x04 << ADC_CR2_EXTSEL_SHIFT) /* 0100: Timer 2 CC3 event */ +# define ADC_CR2_EXTSEL_T2CC4 (0x05 << ADC_CR2_EXTSEL_SHIFT) /* 0101: Timer 2 CC4 event */ +# define ADC_CR2_EXTSEL_T2TRGO (0x06 << ADC_CR2_EXTSEL_SHIFT) /* 0110: Timer 2 TRGO event */ +# define ADC_CR2_EXTSEL_T3CC1 (0x07 << ADC_CR2_EXTSEL_SHIFT) /* 0111: Timer 3 CC1 event */ +# define ADC_CR2_EXTSEL_T3TRGO (0x08 << ADC_CR2_EXTSEL_SHIFT) /* 1000: Timer 3 TRGO event */ +# define ADC_CR2_EXTSEL_T4CC4 (0x09 << ADC_CR2_EXTSEL_SHIFT) /* 1001: Timer 4 CC4 event */ +# define ADC_CR2_EXTSEL_T5CC1 (0x0A << ADC_CR2_EXTSEL_SHIFT) /* 1010: Timer 5 CC1 event */ +# define ADC_CR2_EXTSEL_T5CC2 (0x0B << ADC_CR2_EXTSEL_SHIFT) /* 1011: Timer 5 CC2 event */ +# define ADC_CR2_EXTSEL_T5CC3 (0x0C << ADC_CR2_EXTSEL_SHIFT) /* 1100: Timer 5 CC3 event */ +# define ADC_CR2_EXTSEL_T8CC1 (0x0D << ADC_CR2_EXTSEL_SHIFT) /* 1101: Timer 8 CC1 event */ +# define ADC_CR2_EXTSEL_T8TRGO (0x0E << ADC_CR2_EXTSEL_SHIFT) /* 1110: Timer 8 TRGO event */ +# define ADC_CR2_EXTSEL_EXTI11 (0x0F << ADC_CR2_EXTSEL_SHIFT) /* 1111: EXTI line 11 */ +# define ADC_CR2_EXTSEL_T20TRGO (0x80 << ADC_CR2_EXTSEL_SHIFT) /* 10000000: Timer 20 TRGO event */ +# define ADC_CR2_EXTSEL_T20TRGO1 (0x81 << ADC_CR2_EXTSEL_SHIFT) /* 10000001: Timer 20 TRGO 2 event */ +# define ADC_CR2_EXTSEL_T20CC1 (0x82 << ADC_CR2_EXTSEL_SHIFT) /* 10000010: Timer 20 CC1 event */ +# define ADC_CR2_EXTSEL_T20CC2 (0x83 << ADC_CR2_EXTSEL_SHIFT) /* 10000011: Timer 20 CC2 event */ +# define ADC_CR2_EXTSEL_T20CC3 (0x84 << ADC_CR2_EXTSEL_SHIFT) /* 10000100: Timer 20 CC3 event */ +# define ADC_CR2_EXTSEL_T8TRGO1 (0x85 << ADC_CR2_EXTSEL_SHIFT) /* 10000101: Timer 20 TRGO 2 event */ +# define ADC_CR2_EXTSEL_T1TRGO1 (0x86 << ADC_CR2_EXTSEL_SHIFT) /* 10000110: Timer 1 TRGO 2 event */ +# define ADC_CR2_EXTSEL_T4TRGO (0x87 << ADC_CR2_EXTSEL_SHIFT) /* 10000111: Timer 4 TRGO event */ +# define ADC_CR2_EXTSEL_T6TRGO (0x88 << ADC_CR2_EXTSEL_SHIFT) /* 10001000: Timer 6 TRGO event */ +# define ADC_CR2_EXTSEL_T3CC4 (0x89 << ADC_CR2_EXTSEL_SHIFT) /* 10001001: Timer 3 CC4 event */ +# define ADC_CR2_EXTSEL_T4CC1 (0x8a << ADC_CR2_EXTSEL_SHIFT) /* 10001010: Timer 3 CC4 event */ +# define ADC_CR2_EXTSEL_T1TRGO (0x8b << ADC_CR2_EXTSEL_SHIFT) /* 10001011: Timer 1 TRGO event */ +# define ADC_CR2_EXTSEL_T2CC1 (0x8c << ADC_CR2_EXTSEL_SHIFT) /* 10001100: Timer 2 CC1 event */ +# define ADC_CR2_EXTSEL_T7TRGO (0x8e << ADC_CR2_EXTSEL_SHIFT) /* 10001110: Timer 7 TRGO event */ + +# define ADC_CR2_EXTEN_SHIFT (28) /* Bits 28-29: External trigger enable for regular channels */ +# define ADC_CR2_EXTEN_MASK (3 << ADC_CR2_EXTEN_SHIFT) +# define ADC_CR2_EXTEN_NONE (0 << ADC_CR2_EXTEN_SHIFT) /* 00: Trigger detection disabled */ +# define ADC_CR2_EXTEN_RISING (1 << ADC_CR2_EXTEN_SHIFT) /* 01: Trigger detection on the rising edge */ +# define ADC_CR2_EXTEN_FALLING (2 << ADC_CR2_EXTEN_SHIFT) /* 10: Trigger detection on the falling edge */ +# define ADC_CR2_EXTEN_BOTH (3 << ADC_CR2_EXTEN_SHIFT) /* 11: Trigger detection on both the rising and falling edges */ + +# define ADC_CR2_SWSTART (1 << 30) /* Bit 30: Start Conversion of regular channels */ +# define ADC_CR2_RESERVED (0x8080f0fc) + +/* ADC sample time register 1 */ + +#define ADC_SMPR_2p5 0 /* 000: 2.5 cycles */ +#define ADC_SMPR_6p5 1 /* 001: 6.5 cycles */ +#define ADC_SMPR_12p5 2 /* 010: 12.5 cycles */ +#define ADC_SMPR_24p5 3 /* 011: 24.5 cycles */ +#define ADC_SMPR_47p5 4 /* 100: 47.5 cycles */ +#define ADC_SMPR_92p5 5 /* 101: 92.5 cycles */ +#define ADC_SMPR_247p5 6 /* 110: 247.5 cycles */ +#define ADC_SMPR_640p5 7 /* 111: 640.5 cycles */ + +#define ADC_SMPR1_SMP10_SHIFT (0) /* Bits 0-2: Channel 10 Sample time selection */ +#define ADC_SMPR1_SMP10_MASK (7 << ADC_SMPR1_SMP10_SHIFT) +#define ADC_SMPR1_SMP11_SHIFT (3) /* Bits 3-5: Channel 11 Sample time selection */ +#define ADC_SMPR1_SMP11_MASK (7 << ADC_SMPR1_SMP11_SHIFT) +#define ADC_SMPR1_SMP12_SHIFT (6) /* Bits 6-8: Channel 12 Sample time selection */ +#define ADC_SMPR1_SMP12_MASK (7 << ADC_SMPR1_SMP12_SHIFT) +#define ADC_SMPR1_SMP13_SHIFT (9) /* Bits 9-11: Channel 13 Sample time selection */ +#define ADC_SMPR1_SMP13_MASK (7 << ADC_SMPR1_SMP13_SHIFT) +#define ADC_SMPR1_SMP14_SHIFT (12) /* Bits 12-14: Channel 14 Sample time selection */ +#define ADC_SMPR1_SMP14_MASK (7 << ADC_SMPR1_SMP14_SHIFT) +#define ADC_SMPR1_SMP15_SHIFT (15) /* Bits 15-17: Channel 15 Sample time selection */ +#define ADC_SMPR1_SMP15_MASK (7 << ADC_SMPR1_SMP15_SHIFT) +#define ADC_SMPR1_SMP16_SHIFT (18) /* Bits 18-20: Channel 16 Sample time selection */ +#define ADC_SMPR1_SMP16_MASK (7 << ADC_SMPR1_SMP16_SHIFT) +#define ADC_SMPR1_SMP17_SHIFT (21) /* Bits 21-23: Channel 17 Sample time selection */ +#define ADC_SMPR1_SMP17_MASK (7 << ADC_SMPR1_SMP17_SHIFT) +#define ADC_SMPR1_SMP18_SHIFT (24) /* Bits 24-26: Channel 18 Sample time selection */ +#define ADC_SMPR1_SMP18_MASK (7 << ADC_SMPR1_SMP18_SHIFT) + +/* ADC sample time register 2 */ + +#define ADC_SMPR2_SMP0_SHIFT (0) /* Bits 2-0: Channel 0 Sample time selection */ +#define ADC_SMPR2_SMP0_MASK (7 << ADC_SMPR2_SMP0_SHIFT) +#define ADC_SMPR2_SMP1_SHIFT (3) /* Bits 5-3: Channel 1 Sample time selection */ +#define ADC_SMPR2_SMP1_MASK (7 << ADC_SMPR2_SMP1_SHIFT) +#define ADC_SMPR2_SMP2_SHIFT (6) /* Bits 8-6: Channel 2 Sample time selection */ +#define ADC_SMPR2_SMP2_MASK (7 << ADC_SMPR2_SMP2_SHIFT) +#define ADC_SMPR2_SMP3_SHIFT (9) /* Bits 11-9: Channel 3 Sample time selection */ +#define ADC_SMPR2_SMP3_MASK (7 << ADC_SMPR2_SMP3_SHIFT) +#define ADC_SMPR2_SMP4_SHIFT (12) /* Bits 14-12: Channel 4 Sample time selection */ +#define ADC_SMPR2_SMP4_MASK (7 << ADC_SMPR2_SMP4_SHIFT) +#define ADC_SMPR2_SMP5_SHIFT (15) /* Bits 17-15: Channel 5 Sample time selection */ +#define ADC_SMPR2_SMP5_MASK (7 << ADC_SMPR2_SMP5_SHIFT) +#define ADC_SMPR2_SMP6_SHIFT (18) /* Bits 20-18: Channel 6 Sample time selection */ +#define ADC_SMPR2_SMP6_MASK (7 << ADC_SMPR2_SMP6_SHIFT) +#define ADC_SMPR2_SMP7_SHIFT (21) /* Bits 23-21: Channel 7 Sample time selection */ +#define ADC_SMPR2_SMP7_MASK (7 << ADC_SMPR2_SMP7_SHIFT) +#define ADC_SMPR2_SMP8_SHIFT (24) /* Bits 26-24: Channel 8 Sample time selection */ +#define ADC_SMPR2_SMP8_MASK (7 << ADC_SMPR2_SMP8_SHIFT) +#define ADC_SMPR2_SMP9_SHIFT (27) /* Bits 29-27: Channel 9 Sample time selection */ +#define ADC_SMPR2_SMP9_MASK (7 << ADC_SMPR2_SMP9_SHIFT) + +/* ADC injected channel data offset register 1-4 */ + +#define ADC_JOFR_SHIFT (0) /* Bits 11-0: Data offset for injected channel x */ +#define ADC_JOFR_MASK (0x0fff << ADC_JOFR_SHIFT) + +/* ADC watchdog high threshold register */ + +#define ADC_HTR_SHIFT (0) /* Bits 15-0: Analog watchdog high threshold */ +#define ADC_HTR_MASK (0xffff << ADC_HTR_SHIFT) + +/* ADC watchdog low threshold register */ + +#define ADC_LTR_SHIFT (0) /* Bits 15-0: Analog watchdog low threshold */ +#define ADC_LTR_MASK (0xffff << ADC_LTR_SHIFT) + +/* ADC regular sequence register 1 */ + +#define ADC_SQR1_SQ13_SHIFT (0) /* Bits 4-0: 13th conversion in regular sequence */ +#define ADC_SQR1_SQ13_MASK (0x1f << ADC_SQR1_SQ13_SHIFT) +#define ADC_SQR1_SQ14_SHIFT (5) /* Bits 9-5: 14th conversion in regular sequence */ +#define ADC_SQR1_SQ14_MASK (0x1f << ADC_SQR1_SQ14_SHIFT) +#define ADC_SQR1_SQ15_SHIFT (10) /* Bits 14-10: 15th conversion in regular sequence */ +#define ADC_SQR1_SQ15_MASK (0x1f << ADC_SQR1_SQ15_SHIFT) +#define ADC_SQR1_SQ16_SHIFT (15) /* Bits 19-15: 16th conversion in regular sequence */ +#define ADC_SQR1_SQ16_MASK (0x1f << ADC_SQR1_SQ16_SHIFT) +#define ADC_SQR1_L_SHIFT (20) /* Bits 23-20: Regular channel sequence length */ +#define ADC_SQR1_L_MASK (0x0f << ADC_SQR1_L_SHIFT) +#define ADC_SQR1_RESERVED (0xff000000) +#define ADC_SQR1_FIRST (13) +#define ADC_SQR1_LAST (16) +#define ADC_SQR1_SQ_OFFSET (0) + +/* ADC regular sequence register 2 */ + +#define ADC_SQR2_SQ7_SHIFT (0) /* Bits 4-0: 7th conversion in regular sequence */ +#define ADC_SQR2_SQ7_MASK (0x1f << ADC_SQR2_SQ7_SHIFT) +#define ADC_SQR2_SQ8_SHIFT (5) /* Bits 9-5: 8th conversion in regular sequence */ +#define ADC_SQR2_SQ8_MASK (0x1f << ADC_SQR2_SQ8_SHIFT) +#define ADC_SQR2_SQ9_SHIFT (10) /* Bits 14-10: 9th conversion in regular sequence */ +#define ADC_SQR2_SQ9_MASK (0x1f << ADC_SQR2_SQ9_SHIFT) +#define ADC_SQR2_SQ10_SHIFT (15) /* Bits 19-15: 10th conversion in regular sequence */ +#define ADC_SQR2_SQ10_MASK (0x1f << ADC_SQR2_SQ10_SHIFT) +#define ADC_SQR2_SQ11_SHIFT (20) /* Bits 24-20: 11th conversion in regular sequence */ +#define ADC_SQR2_SQ11_MASK (0x1f << ADC_SQR2_SQ11_SHIFT ) +#define ADC_SQR2_SQ12_SHIFT (25) /* Bits 29-25: 12th conversion in regular sequence */ +#define ADC_SQR2_SQ12_MASK (0x1f << ADC_SQR2_SQ12_SHIFT) +#define ADC_SQR2_RESERVED (0xc0000000) +#define ADC_SQR2_FIRST (7) +#define ADC_SQR2_LAST (12) +#define ADC_SQR2_SQ_OFFSET (0) + +/* ADC regular sequence register 3 */ + +#define ADC_SQR3_SQ1_SHIFT (0) /* Bits 4-0: 1st conversion in regular sequence */ +#define ADC_SQR3_SQ1_MASK (0x1f << ADC_SQR3_SQ1_SHIFT) +#define ADC_SQR3_SQ2_SHIFT (5) /* Bits 9-5: 2nd conversion in regular sequence */ +#define ADC_SQR3_SQ2_MASK (0x1f << ADC_SQR3_SQ2_SHIFT) +#define ADC_SQR3_SQ3_SHIFT (10) /* Bits 14-10: 3rd conversion in regular sequence */ +#define ADC_SQR3_SQ3_MASK (0x1f << ADC_SQR3_SQ3_SHIFT) +#define ADC_SQR3_SQ4_SHIFT (15) /* Bits 19-15: 4th conversion in regular sequence */ +#define ADC_SQR3_SQ4_MASK (0x1f << ADC_SQR3_SQ4_SHIFT) +#define ADC_SQR3_SQ5_SHIFT (20) /* Bits 24-20: 5th conversion in regular sequence */ +#define ADC_SQR3_SQ5_MASK (0x1f << ADC_SQR3_SQ5_SHIFT ) +#define ADC_SQR3_SQ6_SHIFT (25) /* Bits 29-25: 6th conversion in regular sequence */ +#define ADC_SQR3_SQ6_MASK (0x1f << ADC_SQR3_SQ6_SHIFT) +#define ADC_SQR3_RESERVED (0xc0000000) +#define ADC_SQR3_FIRST (1) +#define ADC_SQR3_LAST (6) +#define ADC_SQR3_SQ_OFFSET (0) + +/* Offset between SQ bits */ + +#define ADC_SQ_OFFSET (5) + +/* ADC injected sequence register */ + +#define ADC_JSQR_JSQ1_SHIFT (0) /* Bits 4-0: 1st conversion in injected sequence */ +#define ADC_JSQR_JSQ1_MASK (0x1f << ADC_JSQR_JSQ1_SHIFT) +#define ADC_JSQR_JSQ2_SHIFT (5) /* Bits 9-5: 2nd conversion in injected sequence */ +#define ADC_JSQR_JSQ2_MASK (0x1f << ADC_JSQR_JSQ2_SHIFT) +#define ADC_JSQR_JSQ3_SHIFT (10) /* Bits 14-10: 3rd conversion in injected sequence */ +#define ADC_JSQR_JSQ3_MASK (0x1f << ADC_JSQR_JSQ3_SHIFT) +#define ADC_JSQR_JSQ4_SHIFT (15) /* Bits 19-15: 4th conversion in injected sequence */ +#define ADC_JSQR_JSQ4_MASK (0x1f << ADC_JSQR_JSQ4_SHIFT) +#define ADC_JSQR_JSQ_SHIFT (5) /* Shift between JSQx bits */ +#define ADC_JSQR_JL_SHIFT (20) /* Bits 21-20: Injected Sequence length */ +#define ADC_JSQR_JL_MASK (3 << ADC_JSQR_JL_SHIFT) +# define ADC_JSQR_JL(n) (((n)-1) << ADC_JSQR_JL_SHIFT) /* n=1..4 */ + +/* ADC injected data register 1-4 */ + +#define ADC_JDR_JDATA_SHIFT (0) /* Bits 15-0: Injected data */ +#define ADC_JDR_JDATA_MASK (0xffff << ADC_JDR_JDATA_SHIFT) + +/* ADC regular data register */ + +#define ADC_DR_RDATA_SHIFT (0) /* Bits 15-0 Regular data */ +#define ADC_DR_RDATA_MASK (0xffff << ADC_DR_RDATA_SHIFT) + +/* Common status register */ + +#define ADC_CSR_AWD1 (1 << 0) /* Bit 0: Analog watchdog flag of ADC1 (copy of AWD in ADC1_SR) */ +#define ADC_CSR_EOC1 (1 << 1) /* Bit 1: End of conversion of ADC1 (copy of EOC in ADC1_SR) */ +#define ADC_CSR_JEOC1 (1 << 2) /* Bit 2: Injected channel end of conversion of ADC1 (copy of JEOC in ADC1_SR) */ +#define ADC_CSR_JSTRT1 (1 << 3) /* Bit 3: Injected channel Start flag of ADC1 (copy of JSTRT in ADC1_SR) */ +#define ADC_CSR_STRT1 (1 << 4) /* Bit 4: Regular channel Start flag of ADC1 (copy of STRT in ADC1_SR) */ +#define ADC_CSR_OVR1 (1 << 5) /* Bit 5: Overrun flag of ADC1 (copy of OVR in ADC1_SR) */ +#define ADC_CSR_RDY1 (1 << 6) /* Bit 6: ADC ready to conversion flag of ADC1 */ + /* Bit 7: Reserved, must be kept at reset value. */ +#define ADC_CSR_AWD2 (1 << 8) /* Bit 8: Analog watchdog flag of ADC2 (copy of AWD in ADC2_SR) */ +#define ADC_CSR_EOC2 (1 << 9) /* Bit 9: End of conversion of ADC2 (copy of EOC in ADC2_SR) */ +#define ADC_CSR_JEOC2 (1 << 10) /* Bit 10: Injected channel end of conversion of ADC2 (copy of JEOC in ADC2_SR) */ +#define ADC_CSR_JSTRT2 (1 << 11) /* Bit 11: Injected channel Start flag of ADC2 (copy of JSTRT in ADC2_SR) */ +#define ADC_CSR_STRT2 (1 << 12) /* Bit 12: Regular channel Start flag of ADC2 (copy of STRT in ADC2_SR) */ +#define ADC_CSR_OVR2 (1 << 13) /* Bit 13: Overrun flag of ADC2 (copy of OVR in ADC2_SR) */ +#define ADC_CSR_RDY2 (1 << 14) /* Bit 14: ADC ready to conversion flag of ADC2 */ + /* Bit 15: Reserved, must be kept at reset value. */ +#define ADC_CSR_AWD3 (1 << 16) /* Bit 16: ADC3 Analog watchdog flag (copy of AWD in ADC3_SR) */ +#define ADC_CSR_EOC3 (1 << 17) /* Bit 17: ADC3 End of conversion (copy of EOC in ADC3_SR) */ +#define ADC_CSR_JEOC3 (1 << 18) /* Bit 18: ADC3 Injected channel end of conversion (copy of JEOC in ADC3_SR) */ +#define ADC_CSR_JSTRT3 (1 << 19) /* Bit 19: ADC3 Injected channel Start flag (copy of JSTRT in ADC3_SR) */ +#define ADC_CSR_STRT3 (1 << 20) /* Bit 20: ADC3 Regular channel Start flag (copy of STRT in ADC3_SR). */ +#define ADC_CSR_OVR3 (1 << 21) /* Bit 21: ADC3 overrun flag (copy of OVR in ADC3_SR). */ +#define ADC_CSR_RDY3 (1 << 22) /* Bit 22: ADC ready to conversion flag of ADC3 */ + /* Bit 31: Reserved, must be kept at reset value. */ + +/* Common control register */ + +#define ADC_CCR_MULTI_SHIFT (0) /* Bits 0-4: Multi ADC mode selection */ +#define ADC_CCR_MULTI_MASK (31 << ADC_CCR_MULTI_SHIFT) +# define ADC_CCR_MULTI_NONE (0 << ADC_CCR_MULTI_SHIFT) /* 00000: Independent mode */ + /* 00001 to 01001: Dual mode (ADC1 and ADC2), ADC3 independent */ +# define ADC_CCR_MULTI_RSISM2 (1 << ADC_CCR_MULTI_SHIFT) /* 00001: Combined regular simultaneous + injected simultaneous mode */ +# define ADC_CCR_MULTI_RSATM2 (2 << ADC_CCR_MULTI_SHIFT) /* 00010: Combined regular simultaneous + alternate trigger mode */ +# define ADC_CCR_MULTI_ISM2 (5 << ADC_CCR_MULTI_SHIFT) /* 00101: Injected simultaneous mode only */ +# define ADC_CCR_MULTI_RSM2 (6 << ADC_CCR_MULTI_SHIFT) /* 00110: Regular simultaneous mode only */ +# define ADC_CCR_MULTI_IM2 (7 << ADC_CCR_MULTI_SHIFT) /* 00111: interleaved mode only */ +# define ADC_CCR_MULTI_ATM2 (9 << ADC_CCR_MULTI_SHIFT) /* 01001: Alternate trigger mode only */ + /* 10001 to 11001: Triple mode (ADC1, 2 and 3) */ +# define ADC_CCR_MULTI_RSISM3 (17 << ADC_CCR_MULTI_SHIFT) /* 10001: Combined regular simultaneous + injected simultaneous mode */ +# define ADC_CCR_MULTI_RSATM3 (18 << ADC_CCR_MULTI_SHIFT) /* 10010: Combined regular simultaneous + alternate trigger mode */ +# define ADC_CCR_MULTI_ISM3 (21 << ADC_CCR_MULTI_SHIFT) /* 10101: Injected simultaneous mode only */ +# define ADC_CCR_MULTI_RSM3 (22 << ADC_CCR_MULTI_SHIFT) /* 10110: Regular simultaneous mode only */ +# define ADC_CCR_MULTI_IM3 (23 << ADC_CCR_MULTI_SHIFT) /* 10111: interleaved mode only */ +# define ADC_CCR_MULTI_ATM3 (25 << ADC_CCR_MULTI_SHIFT) /* 11001: Alternate trigger mode only */ + +/* Bits 5-7: Reserved, + * must be kept at reset value. + */ + +#define ADC_CCR_DELAY_SHIFT (8) /* Bits 8-11: Delay between 2 sampling phases */ +#define ADC_CCR_DELAY_MASK (15 << ADC_CCR_DELAY_SHIFT) +# define ADC_CCR_DELAY(n) (((n)-5) << ADC_CCR_DELAY_SHIFT) /* n * TADCCLK, n=5-20 */ + +/* Bit 12 Reserved, + * must be kept at reset value. + */ + +#define ADC_CCR_DDS (1 << 13) /* Bit 13: DMA disable selection (for multi-ADC mode) */ + +#define ADC_CCR_DMA_SHIFT (14) /* Bits 28/14-15: Direct memory access mode for multi ADC mode */ +#define ADC_CCR_DMA_MASK (0x4003 << ADC_CCR_DMA_SHIFT) +# define ADC_CCR_DMA_DISABLED (0 << ADC_CCR_DMA_SHIFT) /* 00: DMA mode disabled */ +# define ADC_CCR_DMA_MODE1 (1 << ADC_CCR_DMA_SHIFT) /* 01: DMA mode 1 enabled */ +# define ADC_CCR_DMA_MODE2 (2 << ADC_CCR_DMA_SHIFT) /* 10: DMA mode 2 enabled */ +# define ADC_CCR_DMA_MODE3 (3 << ADC_CCR_DMA_SHIFT) /* 11: DMA mode 3 enabled */ +# define ADC_CCR_DMA_MODE4 (0x4000 << ADC_CCR_DMA_SHIFT) /* 0x4000: DMA mode 4 enabled */ +# define ADC_CCR_DMA_MODE5 (0x4001 << ADC_CCR_DMA_SHIFT) /* 0x4001: DMA mode 5 enabled */ + +#define ADC_CCR_ADCPRE_SHIFT (16) /* Bits 16-19: ADC prescaler */ +#define ADC_CCR_ADCPRE_MASK (3 << ADC_CCR_ADCPRE_SHIFT) +# define ADC_CCR_ADCPRE_DIV2 (0 << ADC_CCR_ADCPRE_SHIFT) /* 0000: HCLK divided by 2 */ +# define ADC_CCR_ADCPRE_DIV3 (1 << ADC_CCR_ADCPRE_SHIFT) /* 0001: HCLK divided by 3 */ +# define ADC_CCR_ADCPRE_DIV4 (2 << ADC_CCR_ADCPRE_SHIFT) /* 0010: HCLK divided by 4 */ +# define ADC_CCR_ADCPRE_DIV5 (3 << ADC_CCR_ADCPRE_SHIFT) /* 0011: HCLK divided by 5 */ +# define ADC_CCR_ADCPRE_DIV6 (4 << ADC_CCR_ADCPRE_SHIFT) /* 0100: HCLK divided by 6 */ +# define ADC_CCR_ADCPRE_DIV7 (5 << ADC_CCR_ADCPRE_SHIFT) /* 0101: HCLK divided by 7 */ +# define ADC_CCR_ADCPRE_DIV8 (6 << ADC_CCR_ADCPRE_SHIFT) /* 0110: HCLK divided by 8 */ +# define ADC_CCR_ADCPRE_DIV9 (7 << ADC_CCR_ADCPRE_SHIFT) /* 0111: HCLK divided by 9 */ +# define ADC_CCR_ADCPRE_DIV10 (8 << ADC_CCR_ADCPRE_SHIFT) /* 1000: HCLK divided by 10 */ +# define ADC_CCR_ADCPRE_DIV11 (9 << ADC_CCR_ADCPRE_SHIFT) /* 1001: HCLK divided by 11 */ +# define ADC_CCR_ADCPRE_DIV12 (10 << ADC_CCR_ADCPRE_SHIFT) /* 1010: HCLK divided by 12 */ +# define ADC_CCR_ADCPRE_DIV13 (11 << ADC_CCR_ADCPRE_SHIFT) /* 1011: HCLK divided by 13 */ +# define ADC_CCR_ADCPRE_DIV14 (12 << ADC_CCR_ADCPRE_SHIFT) /* 1100: HCLK divided by 14 */ +# define ADC_CCR_ADCPRE_DIV15 (13 << ADC_CCR_ADCPRE_SHIFT) /* 1101: HCLK divided by 15 */ +# define ADC_CCR_ADCPRE_DIV16 (14 << ADC_CCR_ADCPRE_SHIFT) /* 1110: HCLK divided by 16 */ +# define ADC_CCR_ADCPRE_DIV17 (15 << ADC_CCR_ADCPRE_SHIFT) /* 1111: HCLK divided by 17 */ + +/* Bits 18-21: Reserved, + * must be kept at reset value. + */ +#define ADC_CCR_VBATEN (1 << 22) /* Bit 22: VBAT enable */ +#define ADC_CCR_TSVREFE (1 << 23) /* Bit 23: Temperature sensor and VREFINT enable */ + /* Bits 24-31 Reserved, must be kept at reset value. */ + +/* Over sample register */ + +#define ADC_OVSP_OOSEN (1 << 0) /* Bit 0: Ordinary oversampling enable */ +#define ADC_OVSP_POSEN (1 << 1) /* Bit 1: Preempted oversampling enable */ + +#define ADC_OVSP_OSRSEL_SHIFT (2) /* Oversampling ratio select */ +#define ADC_OVSP_OSRSEL_MASK (7 << ADC_OVSP_OSRSEL_SHIFT) +#define ADC_OVSP_OSRSEL_2 (0 << ADC_OVSP_OSRSEL_SHIFT) +#define ADC_OVSP_OSRSEL_4 (1 << ADC_OVSP_OSRSEL_SHIFT) +#define ADC_OVSP_OSRSEL_8 (2 << ADC_OVSP_OSRSEL_SHIFT) +#define ADC_OVSP_OSRSEL_16 (3 << ADC_OVSP_OSRSEL_SHIFT) +#define ADC_OVSP_OSRSEL_32 (4 << ADC_OVSP_OSRSEL_SHIFT) +#define ADC_OVSP_OSRSEL_64 (5 << ADC_OVSP_OSRSEL_SHIFT) +#define ADC_OVSP_OSRSEL_128 (6 << ADC_OVSP_OSRSEL_SHIFT) +#define ADC_OVSP_OSRSEL_256 (7 << ADC_OVSP_OSRSEL_SHIFT) + +#define ADC_OVSP_OSSSEL_SHIFT (5) /* Oversampling shift select */ +#define ADC_OVSP_OSSSEL_MASK (15 << ADC_OVSP_OSSSEL_SHIFT) +#define ADC_OVSP_OSSSEL_1 (0 << ADC_OVSP_OSSSEL_SHIFT) +#define ADC_OVSP_OSSSEL_2 (1 << ADC_OVSP_OSSSEL_SHIFT) +#define ADC_OVSP_OSSSEL_3 (2 << ADC_OVSP_OSSSEL_SHIFT) +#define ADC_OVSP_OSSSEL_4 (3 << ADC_OVSP_OSSSEL_SHIFT) +#define ADC_OVSP_OSSSEL_5 (4 << ADC_OVSP_OSSSEL_SHIFT) +#define ADC_OVSP_OSSSEL_6 (5 << ADC_OVSP_OSSSEL_SHIFT) +#define ADC_OVSP_OSSSEL_7 (6 << ADC_OVSP_OSSSEL_SHIFT) +#define ADC_OVSP_OSSSEL_8 (7 << ADC_OVSP_OSSSEL_SHIFT) + +#define ADC_OVSP_OOSTREN (9) /* Ordinary oversampling trigger mode enable */ + +#define ADC_OVSP_OOSRSEL (10) /* Ordinary oversampling restart mode select */ + +/* Calibration value register */ + +#define ADC_CALVAL_SHIFT (0) +#define ADC_CALVAL_MASK (0x7f << ADC_CALVAL_SHIFT) +# define ADC_CALVAL(n) (n << ADC_CALVAL_SHIFT) + +/* Data register for dual and triple modes + * (32-bit data with no named fields) + */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_ADC_V1_H */ diff --git a/arch/arm/src/at32/hardware/at32_can.h b/arch/arm/src/at32/hardware/at32_can.h new file mode 100644 index 0000000000..b70037dc1c --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_can.h @@ -0,0 +1,469 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_can.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_CAN_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_CAN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* 3 TX mailboxes */ + +#define CAN_TXMBOX1 0 +#define CAN_TXMBOX2 1 +#define CAN_TXMBOX3 2 + +/* 2 RX mailboxes */ + +#define CAN_RXMBOX1 0 +#define CAN_RXMBOX2 1 + +/* Number of filters depends on silicon */ + +#if defined(CONFIG_AT32_AT32F43XX) +# define CAN_NFILTERS 28 +#else +# define CAN_NFILTERS 14 +#endif + +/* Register Offsets *********************************************************/ + +/* CAN control and status registers */ + +#define AT32_CAN_MCTRL_OFFSET (0x000) /* CAN master control register */ +#define AT32_CAN_MSTS_OFFSET (0x004) /* CAN master status register */ +#define AT32_CAN_TSTS_OFFSET (0x008) /* CAN transmit status register */ + +#define AT32_CAN_RF_OFFSET(x) (0x00c+((x)<<2)) +#define AT32_CAN_RF0_OFFSET (0x00c) /* CAN receive FIFO 0 register */ +#define AT32_CAN_RF1_OFFSET (0x010) /* CAN receive FIFO 1 register */ + +#define AT32_CAN_INTEN_OFFSET (0x014) /* CAN interrupt enable register */ +#define AT32_CAN_ESTS_OFFSET (0x018) /* CAN error status register */ +#define AT32_CAN_BTMG_OFFSET (0x01c) /* CAN bit timing register */ + +/* CAN mailbox registers (3 TX and 2 RX) */ + +#define AT32_CAN_TMI_OFFSET(x) (0x180+((x)<<4)) +#define AT32_CAN_TMI0_FFSET (0x180) /* TX mailbox identifier register 0 */ +#define AT32_CAN_TMI1_FFSET (0x190) /* TX mailbox identifier register 1 */ +#define AT32_CAN_TMI2_FFSET (0x1a0) /* TX mailbox identifier register 2 */ + +#define AT32_CAN_TMC_OFFSET(x) (0x184+((x)<<4)) +#define AT32_CAN_TMC0_OFFSET (0x184) /* Mailbox data length control and time stamp register 0 */ +#define AT32_CAN_TMC1_OFFSET (0x194) /* Mailbox data length control and time stamp register 1 */ +#define AT32_CAN_TMC2_OFFSET (0x1a4) /* Mailbox data length control and time stamp register 2 */ + +#define AT32_CAN_TMDTL_OFFSET(x) (0x188+((x)<<4)) +#define AT32_CAN_TMDTL0_OFFSET (0x188) /* Mailbox data low register 0 */ +#define AT32_CAN_TMDTL1_OFFSET (0x198) /* Mailbox data low register 1 */ +#define AT32_CAN_TMDTL2_OFFSET (0x1a8) /* Mailbox data low register 2 */ + +#define AT32_CAN_TMDTH_OFFSET(x) (0x18c+((x)<<4)) +#define AT32_CAN_TMDTH0_OFFSET (0x18c) /* Mailbox data high register 0 */ +#define AT32_CAN_TMDTH1_OFFSET (0x19c) /* Mailbox data high register 1 */ +#define AT32_CAN_TMDTH2_OFFSET (0x1ac) /* Mailbox data high register 2 */ + +#define AT32_CAN_RFI_OFFSET(x) (0x1b0+((x)<<4)) +#define AT32_CAN_RFI0_OFFSET (0x1b0) /* Rx FIFO mailbox identifier register 0 */ +#define AT32_CAN_RFI1_OFFSET (0x1c0) /* Rx FIFO mailbox identifier register 1 */ + +#define AT32_CAN_RFC_OFFSET(x) (0x1b4+((x)<<4)) +#define AT32_CAN_RFC0_OFFSET (0x1b4) /* Rx FIFO mailbox data length control and time stamp register 0 */ +#define AT32_CAN_RFC1_OFFSET (0x1c4) /* Rx FIFO mailbox data length control and time stamp register 1 */ + +#define AT32_CAN_RFDTL_OFFSET(x) (0x1b8+((x)<<4)) +#define AT32_CAN_RFDTL0_OFFSET (0x1b8) /* Receive FIFO mailbox data low register 0 */ +#define AT32_CAN_RFDTL1_OFFSET (0x1c8) /* Receive FIFO mailbox data low register 1 */ + +#define AT32_CAN_RFDTH_OFFSET(x) (0x1bc+((x)<<4)) +#define AT32_CAN_RFDTH0_OFFSET (0x1bc) /* Receive FIFO mailbox data high register 0 */ +#define AT32_CAN_RFDTH1_OFFSET (0x1cc) /* Receive FIFO mailbox data high register 1 */ + +/* CAN filter registers */ + +#define AT32_CAN_FCTRL_OFFSET (0x200) /* CAN filter master register */ +#define AT32_CAN_FMCFG_OFFSET (0x204) /* CAN filter mode register */ +#define AT32_CAN_FSCFG_OFFSET (0x20c) /* CAN filter scale register */ +#define AT32_CAN_FRF_OFFSET (0x214) /* CAN filter FIFO assignment register */ +#define AT32_CAN_FACFG_OFFSET (0x21c) /* CAN filter activation register */ + +/* There are 14 or 28 filter banks (depending) on the device. + * Each filter bank is composed of two 32-bit registers, CAN_FiR: + * FB0F1 Offset 0x240 + * FB0F2 Offset 0x244 + * FB1F1 Offset 0x248 + * FB1F2 Offset 0x24c + * ... + */ + +#define AT32_CAN_FBF_OFFSET(f,i) (0x240+((f)<<3)+(((i)-1)<<2)) + +/* Register Addresses *******************************************************/ + +#if AT32_NCAN > 0 +# define AT32_CAN1_MCTRL (AT32_CAN1_BASE+AT32_CAN_MCTRL_OFFSET) +# define AT32_CAN1_MSTS (AT32_CAN1_BASE+AT32_CAN_MSTS_OFFSET) +# define AT32_CAN1_TSTS (AT32_CAN1_BASE+AT32_CAN_TSTS_OFFSET) +# define AT32_CAN1_RF0 (AT32_CAN1_BASE+AT32_CAN_RF0_OFFSET) +# define AT32_CAN1_RF1 (AT32_CAN1_BASE+AT32_CAN_RF1_OFFSET) +# define AT32_CAN1_INTEN (AT32_CAN1_BASE+AT32_CAN_INTEN_OFFSET) +# define AT32_CAN1_ESTS (AT32_CAN1_BASE+AT32_CAN_ESTS_OFFSET) +# define AT32_CAN1_BTMG (AT32_CAN1_BASE+AT32_CAN_BTMG_OFFSET) +# define AT32_CAN1_TMI(x) (AT32_CAN1_BASE+AT32_CAN_TMI_OFFSET(x)) +# define AT32_CAN1_TMI0 (AT32_CAN1_BASE+AT32_CAN_TMI0_FFSET) +# define AT32_CAN1_TMI1 (AT32_CAN1_BASE+AT32_CAN_TMI1_FFSET) +# define AT32_CAN1_TMI2 (AT32_CAN1_BASE+AT32_CAN_TMI2_FFSET) +# define AT32_CAN1_TMC(x) (AT32_CAN1_BASE+AT32_CAN_TMC_OFFSET(x)) +# define AT32_CAN1_TMC0 (AT32_CAN1_BASE+AT32_CAN_TMC0_OFFSET) +# define AT32_CAN1_TMC1 (AT32_CAN1_BASE+AT32_CAN_TMC1_OFFSET) +# define AT32_CAN1_TMC2 (AT32_CAN1_BASE+AT32_CAN_TMC2_OFFSET) +# define AT32_CAN1_TMDTL(x) (AT32_CAN1_BASE+AT32_CAN_TMDTL_OFFSET(x)) +# define AT32_CAN1_TMDTL0 (AT32_CAN1_BASE+AT32_CAN_TMDTL0_OFFSET) +# define AT32_CAN1_TMDTL1 (AT32_CAN1_BASE+AT32_CAN_TMDTL1_OFFSET) +# define AT32_CAN1_TMDTL2 (AT32_CAN1_BASE+AT32_CAN_TMDTL2_OFFSET) +# define AT32_CAN1_TMDTH(x) (AT32_CAN1_BASE+AT32_CAN_TMDTH_OFFSET(x)) +# define AT32_CAN1_TMDTH0 (AT32_CAN1_BASE+AT32_CAN_TMDTH0_OFFSET) +# define AT32_CAN1_TMDTH1 (AT32_CAN1_BASE+AT32_CAN_TMDTH1_OFFSET) +# define AT32_CAN1_TMDTH2 (AT32_CAN1_BASE+AT32_CAN_TMDTH2_OFFSET) +# define AT32_CAN1_RFI(x) (AT32_CAN1_BASE+AT32_CAN_RFI_OFFSET(x)) +# define AT32_CAN1_RFI0 (AT32_CAN1_BASE+AT32_CAN_RFI0_OFFSET) +# define AT32_CAN1_RFI1 (AT32_CAN1_BASE+AT32_CAN_RFI1_OFFSET) +# define AT32_CAN1_RFC(x) (AT32_CAN1_BASE+AT32_CAN_RFC_OFFSET(x)) +# define AT32_CAN1_RFC0 (AT32_CAN1_BASE+AT32_CAN_RFC0_OFFSET) +# define AT32_CAN1_RFC1 (AT32_CAN1_BASE+AT32_CAN_RFC1_OFFSET) +# define AT32_CAN1_RFDTL(x) (AT32_CAN1_BASE+AT32_CAN_RFDTL_OFFSET(x)) +# define AT32_CAN1_RFDTL0 (AT32_CAN1_BASE+AT32_CAN_RFDTL0_OFFSET) +# define AT32_CAN1_RFDTL1 (AT32_CAN1_BASE+AT32_CAN_RFDTL1_OFFSET) +# define AT32_CAN1_RFDTH(x) (AT32_CAN1_BASE+AT32_CAN_RFDTH_OFFSET(x)) +# define AT32_CAN1_RFDTH0 (AT32_CAN1_BASE+AT32_CAN_RFDTH0_OFFSET) +# define AT32_CAN1_RFDTH1 (AT32_CAN1_BASE+AT32_CAN_RFDTH1_OFFSET) +# define AT32_CAN1_FCTRL (AT32_CAN1_BASE+AT32_CAN_FCTRL_OFFSET) +# define AT32_CAN1_FMCFG (AT32_CAN1_BASE+AT32_CAN_FMCFG_OFFSET) +# define AT32_CAN1_FSCFG (AT32_CAN1_BASE+AT32_CAN_FSCFG_OFFSET) +# define AT32_CAN1_FRF (AT32_CAN1_BASE+AT32_CAN_FRF_OFFSET) +# define AT32_CAN1_FACFG (AT32_CAN1_BASE+AT32_CAN_FACFG_OFFSET) +# define AT32_CAN1_FIR(b,i) (AT32_CAN1_BASE+AT32_CAN_FIR_OFFSET(b,i)) +#endif + +#if AT32_NCAN > 1 +# define AT32_CAN2_MCTRL (AT32_CAN2_BASE+AT32_CAN_MCTRL_OFFSET) +# define AT32_CAN2_MSTS (AT32_CAN2_BASE+AT32_CAN_MSTS_OFFSET) +# define AT32_CAN2_TSTS (AT32_CAN2_BASE+AT32_CAN_TSTS_OFFSET) +# define AT32_CAN2_RF0 (AT32_CAN2_BASE+AT32_CAN_RF0_OFFSET) +# define AT32_CAN2_RF1 (AT32_CAN2_BASE+AT32_CAN_RF1_OFFSET) +# define AT32_CAN2_INTEN (AT32_CAN2_BASE+AT32_CAN_INTEN_OFFSET) +# define AT32_CAN2_ESTS (AT32_CAN2_BASE+AT32_CAN_ESTS_OFFSET) +# define AT32_CAN2_BTMG (AT32_CAN2_BASE+AT32_CAN_BTMG_OFFSET) +# define AT32_CAN2_TMI(x) (AT32_CAN2_BASE+AT32_CAN_TMI_OFFSET(x)) +# define AT32_CAN2_TMI0 (AT32_CAN2_BASE+AT32_CAN_TMI0_FFSET) +# define AT32_CAN2_TMI1 (AT32_CAN2_BASE+AT32_CAN_TMI1_FFSET) +# define AT32_CAN2_TMI2 (AT32_CAN2_BASE+AT32_CAN_TMI2_FFSET) +# define AT32_CAN2_TMC(x) (AT32_CAN2_BASE+AT32_CAN_TMC_OFFSET(x)) +# define AT32_CAN2_TMC0 (AT32_CAN2_BASE+AT32_CAN_TMC0_OFFSET) +# define AT32_CAN2_TMC1 (AT32_CAN2_BASE+AT32_CAN_TMC1_OFFSET) +# define AT32_CAN2_TMC2 (AT32_CAN2_BASE+AT32_CAN_TMC2_OFFSET) +# define AT32_CAN2_TMDTL(x) (AT32_CAN2_BASE+AT32_CAN_TMDTL_OFFSET(x)) +# define AT32_CAN2_TMDTL0 (AT32_CAN2_BASE+AT32_CAN_TMDTL0_OFFSET) +# define AT32_CAN2_TMDTL1 (AT32_CAN2_BASE+AT32_CAN_TMDTL1_OFFSET) +# define AT32_CAN2_TMDTL2 (AT32_CAN2_BASE+AT32_CAN_TMDTL2_OFFSET) +# define AT32_CAN2_TMDTH(x) (AT32_CAN2_BASE+AT32_CAN_TMDTH_OFFSET(x)) +# define AT32_CAN2_TMDTH0 (AT32_CAN2_BASE+AT32_CAN_TMDTH0_OFFSET) +# define AT32_CAN2_TMDTH1 (AT32_CAN2_BASE+AT32_CAN_TMDTH1_OFFSET) +# define AT32_CAN2_TMDTH2 (AT32_CAN2_BASE+AT32_CAN_TMDTH2_OFFSET) +# define AT32_CAN2_RFI(x) (AT32_CAN2_BASE+AT32_CAN_RFI_OFFSET(x)) +# define AT32_CAN2_RFI0 (AT32_CAN2_BASE+AT32_CAN_RFI0_OFFSET) +# define AT32_CAN2_RFI1 (AT32_CAN2_BASE+AT32_CAN_RFI1_OFFSET) +# define AT32_CAN2_RFC(x) (AT32_CAN2_BASE+AT32_CAN_RFC_OFFSET(x)) +# define AT32_CAN2_RFC0 (AT32_CAN2_BASE+AT32_CAN_RFC0_OFFSET) +# define AT32_CAN2_RFC1 (AT32_CAN2_BASE+AT32_CAN_RFC1_OFFSET) +# define AT32_CAN2_RFDTL(x) (AT32_CAN2_BASE+AT32_CAN_RFDTL_OFFSET(x)) +# define AT32_CAN2_RFDTL0 (AT32_CAN2_BASE+AT32_CAN_RFDTL0_OFFSET) +# define AT32_CAN2_RFDTL1 (AT32_CAN2_BASE+AT32_CAN_RFDTL1_OFFSET) +# define AT32_CAN2_RFDTH(x) (AT32_CAN2_BASE+AT32_CAN_RFDTH_OFFSET(x)) +# define AT32_CAN2_RFDTH0 (AT32_CAN2_BASE+AT32_CAN_RFDTH0_OFFSET) +# define AT32_CAN2_RFDTH1 (AT32_CAN2_BASE+AT32_CAN_RFDTH1_OFFSET) +# define AT32_CAN2_FCTRL (AT32_CAN2_BASE+AT32_CAN_FCTRL_OFFSET) +# define AT32_CAN2_FMCFG (AT32_CAN2_BASE+AT32_CAN_FMCFG_OFFSET) +# define AT32_CAN2_FSCFG (AT32_CAN2_BASE+AT32_CAN_FSCFG_OFFSET) +# define AT32_CAN2_FRF (AT32_CAN2_BASE+AT32_CAN_FRF_OFFSET) +# define AT32_CAN2_FACFG (AT32_CAN2_BASE+AT32_CAN_FACFG_OFFSET) +# define AT32_CAN2_FIR(b,i) (AT32_CAN2_BASE+AT32_CAN_FIR_OFFSET(b,i)) +#endif + +/* Register Bitfield Definitions ********************************************/ + +/* CAN master control register */ + +#define CAN_MCTRL_FZEN (1 << 0) /* Freeze mode enable */ +#define CAN_MCTRL_DZEN (1 << 1) /* Doze mode enable */ +#define CAN_MCTRL_MMSSR (1 << 2) /* Multiple message sending sequence rule */ +#define CAN_MCTRL_MDRSEL (1 << 3) /* Message discarding rule select when overflow */ +#define CAN_MCTRL_PRSFEN (1 << 4) /* Prohibit retransmission when sending fails enable */ +#define CAN_MCTRL_AEDEN (1 << 5) /* Automatic exit doze mode enable */ +#define CAN_MCTRL_AEBOEN (1 << 6) /* Automatic exit bus-off enable */ +#define CAN_MCTRL_TTCEN (1 << 7) /* Time triggered communication mode enable */ +#define CAN_MCTRL_SPRST (1 << 15) /* Software partial reset */ +#define CAN_MCTRL_PTD (1 << 16) /* Prohibit trans when debug */ + +/* CAN master status register */ + +#define CAN_MSTS_FZC (1 << 0) /* Freeze mode confirm */ +#define CAN_MSTS_DZC (1 << 1) /* Doze mode confirm */ +#define CAN_MSTS_EOIF (1 << 2) /* Error occur Interrupt flag */ +#define CAN_MSTS_QDZIF (1 << 3) /* Quit doze mode interrupt flag */ +#define CAN_MSTS_EDZIF (1 << 4) /* Enter doze mode interrupt flag */ +#define CAN_MSTS_CUSS (1 << 8) /* Currently sending status */ +#define CAN_MSTS_CURS (1 << 9) /* Currently receiving status */ +#define CAN_MSTS_LSAMPRX (1 << 10) /* Last sample level of RX pin */ +#define CAN_MSTS_REALRX (1 << 11) /* Real time level of RX pin */ + +/* CAN transmit status register */ + +#define CAN_TSTS_TM0TCF (1 << 0) /* Transmit mailbox 0 transmission completed flag */ +#define CAN_TSTS_TM0TSF (1 << 1) /* Transmit mailbox 0 transmission success flag */ +#define CAN_TSTS_TM0ALF (1 << 2) /* Transmit mailbox 0 arbitration lost flag */ +#define CAN_TSTS_TM0TEF (1 << 3) /* Transmit mailbox 0 transmission error flag */ +#define CAN_TSTS_TM0CT (1 << 7) /* Transmit mailbox 0 cancel transmit */ +#define CAN_TSTS_TM1TCF (1 << 8) /* Transmit mailbox 1 transmission completed flag */ +#define CAN_TSTS_TM1TSF (1 << 9) /* Transmit mailbox 1 transmission success flag */ +#define CAN_TSTS_TM1ALF (1 << 10) /* Transmit mailbox 1 arbitration lost flag */ +#define CAN_TSTS_TM1TEF (1 << 11) /* Transmit mailbox 1 transmission error flag */ +#define CAN_TSTS_TM1CT (1 << 15) /* Transmit mailbox 1 cancel transmit */ +#define CAN_TSTS_TM2TCF (1 << 16) /* transmit mailbox 2 transmission completed flag */ +#define CAN_TSTS_TM2TSF (1 << 17) /* Transmit mailbox 2 transmission success flag */ +#define CAN_TSTS_TM2ALF (1 << 18) /* Transmit mailbox 2 arbitration lost flag */ +#define CAN_TSTS_TM2TEF (1 << 19) /* Transmit mailbox 2 transmission error flag */ +#define CAN_TSTS_TM2CT (1 << 23) /* Transmit mailbox 2 cancel transmit */ + +#define CAN_TSTS_TMNR_SHIFT (24) /* Transmit Mailbox number record */ +#define CAN_TSTS_TMNR_MASK (3 << CAN_TSTS_TMNR_SHIFT) + +#define CAN_TSTS_TM0EF (1 << 26) /* Transmit mailbox 0 empty flag */ +#define CAN_TSTS_TM1EF (1 << 27) /* Transmit mailbox 1 empty flag */ +#define CAN_TSTS_TM2EF (1 << 28) /* Transmit mailbox 2 empty flag */ +#define CAN_TSTS_TM0LPF (1 << 29) /* Transmit mailbox 0 lowest priority flag */ +#define CAN_TSTS_TM1LPF (1 << 30) /* Transmit mailbox 1 lowest priority flag */ +#define CAN_TSTS_TM2LPF (1 << 31) /* Transmit mailbox 2 lowest priority flag */ + +/* CAN receive FIFO 0/1 registers */ + +#define CAN_RF_RFMN_SHIFT (0) /* Receive FIFO message num */ +#define CAN_RF_RFMN_MASK (3 << CAN_RF_RFMN_SHIFT) + +#define CAN_RF_RFFF (1 << 3) /* Receive FIFO full flag */ +#define CAN_RF_RFOF (1 << 4) /* Receive FIFO overflow flag */ +#define CAN_RF_RFR (1 << 5) /* Receive FIFO release */ + +/* CAN interrupt enable register */ + +#define CAN_INTEN_TCIEN (1 << 0) /* Transmit mailbox empty interrupt enable */ +#define CAN_INTEN_RF0MIEN (1 << 1) /* FIFO 0 receive message interrupt enable */ +#define CAN_INTEN_RF0FIEN (1 << 2) /* Receive FIFO 0 full interrupt enable */ +#define CAN_INTEN_RF0OIEN (1 << 3) /* Receive FIFO 0 overflow interrupt enable */ +#define CAN_INTEN_RF1MIEN (1 << 4) /* FIFO 1 receive message interrupt enable */ +#define CAN_INTEN_RF1FIEN (1 << 5) /* Receive FIFO 1 full interrupt enable */ +#define CAN_INTEN_RF1OIEN (1 << 6) /* Receive FIFO 1 overflow interrupt enable */ +#define CAN_INTEN_EAIEN (1 << 8) /* Error active interrupt enable */ +#define CAN_INTEN_EPIEN (1 << 9) /* Error passive interrupt enable */ +#define CAN_INTEN_BOIEN (1 << 10) /* Bus-off interrupt enable */ +#define CAN_INTEN_ETRIEN (1 << 11) /* Error type record interrupt enable */ +#define CAN_INTEN_EOIEN (1 << 15) /* Error occur interrupt enable */ +#define CAN_INTEN_QDZIEN (1 << 16) /* Quit doze mode interrupt enable */ +#define CAN_INTEN_EDZIEN (1 << 17) /* Enter doze mode interrupt enable */ + +/* CAN error status register */ + +#define CAN_ESTS_EAF (1 << 0) /* Error active flag */ +#define CAN_ESTS_EPF (1 << 0) /* Error passive flag */ +#define CAN_ESTS_BOF (1 << 0) /* Bus-off flag */ + +#define CAN_ESTS_ETR_SHIFT (4) /* Error type record */ +#define CAN_ESTS_ETR_MASK (7 << CAN_ESTS_ETR_SHIFT) +#define CAN_ESTS_ETR_NONE (0 << CAN_ESTS_ETR_SHIFT) /* No error */ +#define CAN_ESTS_ETR_STUFF (1 << CAN_ESTS_ETR_SHIFT) /* Stuff error */ +#define CAN_ESTS_ETR_FORM (2 << CAN_ESTS_ETR_SHIFT) /* Form error */ +#define CAN_ESTS_ETR_ACK (3 << CAN_ESTS_ETR_SHIFT) /* Ack error */ +#define CAN_ESTS_ETR_BREC (4 << CAN_ESTS_ETR_SHIFT) /* Bit recessive error */ +#define CAN_ESTS_ETR_BDOM (5 << CAN_ESTS_ETR_SHIFT) /* Bit domainant error */ +#define CAN_ESTS_ETR_CRC (6 << CAN_ESTS_ETR_SHIFT) /* CRC error */ +#define CAN_ESTS_ETR_SOFT (7 << CAN_ESTS_ETR_SHIFT) /* Set by soft */ + +#define CAN_ESTS_TEC_SHIFT (16) /* Transmit error counter */ +#define CAN_ESTS_TEC_MASK (0xff << CAN_ESTS_TEC_SHIFT) + +#define CAN_ESTS_REC_SHIFT (24) /* Receive error counter */ +#define CAN_ESTS_REC_MASK (0xff << CAN_ESTS_REC_SHIFT) + +/* CAN bit timing register */ + +#define CAN_BTMG_BRDIV_SHIFT (0) /* Baud rate division */ +#define CAN_BTMG_BRDIV_MASK (0xfff << CAN_BTMG_BRDIV_SHIFT) + +#define CAN_BTMG_BTS1_SHIFT (16) /* Bit time segment 1 */ +#define CAN_BTMG_BTS1_MASK (0xf << CAN_BTMG_BTS1_SHIFT) + +#define CAN_BTMG_BTS2_SHIFT (20) /* Bit time segment 2 */ +#define CAN_BTMG_BTS2_MASK (7 << CAN_BTMG_BTS2_SHIFT) + +#define CAN_BTMG_RSAW_SHIFT (24) /* Resynchronization adjust width */ +#define CAN_BTMG_RSAW_MASK (3 << CAN_BTMG_RSAW_SHIFT) + +#define CAN_BTMG_LBEN (1 << 30) /* Loop back mode */ +#define CAN_BTMG_LOEN (1 << 31) /* Listen-Only mode */ + +#define CAN_BTR_BRP_MAX (1024) /* Maximum BTR value (without decrement) */ +#define CAN_BTR_TSEG1_MAX (16) /* Maximum TSEG1 value (without decrement) */ +#define CAN_BTR_TSEG2_MAX (8) /* Maximum TSEG2 value (without decrement) */ + +/* TX mailbox identifier register */ + +#define CAN_TMI_TMSR (1 << 0) /* transmit mailbox send request */ +#define CAN_TMI_TMFRSEL (1 << 1) /* Transmit mailbox frame type select */ +#define CAN_TMI_TMIDSEL (1 << 2) /* Transmit mailbox identifier type select */ + +#define CAN_TMI_TMEID_SHIFT (3) /* Ttransmit mailbox extended identifier */ +#define CAN_TMI_TMEID_MASK (0x1fffffff << CAN_TMI_TMEID_SHIFT) + +#define CAN_TMI_TMSID_TMEID_SHIFT (21) /* Transmit mailbox standard identifier or extended identifier high bytes */ +#define CAN_TMI_TMSID_TMEID_MASK (0x7ff << CAN_TMI_TMSID_TMEID_SHIFT) + +/* Mailbox data length control and time stamp register */ + +#define CAN_TMC_TMDTBL_SHIFT (0) /* Transmit mailbox data byte length */ +#define CAN_TMC_TMDTBL_MASK (15 << CAN_TMC_TMDTBL_SHIFT) + +#define CAN_TMC_TMTSTEN (1 << 8) /* Transmit mailbox time stamp transmit enable */ + +#define CAN_TMC_TMTS_SHIFT (16) /* Transmit mailbox time stamp */ +#define CAN_TMC_TMTS_MASK (0xffff << CAN_TMC_TMTS_SHIFT) + +/* Mailbox data low register */ + +#define CAN_TMDTL_TMDT0_SHIFT (0) /* Transmit mailbox data byte 0 */ +#define CAN_TMDTL_TMDT0_MASK (0xff << CAN_TMDTL_TMDT0_SHIFT) +#define CAN_TMDTL_TMDT1_SHIFT (8) /* Transmit mailbox data byte 1 */ +#define CAN_TMDTL_TMDT1_MASK (0xff << CAN_TMDTL_TMDT1_SHIFT) +#define CAN_TMDTL_TMDT2_SHIFT (16) /* Transmit mailbox data byte 2 */ +#define CAN_TMDTL_TMDT2_MASK (0xff << CAN_TMDTL_TMDT2_SHIFT) +#define CAN_TMDTL_TMDT3_SHIFT (24) /* Transmit mailbox data byte 3 */ +#define CAN_TMDTL_TMDT3_MASK (0xff << CAN_TMDTL_TMDT3_SHIFT) + +/* Mailbox data high register */ + +#define CAN_TMDTH_TMDT4_SHIFT (0) /* Transmit mailbox data byte 4 */ +#define CAN_TMDTH_TMDT4_MASK (0xff << CAN_TMDTH_TMDT4_SHIFT) +#define CAN_TMDTH_TMDT5_SHIFT (8) /* Transmit mailbox data byte 5 */ +#define CAN_TMDTH_TMDT5_MASK (0xff << CAN_TMDTH_TMDT5_SHIFT) +#define CAN_TMDTH_TMDT6_SHIFT (16) /* Transmit mailbox data byte 6 */ +#define CAN_TMDTH_TMDT6_MASK (0xff << CAN_TMDTH_TMDT6_SHIFT) +#define CAN_TMDTH_TMDT7_SHIFT (24) /* Transmit mailbox data byte 7 */ +#define CAN_TMDTH_TMDT7_MASK (0xff << CAN_TMDTH_TMDT7_SHIFT) + +/* Rx FIFO mailbox identifier register */ + +#define CAN_RDI_RFFRI (1 << 1) /* Receive FIFO frame type indication */ +#define CAN_RDI_RFIDI (1 << 2) /* Receive FIFO identifier type indication */ + +#define CAN_RDI_RFEID_SHIFT (3) /* Receive FIFO extended identifier */ +#define CAN_RDI_RFEID_MASK (0x3fff << CAN_RDI_RFEID_SHIFT) + +#define CAN_RDI_RFSID_RFEID_SHIFT (21) /* Receive FIFO standard identifier or receive FIFO extended identifier */ +#define CAN_RDI_RFSID_RFEID_MASK (0x7ff << CAN_RDI_RFSID_RFEID_SHIFT) + +/* Receive FIFO mailbox data length control and time stamp register */ + +#define CAN_RFC_RFDTL_SHIFT (0) /* Receive FIFO data length */ +#define CAN_RFC_RFDTL_MASK (15 << CAN_RFC_RFDTL_SHIFT) + +#define CAN_RFC_RFFMN_SHIFT (8) /* Receive FIFO filter match number */ +#define CAN_RFC_RFFMN_MASK (0xff << CAN_RFC_RFFMN_SHIFT) + +#define CAN_RFC_RFTS_SHIFT (16) /* Receive FIFO time stamp */ +#define CAN_RFC_RFTS_MASK (0xffff << CAN_RFC_RFTS_SHIFT) + +/* Receive FIFO mailbox data low register */ + +#define CAN_RFDTL_RFDT0_SHIFT (0) /* Receive FIFO data byte 0 */ +#define CAN_RFDTL_RFDT0_MASK (0xff << CAN_RFDTL_RFDT0_SHIFT) +#define CAN_RFDTL_RFDT1_SHIFT (8) /* Receive FIFO data byte 1 */ +#define CAN_RFDTL_RFDT1_MASK (0xff << CAN_RFDTL_RFDT1_SHIFT) +#define CAN_RFDTL_RFDT2_SHIFT (16) /* Receive FIFO data byte 2 */ +#define CAN_RFDTL_RFDT2_MASK (0xff << CAN_RFDTL_RFDT2_SHIFT) +#define CAN_RFDTL_RFDT3_SHIFT (24) /* Receive FIFO data byte 3 */ +#define CAN_RFDTL_RFDT3_MASK (0xff << CAN_RFDTL_RFDT3_SHIFT) + +/* Receive FIFO mailbox data high register */ + +#define CAN_RFDTH_RFDT4_SHIFT (0) /* Receive FIFO data byte 4 */ +#define CAN_RFDTH_RFDT4_MASK (0xff << CAN_RFDTH_RFDT4_SHIFT) +#define CAN_RFDTH_RFDT5_SHIFT (8) /* Receive FIFO data byte 5 */ +#define CAN_RFDTH_RFDT5_MASK (0xff << CAN_RFDTH_RFDT5_SHIFT) +#define CAN_RFDTH_RFDT6_SHIFT (16) /* Receive FIFO data byte 6 */ +#define CAN_RFDTH_RFDT6_MASK (0xff << CAN_RFDTH_RFDT6_SHIFT) +#define CAN_RFDTH_RFDT7_SHIFT (24) /* Receive FIFO data byte 7 */ +#define CAN_RFDTH_RFDT7_MASK (0xff << CAN_RFDTH_RFDT7_SHIFT) + +/* CAN filter master register */ + +#define CAN_FCTRL_FCS (1 << 0) /* Filters configure switch */ + +/* CAN filter mode register */ + +#define CAN_FMCFG_FMSEL_SHIFT (0) /* Filter mode select,0:mask 1:list */ +#define CAN_FMCFG_FMSEL_MASK (0xfffffff << CAN_FMCFG_FMSEL_SHIFT) + +/* CAN filter scale register */ + +#define CAN_FBWCFG_FBWSEL_SHIFT (0) /* Filter bit width select,0:two 16 bits 1:32bits */ +#define CAN_FBWCFG_FBWSEL_MASK (0xfffffff << CAN_FBWCFG_FBWSEL_SHIFT) + +/* CAN filter FIFO assignment register */ + +#define CAN_FRF_FRFSEL_SHIFT (0) /* Filter relation FIFO select,0:FIFO0 1:FIFO1 */ +#define CAN_FRF_FRFSEL_MASK (0xfffffff << CAN_FRF_FRFSEL_SHIFT) + +/* CAN filter activation register */ + +#define CAN_FACFG_FAEN_SHIFT (0) /* Filter active enable */ +#define CAN_FACFG_FAEN_MASK (0xfffffff << CAN_FACFG_FAEN_SHIFT) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_CAN_H */ diff --git a/arch/arm/src/at32/hardware/at32_dbgmcu.h b/arch/arm/src/at32/hardware/at32_dbgmcu.h new file mode 100644 index 0000000000..533b44082d --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_dbgmcu.h @@ -0,0 +1,109 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_dbgmcu.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_DBGMCU_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_DBGMCU_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Addresses *******************************************************/ + +#define AT32_DEBUG_IDCODE 0xE0042000 +#define AT32_DEBUG_CTRL 0xE0042004 +#define AT32_DEBUG_APB1_PAUSE 0xE0042008 +#define AT32_DEBUG_APB2_PAUSE 0xE004200C +#define AT32_DEBUG_SER_ID 0xE0042020 + +/* Register Bitfield Definitions ********************************************/ + +/* MCU identifier */ + +#define DEBUG_IDCODE_DEVID_SHIFT (0) /* Bits 11-0: Device Identifier */ +#define DEBUG_IDCODE_DEVID_MASK (0x0fff << DEBUG_IDCODE_DEVID_SHIFT) +#define DEBUG_IDCODE_REVID_SHIFT (16) /* Bits 31-16: Revision Identifier */ +#define DEBUG_IDCODE_REVID_MASK (0xffff << DEBUG_IDCODE_REVID_SHIFT) + +/* MCU debug */ + +#define DEBUG_CTRL_SLEEP_DEBUG (1 << 0) /* Debug sleep mode*/ +#define DEBUG_CTRL_DEEPSLEEP_DEBUG (1 << 1) /* Debug deep sleep mode */ +#define DEBUG_CTRL_STANDBY_DEBUG (1 << 2) /* Debug standby mode */ + +/* APB1 pause */ + +#define DEBUG_APB1_APUSE_TMR2_PAUSE (1 << 0) +#define DEBUG_APB1_APUSE_TMR3_PAUSE (1 << 1) +#define DEBUG_APB1_APUSE_TMR4_PAUSE (1 << 2) +#define DEBUG_APB1_APUSE_TMR5_PAUSE (1 << 3) +#define DEBUG_APB1_APUSE_TMR6_PAUSE (1 << 4) +#define DEBUG_APB1_APUSE_TMR7_PAUSE (1 << 5) +#define DEBUG_APB1_APUSE_TMR12_PAUSE (1 << 6) +#define DEBUG_APB1_APUSE_TMR13_PAUSE (1 << 7) +#define DEBUG_APB1_APUSE_TMR14_PAUSE (1 << 8) +#define DEBUG_APB1_APUSE_ERTC_PAUSE (1 << 10) +#define DEBUG_APB1_APUSE_WWDT_PAUSE (1 << 11) +#define DEBUG_APB1_APUSE_WDT_PAUSE (1 << 12) +#define DEBUG_APB1_APUSE_ERTC_512_PAUSE (1 << 15) +#define DEBUG_APB1_APUSE_I2C1_SMBUS_TIMEOUT (1 << 24) +#define DEBUG_APB1_APUSE_CAN1_PAUSE (1 << 25) +#define DEBUG_APB1_APUSE_CAN2_PAUSE (1 << 26) +#define DEBUG_APB1_APUSE_I2C2_SMBUS_TIMEOUT (1 << 27) +#define DEBUG_APB1_APUSE_I2C3_SMBUS_TIMEOUT (1 << 28) + +/* APB2 pause */ + +#define DEBUG_APB2_APUSE_TMR1_PAUSE (1 << 0) +#define DEBUG_APB2_APUSE_TMR8_PAUSE (1 << 1) +#define DEBUG_APB2_APUSE_TMR20_PAUSE (1 << 6) +#define DEBUG_APB2_APUSE_TMR9_PAUSE (1 << 16) +#define DEBUG_APB2_APUSE_TMR10_PAUSE (1 << 17) +#define DEBUG_APB2_APUSE_TMR11_PAUSE (1 << 18) + +/* SER ID */ +#define DEBUG_SER_ID_SHIFT (8) +# define DEBUG_SER_ID_F435 (0x0D << DEBUG_SER_ID_SHIFT) +# define DEBUG_SER_ID_F437 (0x0E << DEBUG_SER_ID_SHIFT) + +#define DEBUG_REV_ID_SHIFT (0) +# define DEBUG_REV_ID (0 << DEBUG_REV_ID_SHIFT) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_DBGMCU_H */ diff --git a/arch/arm/src/at32/hardware/at32_dma.h b/arch/arm/src/at32/hardware/at32_dma.h new file mode 100644 index 0000000000..8476afe622 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_dma.h @@ -0,0 +1,324 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_dma.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_DMA_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_DMA_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* 2 DMA controllers */ + +#define DMA1 (0) +#define DMA2 (1) + +#define DMA_CHAN1 (0) +#define DMA_CHAN2 (1) +#define DMA_CHAN3 (2) +#define DMA_CHAN4 (3) +#define DMA_CHAN5 (4) +#define DMA_CHAN6 (5) +#define DMA_CHAN7 (6) +#define DMA_CHAN8 (7) + +/* Register Offsets *********************************************************/ + +#define AT32_DMA_ISR_OFFSET 0x0000 /* DMA interrupt status register */ +#define AT32_DMA_IFCR_OFFSET 0x0004 /* DMA interrupt flag clear register */ + +#define AT32_DMACHAN_OFFSET(n) (0x0014*(n)) +#define AT32_DMACHAN1_OFFSET 0x0000 +#define AT32_DMACHAN2_OFFSET 0x0014 +#define AT32_DMACHAN3_OFFSET 0x0028 +#define AT32_DMACHAN4_OFFSET 0x003c +#define AT32_DMACHAN5_OFFSET 0x0050 +#define AT32_DMACHAN6_OFFSET 0x0064 +#define AT32_DMACHAN7_OFFSET 0x0078 +#define AT32_DMACHAN8_OFFSET 0x008c + +#define AT32_DMACHAN_CCR_OFFSET 0x0008 /* DMA channel configuration register */ +#define AT32_DMACHAN_CNDTR_OFFSET 0x000c /* DMA channel number of data register */ +#define AT32_DMACHAN_CPAR_OFFSET 0x0010 /* DMA channel peripheral address register */ +#define AT32_DMACHAN_CMAR_OFFSET 0x0014 /* DMA channel 1 memory address register */ + +#define AT32_DMA_CCR_OFFSET(n) (AT32_DMACHAN_CCR_OFFSET+AT32_DMACHAN_OFFSET(n)) +#define AT32_DMA_CNDTR_OFFSET(n) (AT32_DMACHAN_CNDTR_OFFSET+AT32_DMACHAN_OFFSET(n)) +#define AT32_DMA_CPAR_OFFSET(n) (AT32_DMACHAN_CPAR_OFFSET+AT32_DMACHAN_OFFSET(n)) +#define AT32_DMA_CMAR_OFFSET(n) (AT32_DMACHAN_CMAR_OFFSET+AT32_DMACHAN_OFFSET(n)) + +#define AT32_DMA_CCR1_OFFSET 0x0008 /* DMA channel 1 configuration register */ +#define AT32_DMA_CCR2_OFFSET 0x001c /* DMA channel 2 configuration register */ +#define AT32_DMA_CCR3_OFFSET 0x0030 /* DMA channel 3 configuration register */ +#define AT32_DMA_CCR4_OFFSET 0x0044 /* DMA channel 4 configuration register */ +#define AT32_DMA_CCR5_OFFSET 0x0058 /* DMA channel 5 configuration register */ +#define AT32_DMA_CCR6_OFFSET 0x006c /* DMA channel 6 configuration register */ +#define AT32_DMA_CCR7_OFFSET 0x0080 /* DMA channel 7 configuration register */ +#define AT32_DMA_CCR8_OFFSET 0x0094 /* DMA channel 8 configuration register */ + +#define AT32_DMA_CNDTR1_OFFSET 0x000c /* DMA channel 1 number of data register */ +#define AT32_DMA_CNDTR2_OFFSET 0x0020 /* DMA channel 2 number of data register */ +#define AT32_DMA_CNDTR3_OFFSET 0x0034 /* DMA channel 3 number of data register */ +#define AT32_DMA_CNDTR4_OFFSET 0x0048 /* DMA channel 4 number of data register */ +#define AT32_DMA_CNDTR5_OFFSET 0x005c /* DMA channel 5 number of data register */ +#define AT32_DMA_CNDTR6_OFFSET 0x0070 /* DMA channel 6 number of data register */ +#define AT32_DMA_CNDTR7_OFFSET 0x0084 /* DMA channel 7 number of data register */ +#define AT32_DMA_CNDTR8_OFFSET 0x0098 /* DMA channel 8 number of data register */ + +#define AT32_DMA_CPAR1_OFFSET 0x0010 /* DMA channel 1 peripheral address register */ +#define AT32_DMA_CPAR2_OFFSET 0x0024 /* DMA channel 2 peripheral address register */ +#define AT32_DMA_CPAR3_OFFSET 0x0038 /* DMA channel 3 peripheral address register */ +#define AT32_DMA_CPAR4_OFFSET 0x004c /* DMA channel 4 peripheral address register */ +#define AT32_DMA_CPAR5_OFFSET 0x0060 /* DMA channel 5 peripheral address register */ +#define AT32_DMA_CPAR6_OFFSET 0x0074 /* DMA channel 6 peripheral address register */ +#define AT32_DMA_CPAR7_OFFSET 0x0088 /* DMA channel 7 peripheral address register */ +#define AT32_DMA_CPAR8_OFFSET 0x009c /* DMA channel 8 peripheral address register */ + +#define AT32_DMA_CMAR1_OFFSET 0x0014 /* DMA channel 1 memory address register */ +#define AT32_DMA_CMAR2_OFFSET 0x0028 /* DMA channel 2 memory address register */ +#define AT32_DMA_CMAR3_OFFSET 0x003c /* DMA channel 3 memory address register */ +#define AT32_DMA_CMAR4_OFFSET 0x0050 /* DMA channel 4 memory address register */ +#define AT32_DMA_CMAR5_OFFSET 0x0064 /* DMA channel 5 memory address register */ +#define AT32_DMA_CMAR6_OFFSET 0x0078 /* DMA channel 6 memory address register */ +#define AT32_DMA_CMAR7_OFFSET 0x008c /* DMA channel 7 memory address register */ +#define AT32_DMA_CMAR8_OFFSET 0x00a0 /* DMA channel 8 memory address register */ + +#ifdef DMA_HAVE_CSELR +# define AT32_DMA_CSELR_OFFSET 0x00a8 /* DMA channel selection register */ +#endif + +/* Register Addresses *******************************************************/ + +#define AT32_DMA1_ISRC (AT32_DMA1_BASE+AT32_DMA_ISR_OFFSET) +#define AT32_DMA1_IFCR (AT32_DMA1_BASE+AT32_DMA_IFCR_OFFSET) + +#define AT32_DMA1_CCR(n) (AT32_DMA1_BASE+AT32_DMA_CCR_OFFSET(n)) +#define AT32_DMA1_CCR1 (AT32_DMA1_BASE+AT32_DMA_CCR1_OFFSET) +#define AT32_DMA1_CCR2 (AT32_DMA1_BASE+AT32_DMA_CCR2_OFFSET) +#define AT32_DMA1_CCR3 (AT32_DMA1_BASE+AT32_DMA_CCR3_OFFSET) +#define AT32_DMA1_CCR4 (AT32_DMA1_BASE+AT32_DMA_CCR4_OFFSET) +#define AT32_DMA1_CCR5 (AT32_DMA1_BASE+AT32_DMA_CCR5_OFFSET) +#define AT32_DMA1_CCR6 (AT32_DMA1_BASE+AT32_DMA_CCR6_OFFSET) +#define AT32_DMA1_CCR7 (AT32_DMA1_BASE+AT32_DMA_CCR7_OFFSET) + +#define AT32_DMA1_CNDTR(n) (AT32_DMA1_BASE+AT32_DMA_CNDTR_OFFSET(n)) +#define AT32_DMA1_CNDTR1 (AT32_DMA1_BASE+AT32_DMA_CNDTR1_OFFSET) +#define AT32_DMA1_CNDTR2 (AT32_DMA1_BASE+AT32_DMA_CNDTR2_OFFSET) +#define AT32_DMA1_CNDTR3 (AT32_DMA1_BASE+AT32_DMA_CNDTR3_OFFSET) +#define AT32_DMA1_CNDTR4 (AT32_DMA1_BASE+AT32_DMA_CNDTR4_OFFSET) +#define AT32_DMA1_CNDTR5 (AT32_DMA1_BASE+AT32_DMA_CNDTR5_OFFSET) +#define AT32_DMA1_CNDTR6 (AT32_DMA1_BASE+AT32_DMA_CNDTR6_OFFSET) +#define AT32_DMA1_CNDTR7 (AT32_DMA1_BASE+AT32_DMA_CNDTR7_OFFSET) + +#define AT32_DMA1_CPAR(n) (AT32_DMA1_BASE+AT32_DMA_CPAR_OFFSET(n)) +#define AT32_DMA1_CPAR1 (AT32_DMA1_BASE+AT32_DMA_CPAR1_OFFSET) +#define AT32_DMA1_CPAR2 (AT32_DMA1_BASE+AT32_DMA_CPAR2_OFFSET) +#define AT32_DMA1_CPAR3 (AT32_DMA1_BASE+AT32_DMA_CPAR3_OFFSET) +#define AT32_DMA1_CPAR4 (AT32_DMA1_BASE+AT32_DMA_CPAR4_OFFSET) +#define AT32_DMA1_CPAR5 (AT32_DMA1_BASE+AT32_DMA_CPAR5_OFFSET) +#define AT32_DMA1_CPAR6 (AT32_DMA1_BASE+AT32_DMA_CPAR6_OFFSET) +#define AT32_DMA1_CPAR7 (AT32_DMA1_BASE+AT32_DMA_CPAR7_OFFSET) + +#define AT32_DMA1_CMAR(n) (AT32_DMA1_BASE+AT32_DMA_CMAR_OFFSET(n)) +#define AT32_DMA1_CMAR1 (AT32_DMA1_BASE+AT32_DMA_CMAR1_OFFSET) +#define AT32_DMA1_CMAR2 (AT32_DMA1_BASE+AT32_DMA_CMAR2_OFFSET) +#define AT32_DMA1_CMAR3 (AT32_DMA1_BASE+AT32_DMA_CMAR3_OFFSET) +#define AT32_DMA1_CMAR4 (AT32_DMA1_BASE+AT32_DMA_CMAR4_OFFSET) +#define AT32_DMA1_CMAR5 (AT32_DMA1_BASE+AT32_DMA_CMAR5_OFFSET) +#define AT32_DMA1_CMAR6 (AT32_DMA1_BASE+AT32_DMA_CMAR6_OFFSET) +#define AT32_DMA1_CMAR7 (AT32_DMA1_BASE+AT32_DMA_CMAR7_OFFSET) + +#define AT32_DMA2_ISRC (AT32_DMA2_BASE+AT32_DMA_ISR_OFFSET) +#define AT32_DMA2_IFCR (AT32_DMA2_BASE+AT32_DMA_IFCR_OFFSET) + +#define AT32_DMA2_CCR(n) (AT32_DMA2_BASE+AT32_DMA_CCR_OFFSET(n)) +#define AT32_DMA2_CCR1 (AT32_DMA2_BASE+AT32_DMA_CCR1_OFFSET) +#define AT32_DMA2_CCR2 (AT32_DMA2_BASE+AT32_DMA_CCR2_OFFSET) +#define AT32_DMA2_CCR3 (AT32_DMA2_BASE+AT32_DMA_CCR3_OFFSET) +#define AT32_DMA2_CCR4 (AT32_DMA2_BASE+AT32_DMA_CCR4_OFFSET) +#define AT32_DMA2_CCR5 (AT32_DMA2_BASE+AT32_DMA_CCR5_OFFSET) +#define AT32_DMA2_CCR6 (AT32_DMA2_BASE+AT32_DMA_CCR6_OFFSET) +#define AT32_DMA2_CCR7 (AT32_DMA2_BASE+AT32_DMA_CCR7_OFFSET) + +#define AT32_DMA2_CNDTR(n) (AT32_DMA2_BASE+AT32_DMA_CNDTR_OFFSET(n)) +#define AT32_DMA2_CNDTR1 (AT32_DMA2_BASE+AT32_DMA_CNDTR1_OFFSET) +#define AT32_DMA2_CNDTR2 (AT32_DMA2_BASE+AT32_DMA_CNDTR2_OFFSET) +#define AT32_DMA2_CNDTR3 (AT32_DMA2_BASE+AT32_DMA_CNDTR3_OFFSET) +#define AT32_DMA2_CNDTR4 (AT32_DMA2_BASE+AT32_DMA_CNDTR4_OFFSET) +#define AT32_DMA2_CNDTR5 (AT32_DMA2_BASE+AT32_DMA_CNDTR5_OFFSET) +#define AT32_DMA2_CNDTR6 (AT32_DMA2_BASE+AT32_DMA_CNDTR6_OFFSET) +#define AT32_DMA2_CNDTR7 (AT32_DMA2_BASE+AT32_DMA_CNDTR7_OFFSET) + +#define AT32_DMA2_CPAR(n) (AT32_DMA2_BASE+AT32_DMA_CPAR_OFFSET(n)) +#define AT32_DMA2_CPAR1 (AT32_DMA2_BASE+AT32_DMA_CPAR1_OFFSET) +#define AT32_DMA2_CPAR2 (AT32_DMA2_BASE+AT32_DMA_CPAR2_OFFSET) +#define AT32_DMA2_CPAR3 (AT32_DMA2_BASE+AT32_DMA_CPAR3_OFFSET) +#define AT32_DMA2_CPAR4 (AT32_DMA2_BASE+AT32_DMA_CPAR4_OFFSET) +#define AT32_DMA2_CPAR5 (AT32_DMA2_BASE+AT32_DMA_CPAR5_OFFSET) +#define AT32_DMA2_CPAR6 (AT32_DMA2_BASE+AT32_DMA_CPAR6_OFFSET) +#define AT32_DMA2_CPAR7 (AT32_DMA2_BASE+AT32_DMA_CPAR7_OFFSET) + +#define AT32_DMA2_CMAR(n) (AT32_DMA2_BASE+AT32_DMA_CMAR_OFFSET(n)) +#define AT32_DMA2_CMAR1 (AT32_DMA2_BASE+AT32_DMA_CMAR1_OFFSET) +#define AT32_DMA2_CMAR2 (AT32_DMA2_BASE+AT32_DMA_CMAR2_OFFSET) +#define AT32_DMA2_CMAR3 (AT32_DMA2_BASE+AT32_DMA_CMAR3_OFFSET) +#define AT32_DMA2_CMAR4 (AT32_DMA2_BASE+AT32_DMA_CMAR4_OFFSET) +#define AT32_DMA2_CMAR5 (AT32_DMA2_BASE+AT32_DMA_CMAR5_OFFSET) +#define AT32_DMA2_CMAR6 (AT32_DMA2_BASE+AT32_DMA_CMAR6_OFFSET) +#define AT32_DMA2_CMAR7 (AT32_DMA2_BASE+AT32_DMA_CMAR7_OFFSET) + +/* Register Bitfield Definitions ********************************************/ + +#define DMA_CHAN_SHIFT(n) ((n) << 2) +#define DMA_CHAN_MASK 0x0f +#define DMA_CHAN_GIF_BIT (1 << 0) /* Bit 0: Channel Global interrupt flag */ +#define DMA_CHAN_TCIF_BIT (1 << 1) /* Bit 1: Channel Transfer Complete flag */ +#define DMA_CHAN_HTIF_BIT (1 << 2) /* Bit 2: Channel Half Transfer flag */ +#define DMA_CHAN_TEIF_BIT (1 << 3) /* Bit 3: Channel Transfer Error flag */ + +/* DMA interrupt status register */ + +#define DMA_ISR_CHAN_SHIFT(n) DMA_CHAN_SHIFT(n) +#define DMA_ISR_CHAN_MASK(n) (DMA_CHAN_MASK << DMA_ISR_CHAN_SHIFT(n)) +#define DMA_ISR_CHAN1_SHIFT (0) /* Bits 3-0: DMA Channel 1 interrupt status */ +#define DMA_ISR_CHAN1_MASK (DMA_CHAN_MASK << DMA_ISR_CHAN1_SHIFT) +#define DMA_ISR_CHAN2_SHIFT (4) /* Bits 7-4: DMA Channel 2 interrupt status */ +#define DMA_ISR_CHAN2_MASK (DMA_CHAN_MASK << DMA_ISR_CHAN2_SHIFT) +#define DMA_ISR_CHAN3_SHIFT (8) /* Bits 11-8: DMA Channel 3 interrupt status */ +#define DMA_ISR_CHAN3_MASK (DMA_CHAN_MASK << DMA_ISR_CHAN3_SHIFT) +#define DMA_ISR_CHAN4_SHIFT (12) /* Bits 15-12: DMA Channel 4 interrupt status */ +#define DMA_ISR_CHAN4_MASK (DMA_CHAN_MASK << DMA_ISR_CHAN4_SHIFT) +#define DMA_ISR_CHAN5_SHIFT (16) /* Bits 19-16: DMA Channel 5 interrupt status */ +#define DMA_ISR_CHAN5_MASK (DMA_CHAN_MASK << DMA_ISR_CHAN5_SHIFT) +#define DMA_ISR_CHAN6_SHIFT (20) /* Bits 23-20: DMA Channel 6 interrupt status */ +#define DMA_ISR_CHAN6_MASK (DMA_CHAN_MASK << DMA_ISR_CHAN6_SHIFT) +#define DMA_ISR_CHAN7_SHIFT (24) /* Bits 27-24: DMA Channel 7 interrupt status */ +#define DMA_ISR_CHAN7_MASK (DMA_CHAN_MASK << DMA_ISR_CHAN7_SHIFT) +#define DMA_ISR_CHAN8_SHIFT (28) /* Bits 31-28: DMA Channel 8 interrupt status */ +#define DMA_ISR_CHAN8_MASK (DMA_CHAN_MASK << DMA_ISR_CHAN8_SHIFT) + +#define DMA_ISR_GIF(n) (DMA_CHAN_GIF_BIT << DMA_ISR_CHAN_SHIFT(n)) +#define DMA_ISR_TCIF(n) (DMA_CHAN_TCIF_BIT << DMA_ISR_CHAN_SHIFT(n)) +#define DMA_ISR_HTIF(n) (DMA_CHAN_HTIF_BIT << DMA_ISR_CHAN_SHIFT(n)) +#define DMA_ISR_TEIF(n) (DMA_CHAN_TEIF_BIT << DMA_ISR_CHAN_SHIFT(n)) + +/* DMA interrupt flag clear register */ + +#define DMA_IFCR_CHAN_SHIFT(n) DMA_CHAN_SHIFT(n) +#define DMA_IFCR_CHAN_MASK(n) (DMA_CHAN_MASK << DMA_IFCR_CHAN_SHIFT(n)) +#define DMA_IFCR_CHAN1_SHIFT (0) /* Bits 3-0: DMA Channel 1 interrupt flag clear */ +#define DMA_IFCR_CHAN1_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN1_SHIFT) +#define DMA_IFCR_CHAN2_SHIFT (4) /* Bits 7-4: DMA Channel 2 interrupt flag clear */ +#define DMA_IFCR_CHAN2_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN2_SHIFT) +#define DMA_IFCR_CHAN3_SHIFT (8) /* Bits 11-8: DMA Channel 3 interrupt flag clear */ +#define DMA_IFCR_CHAN3_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN3_SHIFT) +#define DMA_IFCR_CHAN4_SHIFT (12) /* Bits 15-12: DMA Channel 4 interrupt flag clear */ +#define DMA_IFCR_CHAN4_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN4_SHIFT) +#define DMA_IFCR_CHAN5_SHIFT (16) /* Bits 19-16: DMA Channel 5 interrupt flag clear */ +#define DMA_IFCR_CHAN5_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN5_SHIFT) +#define DMA_IFCR_CHAN6_SHIFT (20) /* Bits 23-20: DMA Channel 6 interrupt flag clear */ +#define DMA_IFCR_CHAN6_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN6_SHIFT) +#define DMA_IFCR_CHAN7_SHIFT (24) /* Bits 27-24: DMA Channel 7 interrupt flag clear */ +#define DMA_IFCR_CHAN7_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN7_SHIFT) +#define DMA_IFCR_CHAN8_SHIFT (28) /* Bits 31-28: DMA Channel 8 interrupt flag clear */ +#define DMA_IFCR_CHAN8_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN8_SHIFT) + +#if defined(CONFIG_AT32_HAVE_DMA1_CHAN8) || defined(CONFIG_AT32_HAVE_DMA2_CHAN678) +# define DMA_IFCR_ALLCHANNELS (0xffffffff) +#else +# define DMA_IFCR_ALLCHANNELS (0x0fffffff) +#endif + +#define DMA_IFCR_CGIF(n) (DMA_CHAN_GIF_BIT << DMA_IFCR_CHAN_SHIFT(n)) +#define DMA_IFCR_CTCIF(n) (DMA_CHAN_TCIF_BIT << DMA_IFCR_CHAN_SHIFT(n)) +#define DMA_IFCR_CHTIF(n) (DMA_CHAN_HTIF_BIT << DMA_IFCR_CHAN_SHIFT(n)) +#define DMA_IFCR_CTEIF(n) (DMA_CHAN_TEIF_BIT << DMA_IFCR_CHAN_SHIFT(n)) + +/* DMA channel configuration register */ + +#define DMA_CCR_EN (1 << 0) /* Bit 0: Channel enable */ +#define DMA_CCR_TCIE (1 << 1) /* Bit 1: Transfer complete interrupt enable */ +#define DMA_CCR_HTIE (1 << 2) /* Bit 2: Half Transfer interrupt enable */ +#define DMA_CCR_TEIE (1 << 3) /* Bit 3: Transfer error interrupt enable */ +#define DMA_CCR_DIR (1 << 4) /* Bit 4: Data transfer direction */ +#define DMA_CCR_CIRC (1 << 5) /* Bit 5: Circular mode */ +#define DMA_CCR_PINC (1 << 6) /* Bit 6: Peripheral increment mode */ +#define DMA_CCR_MINC (1 << 7) /* Bit 7: Memory increment mode */ +#define DMA_CCR_PSIZE_SHIFT (8) /* Bits 8-9: Peripheral size */ +#define DMA_CCR_PSIZE_MASK (3 << DMA_CCR_PSIZE_SHIFT) +# define DMA_CCR_PSIZE_8BITS (0 << DMA_CCR_PSIZE_SHIFT) /* 00: 8-bits */ +# define DMA_CCR_PSIZE_16BITS (1 << DMA_CCR_PSIZE_SHIFT) /* 01: 16-bits */ +# define DMA_CCR_PSIZE_32BITS (2 << DMA_CCR_PSIZE_SHIFT) /* 10: 32-bits */ +#define DMA_CCR_MSIZE_SHIFT (10) /* Bits 10-11: Memory size */ +#define DMA_CCR_MSIZE_MASK (3 << DMA_CCR_MSIZE_SHIFT) +# define DMA_CCR_MSIZE_8BITS (0 << DMA_CCR_MSIZE_SHIFT) /* 00: 8-bits */ +# define DMA_CCR_MSIZE_16BITS (1 << DMA_CCR_MSIZE_SHIFT) /* 01: 16-bits */ +# define DMA_CCR_MSIZE_32BITS (2 << DMA_CCR_MSIZE_SHIFT) /* 10: 32-bits */ +#define DMA_CCR_PL_SHIFT (12) /* Bits 12-13: Channel Priority level */ +#define DMA_CCR_PL_MASK (3 << DMA_CCR_PL_SHIFT) +# define DMA_CCR_PRILO (0 << DMA_CCR_PL_SHIFT) /* 00: Low */ +# define DMA_CCR_PRIMED (1 << DMA_CCR_PL_SHIFT) /* 01: Medium */ +# define DMA_CCR_PRIHI (2 << DMA_CCR_PL_SHIFT) /* 10: High */ +# define DMA_CCR_PRIVERYHI (3 << DMA_CCR_PL_SHIFT) /* 11: Very high */ +#define DMA_CCR_MEM2MEM (1 << 14) /* Bit 14: Memory to memory mode */ + +#define DMA_CCR_ALLINTS (DMA_CCR_TEIE|DMA_CCR_HTIE|DMA_CCR_TCIE) + +/* DMA channel number of data register */ + +#define DMA_CNDTR_NDT_SHIFT (0) /* Bits 15-0: Number of data to Transfer */ +#define DMA_CNDTR_NDT_MASK (0xffff << DMA_CNDTR_NDT_SHIFT) + +/* DMA Channel mapping. + * Each DMA channel has a mapping to several possible sources/sinks of data. + * The requests from peripherals assigned to a channel are simply OR'ed + * together before entering the DMA block. This means that onlyone request + * on a given channel can be enabled at once. + * + * Alternative DMA channel selections are provided with a numeric suffix like + * _1, _2, etc. Drivers, however, will use the pin selection without the + * numeric suffix. Additional definitions are required in the board.h file. + */ + +#define AT32_DMA1_CHAN1 (0) +#define AT32_DMA1_CHAN2 (1) +#define AT32_DMA1_CHAN3 (2) +#define AT32_DMA1_CHAN4 (3) +#define AT32_DMA1_CHAN5 (4) +#define AT32_DMA1_CHAN6 (5) +#define AT32_DMA1_CHAN7 (6) + +#define AT32_DMA2_CHAN1 (7) +#define AT32_DMA2_CHAN2 (8) +#define AT32_DMA2_CHAN3 (9) +#define AT32_DMA2_CHAN4 (10) +#define AT32_DMA2_CHAN5 (11) +#define AT32_DMA2_CHAN6 (12) +#define AT32_DMA2_CHAN7 (13) + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_DMA_H */ diff --git a/arch/arm/src/at32/hardware/at32_dmamux.h b/arch/arm/src/at32/hardware/at32_dmamux.h new file mode 100644 index 0000000000..c16364fd3b --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_dmamux.h @@ -0,0 +1,139 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_dmamux.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_DMAMUX_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_DMAMUX_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DMAMUX1 0 +#define DMAMUX2 1 + +/* Register Offsets *********************************************************/ + +#define AT32_DMAMUX_CXCR_OFFSET(x) (0x0000 + (0x0004 * (x + 1))) /* DMAMUX1 request line multiplexer channel x configuration register */ +#define AT32_DMAMUX_C0CR_OFFSET AT32_DMAMUX_CXCR_OFFSET(0) /* 0x000 */ +#define AT32_DMAMUX_C1CR_OFFSET AT32_DMAMUX_CXCR_OFFSET(1) /* 0x004 */ +#define AT32_DMAMUX_C2CR_OFFSET AT32_DMAMUX_CXCR_OFFSET(2) /* 0x008 */ +#define AT32_DMAMUX_C3CR_OFFSET AT32_DMAMUX_CXCR_OFFSET(3) /* 0x00c */ +#define AT32_DMAMUX_C4CR_OFFSET AT32_DMAMUX_CXCR_OFFSET(4) /* 0x010 */ +#define AT32_DMAMUX_C5CR_OFFSET AT32_DMAMUX_CXCR_OFFSET(5) /* 0x014 */ +#define AT32_DMAMUX_C6CR_OFFSET AT32_DMAMUX_CXCR_OFFSET(6) /* 0x018 */ + /* 0x040-0x07C: Reserved */ +#define AT32_DMAMUX_CSR_OFFSET 0x0030 /* DMAMUX1 request line multiplexer interrupt channel status register */ +#define AT32_DMAMUX_CFR_OFFSET 0x0034 /* DMAMUX1 request line multiplexer interrupt clear flag register */ + /* 0x088-0x0FC: Reserved */ +#define AT32_DMAMUX_RGXCR_OFFSET(x) (0x0020 + (0x004 * (x))) /* DMAMUX1 request generator channel x configuration register */ +#define AT32_DMAMUX_RG0CR_OFFSET AT32_DMAMUX_RGXCR_OFFSET(0) +#define AT32_DMAMUX_RG1CR_OFFSET AT32_DMAMUX_RGXCR_OFFSET(1) +#define AT32_DMAMUX_RG2CR_OFFSET AT32_DMAMUX_RGXCR_OFFSET(2) +#define AT32_DMAMUX_RG3CR_OFFSET AT32_DMAMUX_RGXCR_OFFSET(3) +#define AT32_DMAMUX_RGSR_OFFSET 0x0038 /* DMAMUX1 request generator interrupt status register */ +#define AT32_DMAMUX_RGCFR_OFFSET 0x003c /* DMAMUX1 request generator interrupt clear flag register */ + /* 0x148-0x3FC: Reserved */ + +/* Register Addresses *******************************************************/ + +/* Register Bitfield Definitions ********************************************/ + +/* DMAMUX1 CxCR - request line multiplexer channel x configuration register */ + +#define DMAMUX_CCR_DMAREQID_SHIFT (0) /* Bits 0-6: DMA request identification */ +#define DMAMUX_CCR_DMAREQID_MASK (0x7f << DMAMUX_CCR_DMAREQID_SHIFT) +# define DMAMUX_CCR_DMAREQID(x) ((x) << DMAMUX_CCR_DMAREQID_SHIFT) +#define DMAMUX_CCR_SOIE (8) /* Bit 8: Synchronization overrun interrupt enable */ +#define DMAMUX_CCR_EGE (9) /* Bit 9: Event generation enable */ +#define DMAMUX_CCR_SE (16) /* Bit 16: Synchronization enable */ +#define DMAMUX_CCR_SPOL_SHIFT (17) /* Bits 17-18: Synchronization polarity */ +#define DMAMUX_CCR_SPOL_MASK (3 << DMAMUX_CCR_SPOL_SHIFT) +# define DMAMUX_CCR_SPOL_NONE (0x0 << DMAMUX_CCR_SPOL_SHIFT) /* No event: No trigger detection or generation */ +# define DMAMUX_CCR_SPOL_RISING (0x1 << DMAMUX_CCR_SPOL_SHIFT) /* Rising edge */ +# define DMAMUX_CCR_SPOL_FALLING (0x2 << DMAMUX_CCR_SPOL_SHIFT) /* Falling edge */ +# define DMAMUX_CCR_SPOL_BOTH (0x3 << DMAMUX_CCR_SPOL_SHIFT) /* Both rising and falling edges */ +#define DMAMUX_CCR_NBREQ_SHIFT (19) /* Bits 19-23: Number of DMA request - 1 to forward */ +#define DMAMUX_CCR_NBREQ_MASK (0x1f << DMAMUX_CCR_NBREQ_SHIFT) +#define DMAMUX_CCR_SYNCID_SHIFT (24) /* Bits 24-26: Synchronization identification */ +#define DMAMUX_CCR_SYNCID_MASK (7 << DMAMUX_CCR_SYNCID_SHIFT) + +/* DMAMUX1 CSR - request line multiplexer interrupt channel status register */ + +#define DMAMUX1_CSR_SOF(x) (1 << (x)) /* Synchronization overrun event flag */ + +/* DMAMUX1 CFR - request line multiplexer interrupt clear flag register */ + +#define DMAMUX1_CFR_SOF(x) (1 << (x)) /* Clear synchronization overrun event flag */ + +/* DMAMUX1 RGCR - request generator channel x configuration register */ + +#define DMAMUX_RGCR_SIGID_SHIFT (0) /* Bits 0-4: Signal identification */ +#define DMAMUX_RGCR_SIGID_MASK (0x1f << DMAMUX_RGCR_SIGID_SHIFT) +#define DMAMUX_RGCR_OIE (8) /* Bit 8: Trigger overrun interrupt enable */ +#define DMAMUX_RGCR_GE (16) /* Bit 16: DMA request generator channel X enable*/ +#define DMAMUX_RGCR_GPOL_SHIFT (17) /* Bits 17-18: DMA request generator trigger polarity */ +#define DMAMUX_RGCR_GPOL_MASK (0x3 << DMAMUX_RGCR_GPOL_SHIFT) +# define DMAMUX_RGCR_GPOL_NONE (0x0 << DMAMUX_RGCR_GPOL_SHIFT) /* No event: No trigger detection or generation */ +# define DMAMUX_RGCR_GPOL_RISING (0x1 << DMAMUX_RGCR_GPOL_SHIFT) /* Rising edge */ +# define DMAMUX_RGCR_GPOL_FALLING (0x2 << DMAMUX_RGCR_GPOL_SHIFT) /* Falling edge */ +# define DMAMUX_RGCR_GPOL_BOTH (0x3 << DMAMUX_RGCR_GPOL_SHIFT) /* Both rising and falling edges */ +#define DMAMUX_RGCR_GNBREQ_SHIFT (19) /* Bits 19-23: Number of DMA requests to be generated -1 */ +#define DMAMUX_RGCR_GNBREQ_MASK (0x1f << DMAMUX_RGCR_GNBREQ_SHIFT) + +/* DMAMUX1 RGSR - request generator interrupt status register */ + +#define DMAMUX1_RGSR_OF(x) (1 << (x)) /* Trigger overrun event flag */ + +/* DMAMUX1 RGCFR - request generator interrupt clear flag register */ + +#define DMAMUX1_RGCFR_COF(x) (1 << (x)) /* Clear trigger overrun event flag */ + +/* DMA channel mapping + * + * XXXXX.DDD.CCCCCCCC + * C - DMAMUX request + * D - DMA controller + * X - free bits + */ + +#define DMAMAP_MAP(d,c) ((d) << 8 | (c)) +#define DMAMAP_CONTROLLER(m) ((m) >> 8 & 0x07) +#define DMAMAP_REQUEST(m) ((m) >> 0 & 0xff) + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/* Import DMAMUX map */ + +#if defined(CONFIG_AT32_AT32F43XX) +# include "hardware/at32f43xxx_dmamux.h" +#else +# error "Unsupported AT32 sub family" +#endif + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_DMAMUX_H */ diff --git a/arch/arm/src/at32/hardware/at32_eth.h b/arch/arm/src/at32/hardware/at32_eth.h new file mode 100644 index 0000000000..b713447f07 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_eth.h @@ -0,0 +1,738 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_eth.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_ETH_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_ETH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +#if AT32_NETHERNET > 0 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +/* MAC Registers */ + +#define AT32_ETH_MACCR_OFFSET 0x0000 /* Ethernet MAC configuration register */ +#define AT32_ETH_MACFFR_OFFSET 0x0004 /* Ethernet MAC frame filter register */ +#define AT32_ETH_MACHTHR_OFFSET 0x0008 /* Ethernet MAC hash table high register */ +#define AT32_ETH_MACHTLR_OFFSET 0x000c /* Ethernet MAC hash table low register */ +#define AT32_ETH_MACMIIAR_OFFSET 0x0010 /* Ethernet MAC MII address register */ +#define AT32_ETH_MACMIIDR_OFFSET 0x0014 /* Ethernet MAC MII data register */ +#define AT32_ETH_MACFCR_OFFSET 0x0018 /* Ethernet MAC flow control register */ +#define AT32_ETH_MACVLANTR_OFFSET 0x001c /* Ethernet MAC VLAN tag register */ +#define AT32_ETH_MACRWUFFR_OFFSET 0x0028 /* Ethernet MAC remote wakeup frame filter reg */ +#define AT32_ETH_MACPMTCSR_OFFSET 0x002c /* Ethernet MAC PMT control and status register */ +#define AT32_ETH_MACSR_OFFSET 0x0038 /* Ethernet MAC interrupt status register */ +#define AT32_ETH_MACIMR_OFFSET 0x003c /* Ethernet MAC interrupt mask register */ +#define AT32_ETH_MACA0HR_OFFSET 0x0040 /* Ethernet MAC address 0 high register */ +#define AT32_ETH_MACA0LR_OFFSET 0x0044 /* Ethernet MAC address 0 low register */ +#define AT32_ETH_MACA1HR_OFFSET 0x0048 /* Ethernet MAC address 1 high register */ +#define AT32_ETH_MACA1LR_OFFSET 0x004c /* Ethernet MAC address1 low register */ +#define AT32_ETH_MACA2HR_OFFSET 0x0050 /* Ethernet MAC address 2 high register */ +#define AT32_ETH_MACA2LR_OFFSET 0x0054 /* Ethernet MAC address 2 low register */ +#define AT32_ETH_MACA3HR_OFFSET 0x0058 /* Ethernet MAC address 3 high register */ +#define AT32_ETH_MACA3LR_OFFSET 0x005c /* Ethernet MAC address 3 low register */ + +/* MMC Registers */ + +#define AT32_ETH_MMCCR_OFFSET 0x0100 /* Ethernet MMC control register */ +#define AT32_ETH_MMCRIR_OFFSET 0x0104 /* Ethernet MMC receive interrupt register */ +#define AT32_ETH_MMCTIR_OFFSET 0x0108 /* Ethernet MMC transmit interrupt register */ +#define AT32_ETH_MMCRIMR_OFFSET 0x010c /* Ethernet MMC receive interrupt mask register */ +#define AT32_ETH_MMCTIMR_OFFSET 0x0110 /* Ethernet MMC transmit interrupt mask register */ +#define AT32_ETH_MMCTGFSCCR_OFFSET 0x014c /* Ethernet MMC transmitted good frames counter register (single collision) */ +#define AT32_ETH_MMCTGFMSCCR_OFFSET 0x0150 /* Ethernet MMC transmitted good frames counter register (multiple-collision) */ +#define AT32_ETH_MMCTGFCR_OFFSET 0x0168 /* Ethernet MMC transmitted good frames counter register */ +#define AT32_ETH_MMCRFCECR_OFFSET 0x0194 /* Ethernet MMC received frames with CRC error counter register */ +#define AT32_ETH_MMCRFAECR_OFFSET 0x0198 /* Ethernet MMC received frames with alignment error counter */ +#define AT32_ETH_MMCRGUFCR_OFFSET 0x01c4 /* MMC received good unicast frames counter register */ + +/* IEEE 1588 time stamp registers */ + +#define AT32_ETH_PTPTSCR_OFFSET 0x0700 /* Ethernet PTP time stamp control register */ +#define AT32_ETH_PTPSSIR_OFFSET 0x0704 /* Ethernet PTP subsecond increment register */ +#define AT32_ETH_PTPTSHR_OFFSET 0x0708 /* Ethernet PTP time stamp high register */ +#define AT32_ETH_PTPTSLR_OFFSET 0x070c /* Ethernet PTP time stamp low register */ +#define AT32_ETH_PTPTSHUR_OFFSET 0x0710 /* Ethernet PTP time stamp high update register */ +#define AT32_ETH_PTPTSLUR_OFFSET 0x0714 /* Ethernet PTP time stamp low update register */ +#define AT32_ETH_PTPTSAR_OFFSET 0x0718 /* Ethernet PTP time stamp addend register */ +#define AT32_ETH_PTPTTHR_OFFSET 0x071c /* Ethernet PTP target time high register */ +#define AT32_ETH_PTPTTLR_OFFSET 0x0720 /* Ethernet PTP target time low register */ +#define AT32_ETH_PTPTSSR_OFFSET 0x0728 /* Ethernet PTP time stamp status register */ +#define AT32_ETH_PTPPPSCR_OFFSET 0x072c /* Ethernet PTP PPS control register */ + +/* DMA Registers */ + +#define AT32_ETH_DMABMR_OFFSET 0x1000 /* Ethernet DMA bus mode register */ +#define AT32_ETH_DMATPDR_OFFSET 0x1004 /* Ethernet DMA transmit poll demand register */ +#define AT32_ETH_DMARPDR_OFFSET 0x1008 /* Ethernet DMA receive poll demand register */ +#define AT32_ETH_DMARDLAR_OFFSET 0x100c /* Ethernet DMA receive descriptor list address register */ +#define AT32_ETH_DMATDLAR_OFFSET 0x1010 /* Ethernet DMA transmit descriptor list address register */ +#define AT32_ETH_DMASR_OFFSET 0x1014 /* Ethernet DMA status register */ +#define AT32_ETH_DMAOMR_OFFSET 0x1018 /* Ethernet DMA operation mode register */ +#define AT32_ETH_DMAIER_OFFSET 0x101c /* Ethernet DMA interrupt enable register */ +#define AT32_ETH_DMAMFBOC_OFFSET 0x1020 /* Ethernet DMA missed frame and buffer overflow counter register */ +#define AT32_ETH_DMACHTDR_OFFSET 0x1048 /* Ethernet DMA current host transmit descriptor register */ +#define AT32_ETH_DMACHRDR_OFFSET 0x104c /* Ethernet DMA current host receive descriptor register */ +#define AT32_ETH_DMACHTBAR_OFFSET 0x1050 /* Ethernet DMA current host transmit buffer address register */ +#define AT32_ETH_DMACHRBAR_OFFSET 0x1054 /* Ethernet DMA current host receive buffer address register */ + +/* Register Base Addresses **************************************************/ + +/* MAC Registers */ + +#define AT32_ETH_MACCR (AT32_EMAC_BASE+AT32_ETH_MACCR_OFFSET) +#define AT32_ETH_MACFFR (AT32_EMAC_BASE+AT32_ETH_MACFFR_OFFSET) +#define AT32_ETH_MACHTHR (AT32_EMAC_BASE+AT32_ETH_MACHTHR_OFFSET) +#define AT32_ETH_MACHTLR (AT32_EMAC_BASE+AT32_ETH_MACHTLR_OFFSET) +#define AT32_ETH_MACMIIAR (AT32_EMAC_BASE+AT32_ETH_MACMIIAR_OFFSET) +#define AT32_ETH_MACMIIDR (AT32_EMAC_BASE+AT32_ETH_MACMIIDR_OFFSET) +#define AT32_ETH_MACFCR (AT32_EMAC_BASE+AT32_ETH_MACFCR_OFFSET) +#define AT32_ETH_MACVLANTR (AT32_EMAC_BASE+AT32_ETH_MACVLANTR_OFFSET) +#define AT32_ETH_MACRWUFFR (AT32_EMAC_BASE+AT32_ETH_MACRWUFFR_OFFSET) +#define AT32_ETH_MACPMTCSR (AT32_EMAC_BASE+AT32_ETH_MACPMTCSR_OFFSET) +#define AT32_ETH_MACSR (AT32_EMAC_BASE+AT32_ETH_MACSR_OFFSET) +#define AT32_ETH_MACIMR (AT32_EMAC_BASE+AT32_ETH_MACIMR_OFFSET) +#define AT32_ETH_MACA0HR (AT32_EMAC_BASE+AT32_ETH_MACA0HR_OFFSET) +#define AT32_ETH_MACA0LR (AT32_EMAC_BASE+AT32_ETH_MACA0LR_OFFSET) +#define AT32_ETH_MACA1HR (AT32_EMAC_BASE+AT32_ETH_MACA1HR_OFFSET) +#define AT32_ETH_MACA1LR (AT32_EMAC_BASE+AT32_ETH_MACA1LR_OFFSET) +#define AT32_ETH_MACA2HR (AT32_EMAC_BASE+AT32_ETH_MACA2HR_OFFSET) +#define AT32_ETH_MACA2LR (AT32_EMAC_BASE+AT32_ETH_MACA2LR_OFFSET) +#define AT32_ETH_MACA3HR (AT32_EMAC_BASE+AT32_ETH_MACA3HR_OFFSET) +#define AT32_ETH_MACA3LR (AT32_EMAC_BASE+AT32_ETH_MACA3LR_OFFSET) + +/* MMC Registers */ + +#define AT32_ETH_MMCC (AT32_EMAC_BASE+AT32_ETH_MMCCR_OFFSET) +#define AT32_ETH_MMCRIR (AT32_EMAC_BASE+AT32_ETH_MMCRIR_OFFSET) +#define AT32_ETH_MMCTIR (AT32_EMAC_BASE+AT32_ETH_MMCTIR_OFFSET) +#define AT32_ETH_MMCRIMR (AT32_EMAC_BASE+AT32_ETH_MMCRIMR_OFFSET) +#define AT32_ETH_MMCTIMR (AT32_EMAC_BASE+AT32_ETH_MMCTIMR_OFFSET) +#define AT32_ETH_MMCTGFSCCR (AT32_EMAC_BASE+AT32_ETH_MMCTGFSCCR_OFFSET) +#define AT32_ETH_MMCTGFMSCCR (AT32_EMAC_BASE+AT32_ETH_MMCTGFMSCCR_OFFSET) +#define AT32_ETH_MMCTGFCR (AT32_EMAC_BASE+AT32_ETH_MMCTGFCR_OFFSET) +#define AT32_ETH_MMCRFCECR (AT32_EMAC_BASE+AT32_ETH_MMCRFCECR_OFFSET) +#define AT32_ETH_MMCRFAECR (AT32_EMAC_BASE+AT32_ETH_MMCRFAECR_OFFSET) +#define AT32_ETH_MMCRGUFCR (AT32_EMAC_BASE+AT32_ETH_MMCRGUFCR_OFFSET) + +/* IEEE 1588 time stamp registers */ + +#define AT32_ETH_PTPTSCR (AT32_EMAC_BASE+AT32_ETH_PTPTSCR_OFFSET) +#define AT32_ETH_PTPSSIR (AT32_EMAC_BASE+AT32_ETH_PTPSSIR_OFFSET) +#define AT32_ETH_PTPTSHR (AT32_EMAC_BASE+AT32_ETH_PTPTSHR_OFFSET) +#define AT32_ETH_PTPTSLR (AT32_EMAC_BASE+AT32_ETH_PTPTSLR_OFFSET) +#define AT32_ETH_PTPTSHUR (AT32_EMAC_BASE+AT32_ETH_PTPTSHUR_OFFSET) +#define AT32_ETH_PTPTSLUR (AT32_EMAC_BASE+AT32_ETH_PTPTSLUR_OFFSET) +#define AT32_ETH_PTPTSAR (AT32_EMAC_BASE+AT32_ETH_PTPTSAR_OFFSET) +#define AT32_ETH_PTPTTHR (AT32_EMAC_BASE+AT32_ETH_PTPTTHR_OFFSET) +#define AT32_ETH_PTPTTLR (AT32_EMAC_BASE+AT32_ETH_PTPTTLR_OFFSET) +#define AT32_ETH_PTPTSSR (AT32_EMAC_BASE+AT32_ETH_PTPTSSR_OFFSET) +#define AT32_ETH_PTPPPSCR (AT32_EMAC_BASE+AT32_ETH_PTPPPSCR_OFFSET) + +/* DMA Registers */ + +#define AT32_ETH_DMABMR (AT32_EMAC_BASE+AT32_ETH_DMABMR_OFFSET) +#define AT32_ETH_DMATPDR (AT32_EMAC_BASE+AT32_ETH_DMATPDR_OFFSET) +#define AT32_ETH_DMARPDR (AT32_EMAC_BASE+AT32_ETH_DMARPDR_OFFSET) +#define AT32_ETH_DMARDLAR (AT32_EMAC_BASE+AT32_ETH_DMARDLAR_OFFSET) +#define AT32_ETH_DMATDLAR (AT32_EMAC_BASE+AT32_ETH_DMATDLAR_OFFSET) +#define AT32_ETH_DMASR (AT32_EMAC_BASE+AT32_ETH_DMASR_OFFSET) +#define AT32_ETH_DMAOMR (AT32_EMAC_BASE+AT32_ETH_DMAOMR_OFFSET) +#define AT32_ETH_DMAIER (AT32_EMAC_BASE+AT32_ETH_DMAIER_OFFSET) +#define AT32_ETH_DMAMFBOC (AT32_EMAC_BASE+AT32_ETH_DMAMFBOC_OFFSET) +#define AT32_ETH_DMACHTDR (AT32_EMAC_BASE+AT32_ETH_DMACHTDR_OFFSET) +#define AT32_ETH_DMACHRDR (AT32_EMAC_BASE+AT32_ETH_DMACHRDR_OFFSET) +#define AT32_ETH_DMACHTBAR (AT32_EMAC_BASE+AT32_ETH_DMACHTBAR_OFFSET) +#define AT32_ETH_DMACHRBAR (AT32_EMAC_BASE+AT32_ETH_DMACHRBAR_OFFSET) + +/* Register Bit-Field Definitions *******************************************/ + +/* MAC Registers */ + +/* Ethernet MAC configuration register */ + +#define ETH_MACCR_RE (1 << 2) /* Bit 2: Receiver enable */ +#define ETH_MACCR_TE (1 << 3) /* Bit 3: Transmitter enable */ +#define ETH_MACCR_DC (1 << 4) /* Bit 4: Deferral check */ +#define ETH_MACCR_BL_SHIFT (5) /* Bits 5-6: Back-off limit */ +#define ETH_MACCR_BL_MASK (3 << ETH_MACCR_BL_SHIFT) +# define ETH_MACCR_BL_10 (0 << ETH_MACCR_BL_SHIFT) /* 00: k = min (n, 10) */ +# define ETH_MACCR_BL_8 (1 << ETH_MACCR_BL_SHIFT) /* 01: k = min (n, 8) */ +# define ETH_MACCR_BL_4 (2 << ETH_MACCR_BL_SHIFT) /* 10: k = min (n, 4) */ +# define ETH_MACCR_BL_1 (3 << ETH_MACCR_BL_SHIFT) /* 11: k = min (n, 1) */ + +#define ETH_MACCR_APCS (1 << 7) /* Bit 7: Automatic pad/CRC stripping */ +#define ETH_MACCR_RD (1 << 9) /* Bit 9: Retry disable */ +#define ETH_MACCR_IPCO (1 << 10) /* Bit 10: IPv4 checksum offload */ +#define ETH_MACCR_DM (1 << 11) /* Bit 11: Duplex mode */ +#define ETH_MACCR_LM (1 << 12) /* Bit 12: Loopback mode */ +#define ETH_MACCR_ROD (1 << 13) /* Bit 13: Receive own disable */ +#define ETH_MACCR_FES (1 << 14) /* Bit 14: Fast Ethernet speed */ +#define ETH_MACCR_CSD (1 << 16) /* Bit 16: Carrier sense disable */ +#define ETH_MACCR_IFG_SHIFT (17) /* Bits 17-19: Interframe gap */ +#define ETH_MACCR_IFG_MASK (7 << ETH_MACCR_IFG_SHIFT) +# define ETH_MACCR_IFG(n) ((12-((n) >> 3)) << ETH_MACCR_IFG_SHIFT) /* n bit times, n=40,48,..96 */ + +#define ETH_MACCR_JD (1 << 22) /* Bit 22: Jabber disable */ +#define ETH_MACCR_WD (1 << 23) /* Bit 23: Watchdog disable */ + +/* Ethernet MAC frame filter register */ + +#define ETH_MACFFR_PM (1 << 0) /* Bit 0: Promiscuous mode */ +#define ETH_MACFFR_HU (1 << 1) /* Bit 1: Hash unicast */ +#define ETH_MACFFR_HM (1 << 2) /* Bit 2: Hash multicast */ +#define ETH_MACFFR_DAIF (1 << 3) /* Bit 3: Destination address inverse filtering */ +#define ETH_MACFFR_PAM (1 << 4) /* Bit 4: Pass all multicast */ +#define ETH_MACFFR_BFD (1 << 5) /* Bit 5: Broadcast frames disable */ +#define ETH_MACFFR_PCF_SHIFT (6) /* Bits 6-7: Pass control frames */ +#define ETH_MACFFR_PCF_MASK (3 << ETH_MACFFR_PCF_SHIFT) +# define ETH_MACFFR_PCF_NONE (0 << ETH_MACFFR_PCF_SHIFT) /* Prevents all control frames */ +# define ETH_MACFFR_PCF_PAUSE (1 << ETH_MACFFR_PCF_SHIFT) /* Prevents all except Pause control frames */ +# define ETH_MACFFR_PCF_ALL (2 << ETH_MACFFR_PCF_SHIFT) /* Forwards all control frames */ +# define ETH_MACFFR_PCF_FILTER (3 << ETH_MACFFR_PCF_SHIFT) /* Forwards all that pass address filter */ + +#define ETH_MACFFR_SAIF (1 << 8) /* Bit 8: Source address inverse filtering */ +#define ETH_MACFFR_SAF (1 << 9) /* Bit 9: Source address filter */ +#define ETH_MACFFR_HPF (1 << 10) /* Bit 10: Hash or perfect filter */ +#define ETH_MACFFR_RA (1 << 31) /* Bit 31: Receive all */ + +/* Ethernet MAC hash table high/low registers (32-bit values) */ + +/* Ethernet MAC MII address register */ + +#define ETH_MACMIIAR_MB (1 << 0) /* Bit 0: MII busy */ +#define ETH_MACMIIAR_MW (1 << 1) /* Bit 1: MII write */ +#define ETH_MACMIIAR_CR_SHIFT (2) /* Bits 2-5: Clock range */ +#define ETH_MACMIIAR_CR_MASK (15 << ETH_MACMIIAR_CR_SHIFT) + +#define ETH_MACMIIAR_CR_60_100 (0 << ETH_MACMIIAR_CR_SHIFT) /* 000 60-100 MHz HCLK/42 */ +#define ETH_MACMIIAR_CR_100_150 (1 << ETH_MACMIIAR_CR_SHIFT) /* 001 100-150 MHz HCLK/62 */ +#define ETH_MACMIIAR_CR_20_35 (2 << ETH_MACMIIAR_CR_SHIFT) /* 010 20-35 MHz HCLK/16 */ +#define ETH_MACMIIAR_CR_35_60 (3 << ETH_MACMIIAR_CR_SHIFT) /* 011 35-60 MHz HCLK/26 */ +#define ETH_MACMIIAR_CR_150_250 (4 << ETH_MACMIIAR_CR_SHIFT) /* 100 150-250 MHz HCLK/102 */ +#define ETH_MACMIIAR_CR_250_300 (5 << ETH_MACMIIAR_CR_SHIFT) /* 101 250-300 MHz HCLK/124 */ + +#define ETH_MACMIIAR_MR_SHIFT (6) /* Bits 6-10: MII register */ +#define ETH_MACMIIAR_MR_MASK (31 << ETH_MACMIIAR_MR_SHIFT) +#define ETH_MACMIIAR_PA_SHIFT (11) /* Bits 11-15: PHY address */ +#define ETH_MACMIIAR_PA_MASK (31 << ETH_MACMIIAR_PA_SHIFT) + +/* Ethernet MAC MII data register */ + +#define ETH_MACMIIDR_MASK (0xffff) + +/* Ethernet MAC flow control register */ + +#define ETH_MACFCR_FCB_BPA (1 << 0) /* Bit 0: Flow control busy/back pressure activate */ +#define ETH_MACFCR_TFCE (1 << 1) /* Bit 1: Transmit flow control enable */ +#define ETH_MACFCR_RFCE (1 << 2) /* Bit 2: Receive flow control enable */ +#define ETH_MACFCR_UPFD (1 << 3) /* Bit 3: Unicast pause frame detect */ +#define ETH_MACFCR_PLT_SHIFT (4) /* Bits 4-5: Pause low threshold */ +#define ETH_MACFCR_PLT_MASK (3 << ETH_MACFCR_PLT_SHIFT) +# define ETH_MACFCR_PLT_M4 (0 << ETH_MACFCR_PLT_SHIFT) /* 00 Pause - 4 slot times */ +# define ETH_MACFCR_PLT_M28 (1 << ETH_MACFCR_PLT_SHIFT) /* 01 Pause - 28 slot times */ +# define ETH_MACFCR_PLT_M144 (2 << ETH_MACFCR_PLT_SHIFT) /* 10 Pause - 144 slot times */ +# define ETH_MACFCR_PLT_M256 (3 << ETH_MACFCR_PLT_SHIFT) /* 11 Pause -s 256 slot times */ + +#define ETH_MACFCR_ZQPD (1 << 7) /* Bit 7: Zero-quanta pause disable */ +#define ETH_MACFCR_PT_SHIFT (16) /* Bits 16-31: Pause time */ +#define ETH_MACFCR_PT_MASK (0xffff << ETH_MACFCR_PT_SHIFT) + +/* Ethernet MAC VLAN tag register */ + +#define ETH_MACVLANTR_VLANTI_SHIFT (0) /* Bits 0-15: VLAN tag identifier (for receive frames) */ +#define ETH_MACVLANTR_VLANTI_MASK (0xffff << ETH_MACVLANTR_VLANTI_SHIFT) +#define ETH_MACVLANTR_VLANTC (1 << 16) /* Bit 16: 12-bit VLAN tag comparison */ + +/* Ethernet MAC remote wakeup frame filter reg. Provides 32-bit access to + * remote remote wake-up filters. + */ + +/* Ethernet MAC PMT control and status register */ + +#define ETH_MACPMTCSR_PD (1 << 0) /* Bit 0: Power down */ +#define ETH_MACPMTCSR_MPE (1 << 1) /* Bit 1: Magic Packet enable */ +#define ETH_MACPMTCSR_WFE (1 << 2) /* Bit 2: Wakeup frame enable */ +#define ETH_MACPMTCSR_MPR (1 << 5) /* Bit 5: Magic packet received */ +#define ETH_MACPMTCSR_WFR (1 << 6) /* Bit 6: Wakeup frame received */ +#define ETH_MACPMTCSR_GU (1 << 9) /* Bit 9: Global unicast */ + +/* Ethernet MAC interrupt status register */ + +#define ETH_MACSR_PMTS (1 << 3) /* Bit 3: PMT status */ +#define ETH_MACSR_MMCS (1 << 4) /* Bit 4: MMC status */ +#define ETH_MACSR_MMCRS (1 << 5) /* Bit 5: MMC receive status */ +#define ETH_MACSR_MMCTS (1 << 6) /* Bit 6: MMC transmit status */ +#define ETH_MACSR_TSTS (1 << 9) /* Bit 9: Time stamp trigger status */ + +/* Ethernet MAC interrupt mask register */ + +#define ETH_MACIMR_PMTIM (1 << 3) /* Bit 3: PMT interrupt mask */ +#define ETH_MACIMR_TSTIM (1 << 9) /* Bit 9: Time stamp trigger interrupt mask */ +#define ETH_MACIMR_ALLINTS (ETH_MACIMR_PMTIM|ETH_MACIMR_TSTIM) + +/* Ethernet MAC address 0 high register */ + +#define ETH_MACA0HR_MACA0H_SHIFT (0) /* Bits 0-15: MAC address0 high [47:32] */ +#define ETH_MACA0HR_MACA0H_MASK (0xffff << ETH_MACA0HR_MACA0H_SHIFT) +#define ETH_MACA0HR_MO (1 << 31) /* Bit 31:Always */ + +/* Ethernet MAC address 0 low register (MAC address0 low [31:0]) */ + +/* Ethernet MAC address 1 high register */ + +#define ETH_MACA1HR_MACA1H_SHIFT (0) /* Bits 0-15: MAC address1 high [47:32] */ +#define ETH_MACA1HR_MACA1H_MASK (0xffff << ETH_MACA1HR_MACA1H_SHIFT) +#define ETH_MACA1HR_MBC_SHIFT (24) /* Bits 24-29: Mask byte control */ +#define ETH_MACA1HR_MBC_MASK (0x3f << ETH_MACA1HR_MBC_SHIFT) +# define ETH_MACA1HR_MBC_40_47 (0x20 << ETH_MACA1HR_MBC_SHIFT) /* Bit 29: ETH_MACA1HR [8-15] */ +# define ETH_MACA1HR_MBC_32_39 (0x10 << ETH_MACA1HR_MBC_SHIFT) /* Bit 28: ETH_MACA1HR [0-7] */ +# define ETH_MACA1HR_MBC_24_31 (0x08 << ETH_MACA1HR_MBC_SHIFT) /* Bit 27: ETH_MACA1LR [24-31] */ +# define ETH_MACA1HR_MBC_16_23 (0x04 << ETH_MACA1HR_MBC_SHIFT) /* Bit 26: ETH_MACA1LR [16-23] */ +# define ETH_MACA1HR_MBC_8_15 (0x02 << ETH_MACA1HR_MBC_SHIFT) /* Bit 25: ETH_MACA1LR [8-15] */ +# define ETH_MACA1HR_MBC_0_7 (0x01 << ETH_MACA1HR_MBC_SHIFT) /* Bit 24: ETH_MACA1LR [0-7] */ + +#define ETH_MACA1HR_SA (1 << 30) /* Bit 30: Source address */ +#define ETH_MACA1HR_AE (1 << 31) /* Bit 31: Address enable */ + +/* Ethernet MAC address1 low register (MAC address1 low [31:0]) */ + +/* Ethernet MAC address 2 high register */ + +#define ETH_MACA2HR_MACA2H_SHIFT (0) /* Bits 0-15: MAC address2 high [47:32] */ +#define ETH_MACA2HR_MACA2H_MASK (0xffff << ETH_MACA2HR_MACA2H_SHIFT) +#define ETH_MACA2HR_MBC_SHIFT (24) /* Bits 24-29: Mask byte control */ +#define ETH_MACA2HR_MBC_MASK (0x3f << ETH_MACA2HR_MBC_SHIFT) +# define ETH_MACA2HR_MBC_40_47 (0x20 << ETH_MACA2HR_MBC_SHIFT) /* Bit 29: ETH_MACA2HR [8-15] */ +# define ETH_MACA2HR_MBC_32_39 (0x10 << ETH_MACA2HR_MBC_SHIFT) /* Bit 28: ETH_MACA2HR [0-7] */ +# define ETH_MACA2HR_MBC_24_31 (0x08 << ETH_MACA2HR_MBC_SHIFT) /* Bit 27: ETH_MACA2LR [24-31] */ +# define ETH_MACA2HR_MBC_16_23 (0x04 << ETH_MACA2HR_MBC_SHIFT) /* Bit 26: ETH_MACA2LR [16-23] */ +# define ETH_MACA2HR_MBC_8_15 (0x02 << ETH_MACA2HR_MBC_SHIFT) /* Bit 25: ETH_MACA2LR [8-15] */ +# define ETH_MACA2HR_MBC_0_7 (0x01 << ETH_MACA2HR_MBC_SHIFT) /* Bit 24: ETH_MACA2LR [0-7] */ + +#define ETH_MACA2HR_SA (1 << 30) /* Bit 30: Source address */ +#define ETH_MACA2HR_AE (1 << 31) /* Bit 31: Address enable */ + +/* Ethernet MAC address 2 low register (MAC address2 low [31:0]) */ + +/* Ethernet MAC address 3 high register */ + +#define ETH_MACA3HR_MACA3H_SHIFT (0) /* Bits 0-15: MAC address3 high [47:32] */ +#define ETH_MACA3HR_MACA3H_MASK (0xffff << ETH_MACA3HR_MACA3H_SHIFT) +#define ETH_MACA3HR_MBC_SHIFT (24) /* Bits 24-29: Mask byte control */ +#define ETH_MACA3HR_MBC_MASK (0x3f << ETH_MACA3HR_MBC_SHIFT) +# define ETH_MACA3HR_MBC_40_47 (0x20 << ETH_MACA3HR_MBC_SHIFT) /* Bit 29: ETH_MACA3HR [8-15] */ +# define ETH_MACA3HR_MBC_32_39 (0x10 << ETH_MACA3HR_MBC_SHIFT) /* Bit 28: ETH_MACA3HR [0-7] */ +# define ETH_MACA3HR_MBC_24_31 (0x08 << ETH_MACA3HR_MBC_SHIFT) /* Bit 27: ETH_MACA3LR [24-31] */ +# define ETH_MACA3HR_MBC_16_23 (0x04 << ETH_MACA3HR_MBC_SHIFT) /* Bit 26: ETH_MACA3LR [16-23] */ +# define ETH_MACA3HR_MBC_8_15 (0x02 << ETH_MACA3HR_MBC_SHIFT) /* Bit 25: ETH_MACA3LR [8-15] */ +# define ETH_MACA3HR_MBC_0_7 (0x01 << ETH_MACA3HR_MBC_SHIFT) /* Bit 24: ETH_MACA3LR [0-7] */ + +#define ETH_MACA3HR_SA (1 << 30) /* Bit 30: Source address */ +#define ETH_MACA3HR_AE (1 << 31) /* Bit 31: Address enable */ + +/* Ethernet MAC address 3 low register (MAC address3 low [31:0]) */ + +/* MMC Registers */ + +/* Ethernet MMC control register */ + +#define ETH_MMCCR_CR (1 << 0) /* Bit 0: Counter reset */ +#define ETH_MMCCR_CSR (1 << 1) /* Bit 1: Counter stop rollover */ +#define ETH_MMCCR_ROR (1 << 2) /* Bit 2: Reset on read */ +#define ETH_MMCCR_MCF (1 << 3) /* Bit 3: MMC counter freeze */ + +/* Ethernet MMC receive interrupt and interrupt mask registers */ + +#define ETH_MMCRI_RFCE (1 << 5) /* Bit 5: Received frame CRC error */ +#define ETH_MMCRI_RFAE (1 << 6) /* Bit 6: Received frames alignment error */ +#define ETH_MMCRI_RGUF (1 << 17) /* Bit 17: Received good unicast frames */ + +/* Ethernet MMC transmit interrupt and interrupt mask register */ + +#define ETH_MMCTI_TGFSC (1 << 14) /* Bit 14: Transmitted good frames single collision */ +#define ETH_MMCTI_TGFMSC (1 << 15) /* Bit 15: Transmitted good frames more single collision */ +#define ETH_MMCTI_TGF (1 << 21) /* Bit 21: Transmitted good frames */ + +/* 32-bit counters: + * + * Ethernet MMC transmitted good frames counter register (single collision) + * Ethernet MMC transmitted good frames counter register (multiple-collision) + * Ethernet MMC transmitted good frames counter register + * Ethernet MMC received frames with CRC error counter register + * Ethernet MMC received frames with alignment error counter + * MMC received good unicast frames counter register + */ + +/* IEEE 1588 time stamp registers */ + +/* Ethernet PTP time stamp control register */ + +#define ETH_PTPTSCR_TSE (1 << 0) /* Bit 0: Time stamp enable */ +#define ETH_PTPTSCR_TSFCU (1 << 1) /* Bit 1: Time stamp fine or coarse update */ +#define ETH_PTPTSCR_TSSTI (1 << 2) /* Bit 2: Time stamp system time initialize */ +#define ETH_PTPTSCR_TSSTU (1 << 3) /* Bit 3: Time stamp system time update */ +#define ETH_PTPTSCR_TSITE (1 << 4) /* Bit 4: Time stamp interrupt trigger enable */ +#define ETH_PTPTSCR_TSARU (1 << 5) /* Bit 5: Time stamp addend register update */ + +#if defined(CONFIG_AT32_AT32F43XX) +#define ETH_PTPTSCR_TSSARFE (1 << 8) /* Bit 8: Time stamp snapshot for all received frames enable */ +#define ETH_PTPTSCR_TSSSR (1 << 9) /* Bit 9: Time stamp subsecond rollover: digital or binary rollover control */ +#define ETH_PTPTSCR_TSPTPPSV2E (1 << 10) /* Bit 10: Time stamp PTP packet snooping for version2 format enable */ +#define ETH_PTPTSCR_TSSPTPOEFE (1 << 11) /* Bit 11: Time stamp snapshot for PTP over ethernet frames enable */ +#define ETH_PTPTSCR_TSSIPV6FE (1 << 12) /* Bit 12: Time stamp snapshot for IPv6 frames enable */ +#define ETH_PTPTSCR_TSSIPV4FE (1 << 13) /* Bit 13: Time stamp snapshot for IPv4 frames enable */ +#define ETH_PTPTSCR_TSSEME (1 << 14) /* Bit 14: Time stamp snapshot for event message enable */ +#define ETH_PTPTSCR_TSSMRME (1 << 15) /* Bit 15: Time stamp snapshot for message relevant to master enable */ +#define ETH_PTPTSCR_TSCNT_SHIFT (16) /* Bits 16-17: Time stamp clock node type */ +#define ETH_PTPTSCR_TSCNT_MASK (3 << ETH_PTPTSCR_TSCNT_SHIFT) +# define ETH_PTPTSCR_TSCNT_ORDINARY (0 << ETH_PTPTSCR_TSCNT_SHIFT) /* 00: Ordinary clock */ +# define ETH_PTPTSCR_TSCNT_BOUNDARY (1 << ETH_PTPTSCR_TSCNT_SHIFT) /* 01: Boundary clock */ +# define ETH_PTPTSCR_TSCNT_E2E (2 << ETH_PTPTSCR_TSCNT_SHIFT) /* 10: End-to-end transparent clock */ +# define ETH_PTPTSCR_TSCNT_P2P (3 << ETH_PTPTSCR_TSCNT_SHIFT) /* 11: Peer-to-peer transparent clock */ + +#define ETH_PTPTSCR_TSPFFMAE (1 << 18) /* Bit 18: Time stamp PTP frame filtering MAC address enable */ +#endif + +/* Ethernet PTP subsecond increment register */ + +#define ETH_PTPSSIR_MASK (0xff) + +/* Ethernet PTP time stamp high register (32-bit) */ + +/* Ethernet PTP time stamp low register */ + +#define ETH_PTPTSLR_STPNS (1 << 31) /* Bit 31: System time positive or negative sign */ +#define ETH_PTPTSLR_MASK (0x7fffffff) /* Bits 0-30: System time subseconds */ + +/* Ethernet PTP time stamp high update register (32-bit) */ + +/* Ethernet PTP time stamp low update register */ + +#define ETH_PTPTSLU_TSUPNS (1 << 31) /* Bit 31: System time positive or negative sign */ +#define ETH_PTPTSLU_MASK (0x7fffffff) /* Bits 0-30: Time stamp update subsecond */ + +/* Ethernet PTP time stamp addend register (32-bit) */ + +/* Ethernet PTP target time high register (32-bit) */ + +/* Ethernet PTP target time low register (32-bit) */ + +/* Ethernet PTP time stamp status register */ + +#define ETH_PTPTSSR_TSSO (1 << 0) /* Bit 0: Time stamp second overflow */ +#define ETH_PTPTSSR_TSTTR (1 << 1) /* Bit 1: Time stamp target time reached */ + +/* Ethernet PTP PPS control register */ + +#define ETH_PTPPPSCR_PPSFREQ_SHIFT (0) /* Bits 0-3: PPS frequency selection */ +#define ETH_PTPPPSCR_PPSFREQ_MASK (15 << ETH_PTPPPSCR_PPSFREQ_SHIFT) +# define ETH_PTPPPSCR_PPSFREQ_1HZ (0 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 1 Hz with pulse width of 125/100 ms for binary/digital rollover */ +# define ETH_PTPPPSCR_PPSFREQ_2HZ (1 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 2 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_4HZ (2 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 4 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_8HZ (3 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 8 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_16HZ (4 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 16 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_32HZ (5 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 32 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_64HZ (6 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 64 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_128HZ (7 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 128 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_256HZ (8 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 256 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_512HZ (9 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 512 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_1KHZ (10 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 1024 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_2KHZ (11 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 2048 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_4KHZ (12 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 4096 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_8KHZ (13 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 8192 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_16KHZ (14 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 16384 Hz with 50% duty cycle */ +# define ETH_PTPPPSCR_PPSFREQ_32KHZ (15 << ETH_PTPPPSCR_PPSFREQ_SHIFT) /* 32768 Hz with 50% duty cycle */ + +/* DMA Registers */ + +/* Ethernet DMA bus mode register */ + +#define ETH_DMABMR_SR (1 << 0) /* Bit 0: Software reset */ +#define ETH_DMABMR_DA (1 << 1) /* Bit 1: DMA Arbitration */ +#define ETH_DMABMR_DSL_SHIFT (2) /* Bits 2-6: Descriptor skip length */ +#define ETH_DMABMR_DSL_MASK (31 << ETH_DMABMR_DSL_SHIFT) +# define ETH_DMABMR_DSL(n) ((n) << ETH_DMABMR_DSL_SHIFT) + +#define ETH_DMABMR_PBL_SHIFT (8) /* Bits 8-13: Programmable burst length */ + +# define ETH_DMABMR_PBL(n) ((n) << ETH_DMABMR_PBL_SHIFT) /* n=1, 2, 4, 8, 16, 32 */ +#define ETH_DMABMR_PBL_MASK (0x3f << ETH_DMABMR_PBL_SHIFT) + +#define ETH_DMABMR_RTPR_SHIFT (14) /* Bits 14-15: Rx Tx priority ratio */ +#define ETH_DMABMR_RTPR_MASK (3 << ETH_DMABMR_RTPR_SHIFT) +# define ETH_DMABMR_RTPR_1TO1 (0 << ETH_DMABMR_RTPR_SHIFT) /* 00: 1:1 */ +# define ETH_DMABMR_RTPR_2TO1 (1 << ETH_DMABMR_RTPR_SHIFT) /* 01: 2:1 */ +# define ETH_DMABMR_RTPR_3TO1 (2 << ETH_DMABMR_RTPR_SHIFT) /* 10: 3:1 */ +# define ETH_DMABMR_RTPR_4TO1 (3 << ETH_DMABMR_RTPR_SHIFT) /* 11: 4:1 */ + +#define ETH_DMABMR_FB (1 << 16) /* Bit 16: Fixed burst */ +#define ETH_DMABMR_RDP_SHIFT (17) /* Bits 17-22: Rx DMA PBL */ +#define ETH_DMABMR_RDP_MASK (0x3f << ETH_DMABMR_RDP_SHIFT) +# define ETH_DMABMR_RDP(n) ((n) << ETH_DMABMR_RDP_SHIFT) /* n=1, 2, 4, 8, 16, 32 */ + +#define ETH_DMABMR_USP (1 << 23) /* Bit 23: Use separate PBL */ +#define ETH_DMABMR_FPM (1 << 24) /* Bit 24: 8xPBL mode */ +#define ETH_DMABMR_AAB (1 << 25) /* Bit 25: Address-aligned beats */ + +/* Ethernet DMA transmit poll demand register (32-bit) */ + +/* Ethernet DMA receive poll demand register (32-bit) */ + +/* Ethernet DMA receive descriptor list address register (32-bit address) */ + +/* Ethernet DMA transmit descriptor list address register (32-bit address) */ + +/* Interrupt bit definitions common between the DMA status register (DMASR) + * and the DMA interrupt enable register (DMAIER). + */ + +#define ETH_DMAINT_TI (1 << 0) /* Bit 0: Transmit interrupt */ +#define ETH_DMAINT_TPSI (1 << 1) /* Bit 1: Transmit process stopped interrupt */ +#define ETH_DMAINT_TBUI (1 << 2) /* Bit 2: Transmit buffer unavailable interrupt */ +#define ETH_DMAINT_TJTI (1 << 3) /* Bit 3: Transmit jabber timeout interrupt */ +#define ETH_DMAINT_ROI (1 << 4) /* Bit 4: Overflow interrupt */ +#define ETH_DMAINT_TUI (1 << 5) /* Bit 5: Underflow interrupt */ +#define ETH_DMAINT_RI (1 << 6) /* Bit 6: Receive interrupt */ +#define ETH_DMAINT_RBUI (1 << 7) /* Bit 7: Receive buffer unavailable interrupt */ +#define ETH_DMAINT_RPSI (1 << 8) /* Bit 8: Receive process stopped interrupt */ +#define ETH_DMAINT_RWTI (1 << 9) /* Bit 9: Receive watchdog timeout interrupt */ +#define ETH_DMAINT_ETI (1 << 10) /* Bit 10: Early transmit interrupt */ +#define ETH_DMAINT_FBEI (1 << 13) /* Bit 13: Fatal bus error interrupt */ +#define ETH_DMAINT_ERI (1 << 14) /* Bit 14: Early receive interrupt */ +#define ETH_DMAINT_AIS (1 << 15) /* Bit 15: Abnormal interrupt summary */ +#define ETH_DMAINT_NIS (1 << 16) /* Bit 16: Normal interrupt summary */ + +/* Ethernet DMA status register (in addition to the interrupt bits above */ + +#define ETH_DMASR_RPS_SHIFT (17) /* Bits 17-19: Receive process state */ +#define ETH_DMASR_RPS_MASK (7 << ETH_DMASR_RPS_SHIFT) +# define ETH_DMASR_RPS_STOPPED (0 << ETH_DMASR_RPS_SHIFT) /* 000: Stopped: Reset or Stop Receive Command issued */ +# define ETH_DMASR_RPS_RXDESC (1 << ETH_DMASR_RPS_SHIFT) /* 001: Running: Fetching receive transfer descriptor */ +# define ETH_DMASR_RPS_WAITING (3 << ETH_DMASR_RPS_SHIFT) /* 011: Running: Waiting for receive packet */ +# define ETH_DMASR_RPS_SUSPENDED (4 << ETH_DMASR_RPS_SHIFT) /* 100: Suspended: Receive descriptor unavailable */ +# define ETH_DMASR_RPS_CLOSING (5 << ETH_DMASR_RPS_SHIFT) /* 101: Running: Closing receive descriptor */ +# define ETH_DMASR_RPS_TRANSFER (6 << ETH_DMASR_RPS_SHIFT) /* 111: Running: Transferring the receive data to memory */ + +#define ETH_DMASR_TPS_SHIFT (20) /* Bits 20-22: Transmit process state */ +#define ETH_DMASR_TPS_MASK (7 << ETH_DMASR_TPS_SHIFT) +# define ETH_DMASR_TPS_STOPPED (0 << ETH_DMASR_TPS_SHIFT) /* 000: Stopped; Reset or Stop Transmit Command issued */ +# define ETH_DMASR_TPS_TXDESC (1 << ETH_DMASR_TPS_SHIFT) /* 001: Running; Fetching transmit transfer descriptor */ +# define ETH_DMASR_TPS_WAITING (2 << ETH_DMASR_TPS_SHIFT) /* 010: Running; Waiting for status */ +# define ETH_DMASR_TPS_TRANSFER (3 << ETH_DMASR_TPS_SHIFT) /* 011: Running; Reading data and queuing to transmit (TxFIFO) */ +# define ETH_DMASR_TPS_SUSPENDED (6 << ETH_DMASR_TPS_SHIFT) /* 110: Suspended; Transmit descriptor unavailable or buffer underflow */ +# define ETH_DMASR_TPS_CLOSING (7 << ETH_DMASR_TPS_SHIFT) /* 111: Running; Closing transmit descriptor */ + +#define ETH_DMASR_EBS_SHIFT (23) /* Bits 23-25: Error bits status */ +#define ETH_DMASR_EBS_MASK (7 << ETH_DMASR_EBS_SHIFT) +#define ETH_DMASR_EBS_TXDMS (1 << ETH_DMASR_EBS_SHIFT) /* Bit 23 1 Error during data transfer by TxDMA */ +#define ETH_DMASR_EBS_READ (2 << ETH_DMASR_EBS_SHIFT) /* Bit 24 1 Error during read transfer */ +#define ETH_DMASR_EBS_DESC (4 << ETH_DMASR_EBS_SHIFT) /* Bit 25 1 Error during descriptor access */ + +#define ETH_DMASR_MMCS (1 << 27) /* Bit 27: MMC status */ +#define ETH_DMASR_PMTS (1 << 28) /* Bit 28: PMT status */ +#define ETH_DMASR_TSTS (1 << 29) /* Bit 29: Time stamp trigger status */ + +/* Ethernet DMA operation mode register */ + +#define ETH_DMAOMR_SR (1 << 1) /* Bit 1: Start/stop receive */ +#define ETH_DMAOMR_OSF (1 << 2) /* Bit 2: Operate on second frame */ +#define ETH_DMAOMR_RTC_SHIFT (3) /* Bits 3-4: Receive threshold control */ +#define ETH_DMAOMR_RTC_MASK (3 << ETH_DMAOMR_RTC_SHIFT) +# define ETH_DMAOMR_RTC_64 (0 << ETH_DMAOMR_RTC_SHIFT) +# define ETH_DMAOMR_RTC_32 (1 << ETH_DMAOMR_RTC_SHIFT) +# define ETH_DMAOMR_RTC_96 (2 << ETH_DMAOMR_RTC_SHIFT) +# define ETH_DMAOMR_RTC_128 (3 << ETH_DMAOMR_RTC_SHIFT) +#define ETH_DMAOMR_FUGF (1 << 6) /* Bit 6: Forward undersized good frames */ +#define ETH_DMAOMR_FEF (1 << 7) /* Bit 7: Forward error frames */ +#define ETH_DMAOMR_ST (1 << 13) /* Bit 13: Start/stop transmission */ +#define ETH_DMAOMR_TTC_SHIFT (14) /* Bits 14-16: Transmit threshold control */ +#define ETH_DMAOMR_TTC_MASK (7 << ETH_DMAOMR_TTC_SHIFT) +# define ETH_DMAOMR_TTC_64 (0 << ETH_DMAOMR_TTC_SHIFT) +# define ETH_DMAOMR_TTC_128 (1 << ETH_DMAOMR_TTC_SHIFT) +# define ETH_DMAOMR_TTC_192 (2 << ETH_DMAOMR_TTC_SHIFT) +# define ETH_DMAOMR_TTC_256 (3 << ETH_DMAOMR_TTC_SHIFT) +# define ETH_DMAOMR_TTC_40 (4 << ETH_DMAOMR_TTC_SHIFT) +# define ETH_DMAOMR_TTC_32 (5 << ETH_DMAOMR_TTC_SHIFT) +# define ETH_DMAOMR_TTC_24 (6 << ETH_DMAOMR_TTC_SHIFT) +# define ETH_DMAOMR_TTC_16 (7 << ETH_DMAOMR_TTC_SHIFT) +#define ETH_DMAOMR_FTF (1 << 20) /* Bit 20: Flush transmit FIFO */ +#define ETH_DMAOMR_TSF (1 << 21) /* Bit 21: Transmit store and forward */ +#define ETH_DMAOMR_DFRF (1 << 24) /* Bit 24: Disable flushing of received frames */ +#define ETH_DMAOMR_RSF (1 << 25) /* Bit 25: Receive store and forward */ +#define ETH_DMAOMR_DTCEFD (1 << 26) /* Bit 26: Dropping of TCP/IP checksum error frames disable */ + +/* Ethernet DMA missed frame and buffer overflow counter register */ + +#define ETH_DMAMFBOC_MFC_SHIFT (0) /* Bits 0-15: Missed frames by the controller */ +#define ETH_DMAMFBOC_MFC_MASK (0xffff << ETH_DMAMFBOC_MFC_SHIFT) +#define ETH_DMAMFBOC_OMFC (1 << 16) /* Bit 16: Overflow bit for missed frame counter */ +#define ETH_DMAMFBOC_MFA_SHIFT (17) /* Bits 17-27: Missed frames by the application */ +#define ETH_DMAMFBOC_MFA_MASK (0x7ff << ETH_DMAMFBOC_MFA_SHIFT) +#define ETH_DMAMFBOC_OFOC (1 << 28) /* Bit 28: Overflow bit for FIFO overflow counter */ + +/* Ethernet DMA current host transmit descriptor register + * (32-bit address) + */ + +/* Ethernet DMA current host receive descriptor register + * (32-bit address) + */ + +/* Ethernet DMA current host transmit buffer address register + * (32-bit address) + */ + +/* Ethernet DMA current host receive buffer address register + * (32-bit address) + */ + +/* DMA Descriptors **********************************************************/ + +/* TDES0: Transmit descriptor Word0 */ + +#define ETH_TDES0_DB (1 << 0) /* Bit 0: Deferred bit */ +#define ETH_TDES0_UF (1 << 1) /* Bit 1: Underflow error */ +#define ETH_TDES0_ED (1 << 2) /* Bit 2: Excessive deferral */ +#define ETH_TDES0_CC_SHIFT (3) /* Bits 3-6: Collision count */ +#define ETH_TDES0_CC_MASK (15 << ETH_TDES0_CC_SHIFT) +#define ETH_TDES0_VF (1 << 7) /* Bit 7: VLAN frame */ +#define ETH_TDES0_EC (1 << 8) /* Bit 8: Excessive collision */ +#define ETH_TDES0_LCO (1 << 9) /* Bit 9: Late collision */ +#define ETH_TDES0_NC (1 << 10) /* Bit 10: No carrier */ +#define ETH_TDES0_LCA (1 << 11) /* Bit 11: Loss of carrier */ +#define ETH_TDES0_IPE (1 << 12) /* Bit 12: IP payload error */ +#define ETH_TDES0_FF (1 << 13) /* Bit 13: Frame flushed */ +#define ETH_TDES0_JT (1 << 14) /* Bit 14: Jabber timeout */ +#define ETH_TDES0_ES (1 << 15) /* Bit 15: Error summary */ +#define ETH_TDES0_IHE (1 << 16) /* Bit 16: IP header error */ +#define ETH_TDES0_TTSS (1 << 17) /* Bit 17: Transmit time stamp status */ +#define ETH_TDES0_TCH (1 << 20) /* Bit 20: Second address chained */ +#define ETH_TDES0_TER (1 << 21) /* Bit 21: Transmit end of ring */ +#define ETH_TDES0_CIC_SHIFT (22) /* Bits 22-23: Checksum insertion control */ +#define ETH_TDES0_CIC_MASK (3 << ETH_TDES0_CIC_SHIFT) +# define ETH_TDES0_CIC_DISABLED (0 << ETH_TDES0_CIC_SHIFT) /* Checksum disabled */ +# define ETH_TDES0_CIC_IH (1 << ETH_TDES0_CIC_SHIFT) /* IP header checksum enabled */ +# define ETH_TDES0_CIC_IHPL (2 << ETH_TDES0_CIC_SHIFT) /* IP header and payload checksum enabled */ +# define ETH_TDES0_CIC_ALL (3 << ETH_TDES0_CIC_SHIFT) /* IP Header, payload, and pseudo-header checksum enabled */ + +#define ETH_TDES0_TTSE (1 << 25) /* Bit 25: Transmit time stamp enable */ +#define ETH_TDES0_DP (1 << 26) /* Bit 26: Disable pad */ +#define ETH_TDES0_DC (1 << 27) /* Bit 27: Disable CRC */ +#define ETH_TDES0_FS (1 << 28) /* Bit 28: First segment */ +#define ETH_TDES0_LS (1 << 29) /* Bit 29: Last segment */ +#define ETH_TDES0_IC (1 << 30) /* Bit 30: Interrupt on completion */ +#define ETH_TDES0_OWN (1 << 31) /* Bit 31: Own bit */ + +/* TDES1: Transmit descriptor Word1 */ + +#define ETH_TDES1_TBS1_SHIFT (0) /* Bits 0-12: Transmit buffer 1 size */ +#define ETH_TDES1_TBS1_MASK (0x1fff << ETH_TDES1_TBS1_SHIFT) +#define ETH_TDES1_TBS2_SHIFT (16) /* Bits 16-28: Transmit buffer 2 size */ +#define ETH_TDES1_TBS2_MASK (0x1fff << ETH_TDES1_TBS2_SHIFT) + +/* TDES2: Transmit descriptor Word2 (32-bit address) */ + +/* TDES3: Transmit descriptor Word3 (32-bit address) */ + +/* RDES0: Receive descriptor Word0 */ + +#define ETH_RDES0_PCE (1 << 0) /* Bit 0: Payload checksum error */ +#define ETH_RDES0_CE (1 << 1) /* Bit 1: CRC error */ +#define ETH_RDES0_DBE (1 << 2) /* Bit 2: Dribble bit error */ +#define ETH_RDES0_RE (1 << 3) /* Bit 3: Receive error */ +#define ETH_RDES0_RWT (1 << 4) /* Bit 4: Receive watchdog timeout */ +#define ETH_RDES0_FT (1 << 5) /* Bit 5: Frame type */ +#define ETH_RDES0_LCO (1 << 6) /* Bit 6: Late collision */ +#define ETH_RDES0_IPHCE (1 << 7) /* Bit 7: IPv header checksum error */ +#define ETH_RDES0_LS (1 << 8) /* Bit 8: Last descriptor */ +#define ETH_RDES0_FS (1 << 9) /* Bit 9: First descriptor */ +#define ETH_RDES0_VLAN (1 << 10) /* Bit 10: VLAN tag */ +#define ETH_RDES0_OE (1 << 11) /* Bit 11: Overflow error */ +#define ETH_RDES0_LE (1 << 12) /* Bit 12: Length error */ +#define ETH_RDES0_SAF (1 << 13) /* Bit 13: Source address filter fail */ +#define ETH_RDES0_DE (1 << 14) /* Bit 14: Descriptor error */ +#define ETH_RDES0_ES (1 << 15) /* Bit 15: Error summary */ +#define ETH_RDES0_FL_SHIFT (16) /* Bits 16-29: Frame length */ +#define ETH_RDES0_FL_MASK (0x3fff << ETH_RDES0_FL_SHIFT) +#define ETH_RDES0_AFM (1 << 30) /* Bit 30: Destination address filter fail */ +#define ETH_RDES0_OWN (1 << 31) /* Bit 31: Own bit */ + +/* RDES1: Receive descriptor Word1 */ + +#define ETH_RDES1_RBS1_SHIFT (0) /* Bits 0-12: Receive buffer 1 size */ +#define ETH_RDES1_RBS1_MASK (0x1fff << ETH_RDES1_RBS1_SHIFT) + /* Bit 13: Reserved */ +#define ETH_RDES1_RCH (1 << 14) /* Bit 14: Second address chained */ +#define ETH_RDES1_RER (1 << 15) /* Bit 15: Receive end of ring */ +#define ETH_RDES1_RBS2_SHIFT (16) /* Bits 16-28: Receive buffer 2 size */ +#define ETH_RDES1_RBS2_MASK (0x1fff << ETH_RDES1_RBS2_SHIFT) +#define ETH_RDES1_DIC (1 << 31) /* Bit 31: Disable interrupt on completion */ + +/* RDES2: Receive descriptor Word2 (32-bit address) */ + +/* RDES3: Receive descriptor Word3 (32-bit address) */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* Ethernet TX DMA Descriptor */ + +struct eth_txdesc_s +{ + /* Normal DMA descriptor words */ + + volatile uint32_t tdes0; /* Status */ + volatile uint32_t tdes1; /* Control and buffer1/2 lengths */ + volatile uint32_t tdes2; /* Buffer1 address pointer */ + volatile uint32_t tdes3; /* Buffer2 or next descriptor address pointer */ +}; + +/* Ethernet RX DMA Descriptor */ + +struct eth_rxdesc_s +{ + volatile uint32_t rdes0; /* Status */ + volatile uint32_t rdes1; /* Control and buffer1/2 lengths */ + volatile uint32_t rdes2; /* Buffer1 address pointer */ + volatile uint32_t rdes3; /* Buffer2 or next descriptor address pointer */ +}; + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#endif /* __ASSEMBLY__ */ +#endif /* AT32_NETHERNET > 0 */ +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_ETH_H */ diff --git a/arch/arm/src/at32/hardware/at32_exti.h b/arch/arm/src/at32/hardware/at32_exti.h new file mode 100644 index 0000000000..49aab8e28c --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_exti.h @@ -0,0 +1,113 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_exti.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_EXTI_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_EXTI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_AT32_AT32F43XX) +# define AT32_NEXTI 23 +# define AT32_EXTI_MASK 0x007fffff +#endif + +#define AT32_EXTI_BIT(n) (1 << (n)) + +/* Register Offsets *********************************************************/ + +#define AT32_EXTI_IMR_OFFSET 0x0000 /* Interrupt mask register */ +#define AT32_EXTI_EMR_OFFSET 0x0004 /* Event mask register */ +#define AT32_EXTI_RTSR_OFFSET 0x0008 /* Rising Trigger selection register */ +#define AT32_EXTI_FTSR_OFFSET 0x000c /* Falling Trigger selection register */ +#define AT32_EXTI_SWIER_OFFSET 0x0010 /* Software interrupt event register */ +#define AT32_EXTI_PR_OFFSET 0x0014 /* Pending register */ + +/* Register Addresses *******************************************************/ + +# define AT32_EXTI_IMR (AT32_EXINT_BASE+AT32_EXTI_IMR_OFFSET) +# define AT32_EXTI_EMR (AT32_EXINT_BASE+AT32_EXTI_EMR_OFFSET) +# define AT32_EXTI_RTSR (AT32_EXINT_BASE+AT32_EXTI_RTSR_OFFSET) +# define AT32_EXTI_FTSR (AT32_EXINT_BASE+AT32_EXTI_FTSR_OFFSET) +# define AT32_EXTI_SWIER (AT32_EXINT_BASE+AT32_EXTI_SWIER_OFFSET) +# define AT32_EXTI_PR (AT32_EXINT_BASE+AT32_EXTI_PR_OFFSET) + +/* Register Bitfield Definitions ********************************************/ + +/* EXTI lines > 15 are associated with internal devices: */ + +#if defined(CONFIG_AT32_AT32F43XX) +# define EXTI_PVD_LINE (1 << 16) /* EXTI line 16 is connected to the PVD output */ +# define EXTI_RTC_ALARM (1 << 17) /* EXTI line 17 is connected to the RTC Alarm event */ +# define EXTI_OTGFS_WAKEUP (1 << 18) /* EXTI line 18 is connected to the USB OTG FS Wakeup event */ +# define EXTI_ETH_WAKEUP (1 << 19) /* EXTI line 19 is connected to the Ethernet Wakeup event */ +# define EXTI_OTGHS_WAKEUP (1 << 20) /* EXTI line 20 is connected to the USB OTG HS Wakeup event */ +# define EXTI_RTC_TAMPER (1 << 21) /* EXTI line 21 is connected to the RTC Tamper and TimeStamp events */ +# define EXTI_RTC_TIMESTAMP (1 << 21) /* EXTI line 21 is connected to the RTC Tamper and TimeStamp events */ +# define EXTI_RTC_WAKEUP (1 << 22) /* EXTI line 22 is connected to the RTC Wakeup event */ +#endif + +/* Interrupt mask register */ + +#define EXTI_IMR_BIT(n) AT32_EXTI_BIT(n) /* 1=Interrupt request from line x is not masked */ +#define EXTI_IMR_SHIFT (0) /* Bits 0-X: Interrupt Mask for all lines */ +#define EXTI_IMR_MASK AT32_EXTI_MASK + +/* Event mask register */ + +#define EXTI_EMR_BIT(n) AT32_EXTI_BIT(n) /* 1=Event request from line x is not mask */ +#define EXTI_EMR_SHIFT (0) /* Bits Bits 0-X: Event Mask for all lines */ +#define EXTI_EMR_MASK AT32_EXTI_MASK + +/* Rising Trigger selection register */ + +#define EXTI_RTSR_BIT(n) AT32_EXTI_BIT(n) /* 1=Rising trigger enabled (for Event and Interrupt) for input line */ +#define EXTI_RTSR_SHIFT (0) /* Bits 0-X: Rising trigger event configuration bit for all lines */ +#define EXTI_RTSR_MASK AT32_EXTI_MASK + +/* Falling Trigger selection register */ + +#define EXTI_FTSR_BIT(n) AT32_EXTI_BIT(n) /* 1=Falling trigger enabled (for Event and Interrupt) for input line */ +#define EXTI_FTSR_SHIFT (0) /* Bits 0-X: Falling trigger event configuration bitfor all lines */ +#define EXTI_FTSR_MASK AT32_EXTI_MASK + +/* Software interrupt event register */ + +#define EXTI_SWIER_BIT(n) AT32_EXTI_BIT(n) /* 1=Sets the corresponding pending bit in EXTI_PR */ +#define EXTI_SWIER_SHIFT (0) /* Bits 0-X: Software Interrupt for all lines */ +#define EXTI_SWIER_MASK AT32_EXTI_MASK + +/* Pending register */ + +#define EXTI_PR_BIT(n) AT32_EXTI_BIT(n) /* 1=Selected trigger request occurred */ +#define EXTI_PR_SHIFT (0) /* Bits 0-X: Pending bit for all lines */ +#define EXTI_PR_MASK AT32_EXTI_MASK + +/* Compatibility Definitions ************************************************/ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_EXTI_H */ \ No newline at end of file diff --git a/arch/arm/src/at32/hardware/at32_flash.h b/arch/arm/src/at32/hardware/at32_flash.h new file mode 100644 index 0000000000..c5cc077948 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_flash.h @@ -0,0 +1,226 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_flash.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_FLASH_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_FLASH_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if !defined(CONFIG_AT32_FLASH_CONFIG_DEFAULT) && \ + !defined(CONFIG_AT32_FLASH_CONFIG_C) && \ + !defined(CONFIG_AT32_FLASH_CONFIG_G) && \ + !defined(CONFIG_AT32_FLASH_CONFIG_M) +# define CONFIG_AT32_FLASH_CONFIG_DEFAULT +#endif + +#if defined(CONFIG_AT32_FLASH_CONFIG_DEFAULT) + +# if defined(CONFIG_AT32_AT32F43XX) +# define AT32_FLASH_NPAGES 512 +# define AT32_FLASH_BANK2_START 256 +# define AT32_FLASH_SIZE (AT32_FLASH_NPAGES * AT32_FLASH_PAGESIZE) +# define AT32_FLASH_PAGESIZE (2 * 1024) +# endif + +#endif /* CONFIG_AT32_FLASH_CONFIG_DEFAULT */ + + /* Override of the Flash Has been Chosen */ + +#if !defined(CONFIG_AT32_FLASH_CONFIG_DEFAULT) + +# if defined(CONFIG_AT32_AT32F43XX) + +# if defined(CONFIG_AT32_FLASH_CONFIG_C) +# define AT32_FLASH_NPAGES 128 +# undef AT32_FLASH_BANK2_START /* there is no bank2 */ +# define AT32_FLASH_SIZE (AT32_FLASH_NPAGES * AT32_FLASH_PAGESIZE) +# define AT32_FLASH_PAGESIZE (2 * 1024) + +# elif defined(CONFIG_AT32_FLASH_CONFIG_G) +# define AT32_FLASH_NPAGES 512 +# define AT32_FLASH_BANK2_START 256 +# define AT32_FLASH_SIZE (AT32_FLASH_NPAGES * AT32_FLASH_PAGESIZE) +# define AT32_FLASH_PAGESIZE (2 * 1024) + +# elif defined(CONFIG_AT32_FLASH_CONFIG_M) +# define AT32_FLASH_NPAGES 1008 +# define AT32_FLASH_BANK2_START 512 +# define AT32_FLASH_PAGESIZE (4 * 1024) +# define AT32_FLASH_SIZE (AT32_FLASH_NPAGES * AT32_FLASH_PAGESIZE) + +# else +# define AT32_FLASH_NPAGES 128 +# undef AT32_FLASH_BANK2_START /* there is no bank2 */ +# define AT32_FLASH_SIZE (AT32_FLASH_NPAGES * AT32_FLASH_PAGESIZE) +# define AT32_FLASH_PAGESIZE (2 * 1024) +# endif + +# endif +#endif /* !defined(CONFIG_AT32_FLASH_CONFIG_DEFAULT) */ + +#if defined(CONFIG_AT32_AT32F43XX) && (AT32_FLASH_NPAGES > 128) +#if (AT32_FLASH_NPAGES > 128) +# define AT32_FLASH_DUAL_BANK 1 +# if defined(CONFIG_AT32_FLASH_CONFIG_G) +# define AT32_FLASH_BANK0_NPAGES 256 +# else +# define AT32_FLASH_BANK0_NPAGES 512 +# endif +# define AT32_FLASH_BANK1_NPAGES (AT32_FLASH_NPAGES - AT32_FLASH_BANK0_NPAGES) +# define AT32_FLASH_BANK0_BASE (AT32_FLASH_BASE) +# define AT32_FLASH_BANK1_BASE \ + (AT32_FLASH_BASE + AT32_FLASH_PAGESIZE * AT32_FLASH_BANK0_NPAGES) +#else +# define AT32_FLASH_BANK0_NPAGES 128 +# define AT32_FLASH_BANK0_BASE (AT32_FLASH_BASE) +#endif +#endif + +/* Register Offsets *********************************************************/ + +#if defined(CONFIG_AT32_AT32F43XX) + +#define AT32_FLASH_PSR_OFFSET 0x00 +#define AT32_FLASH_UNLOCK_OFFSET 0x04 +#define AT32_FLASH_USD_UNLOCK_OFFSET 0x08 +#define AT32_FLASH_STS_OFFSET 0x0C +#define AT32_FLASH_CTRL_OFFSET 0x10 +#define AT32_FLASH_ADDR_OFFSET 0x14 +#define AT32_FLASH_USD_OFFSET 0x1C +#define AT32_FLASH_EPPS0_OFFSET 0x20 +#define AT32_FLASH_EPPS1_OFFSET 0x2C +#define AT32_FLASH_UNLOCK2_OFFSET 0x44 +#define AT32_FLASH_STS2_OFFSET 0x4C +#define AT32_FLASH_CTRL2_OFFSET 0x50 +#define AT32_FLASH_ADDR2_OFFSET 0x54 +#define AT32_FLASH_CONTR_OFFSET 0x58 +#define AT32_FLASH_DIVR_OFFSET 0x60 +#define AT32_SLIB_STS2_OFFSET 0xC8 +#define AT32_SLIB_STS0_OFFSET 0xCC +#define AT32_SLIB_STS1_OFFSET 0xD0 +#define AT32_SLIB_PWD_CRL_OFFSET 0xD4 +#define AT32_SLIB_MISC_STS_OFFSET 0xD8 +#define AT32_SLIB_SET_PWD_OFFSET 0xDC +#define AT32_SLIB_SET_RANGE0_OFFSET 0xE0 +#define AT32_SLIB_SET_RANGE1_OFFSET 0xE4 +#define AT32_SLIB_UNLOCK_OFFSET 0xF0 +#define AT32_FLASH_CRC_CTRL_OFFSET 0xF4 +#define AT32_FLASH_CRC_CHKR_OFFSET 0xF8 +#endif + +/* Register Addresses *******************************************************/ + +#if defined(CONFIG_AT32_AT32F43XX) + +#define AT32_FLASH_PSR (AT32_FLASHIF_BASE+AT32_FLASH_PSR_OFFSET) +#define AT32_FLASH_UNLOCK (AT32_FLASHIF_BASE+AT32_FLASH_UNLOCK_OFFSET) +#define AT32_FLASH_USD_UNLOCK (AT32_FLASHIF_BASE+AT32_FLASH_USD_UNLOCK_OFFSET) +#define AT32_FLASH_STS (AT32_FLASHIF_BASE+AT32_FLASH_STS_OFFSET) +#define AT32_FLASH_CTRL (AT32_FLASHIF_BASE+AT32_FLASH_CTRL_OFFSET) +#define AT32_FLASH_ADDR (AT32_FLASHIF_BASE+AT32_FLASH_ADDR_OFFSET) +#define AT32_FLASH_USD (AT32_FLASHIF_BASE+AT32_FLASH_USD_OFFSET) +#define AT32_FLASH_EPPS0 (AT32_FLASHIF_BASE+AT32_FLASH_EPPS0_OFFSET) +#define AT32_FLASH_EPPS1 (AT32_FLASHIF_BASE+AT32_FLASH_EPPS1_OFFSET) +#define AT32_FLASH_UNLOCK2 (AT32_FLASHIF_BASE+AT32_FLASH_UNLOCK2_OFFSET) +#define AT32_FLASH_STS2 (AT32_FLASHIF_BASE+AT32_FLASH_STS2_OFFSET) +#define AT32_FLASH_CTRL2 (AT32_FLASHIF_BASE+AT32_FLASH_CTRL2_OFFSET) +#define AT32_FLASH_ADDR2 (AT32_FLASHIF_BASE+AT32_FLASH_ADDR2_OFFSET) +#define AT32_FLASH_CONTR (AT32_FLASHIF_BASE+AT32_FLASH_CONTR_OFFSET) +#define AT32_FLASH_DIVR (AT32_FLASHIF_BASE+AT32_FLASH_DIVR_OFFSET) +#define AT32_SLIB_STS2 (AT32_FLASHIF_BASE+AT32_SLIB_STS2_OFFSET) +#define AT32_SLIB_STS0 (AT32_FLASHIF_BASE+AT32_SLIB_STS0_OFFSET) +#define AT32_SLIB_STS1 (AT32_FLASHIF_BASE+AT32_SLIB_STS1_OFFSET) +#define AT32_SLIB_PWD_CRL (AT32_FLASHIF_BASE+AT32_SLIB_PWD_CRL_OFFSET) +#define AT32_SLIB_MISC_STS (AT32_FLASHIF_BASE+AT32_SLIB_MISC_STS_OFFSET) +#define AT32_SLIB_SET_PWD (AT32_FLASHIF_BASE+AT32_SLIB_SET_PWD_OFFSET) +#define AT32_SLIB_SET_RANGE0 (AT32_FLASHIF_BASE+AT32_SLIB_SET_RANGE0_OFFSET) +#define AT32_SLIB_SET_RANGE1 (AT32_FLASHIF_BASE+AT32_SLIB_SET_RANGE1_OFFSET) +#define AT32_SLIB_UNLOCK (AT32_FLASHIF_BASE+AT32_SLIB_UNLOCK_OFFSET) +#define AT32_FLASH_CRC_CTRL (AT32_FLASHIF_BASE+AT32_FLASH_CRC_CTRL_OFFSET) +#define AT32_FLASH_CRC_CHKR (AT32_FLASHIF_BASE+AT32_FLASH_CRC_CHKR_OFFSET) +#endif + +/* Register Bitfield Definitions ********************************************/ + +/* Flash Access Control Register (PSR) */ +#if defined(CONFIG_AT32_AT32F43XX) +#define FLASH_PSR_NZW_BST (1 << 12) /* Flash non-zero wait area boost */ +#define FLASH_PSR_NZW_BST_STS (1 << 13) /* Flash non-zero wait area boost status */ +#endif + +/* Flash status Register1(for bank1) */ +#if defined(CONFIG_AT32_AT32F43XX) +#define FLASH_STS_OBF (1 << 0) /* Operation busy flag */ +#define FLASH_STS_PRGMERR (1 << 2) /* Program error */ +#define FLASH_STS_EPPERR (1 << 4) /* Erase/Program protection error */ +#define FLASH_STS_ODF (1 << 5) /* Operation done flag */ +#endif + +/* Flash control Register(for bank1) */ +#if defined(CONFIG_AT32_AT32F43XX) +#define FLASH_CTRL_FPRGM (1 << 0) /* Flash program */ +#define FLASH_CTRL_SECERS (1 << 1) /* Sector erase */ +#define FLASH_CTRL_BANKERS (1 << 2) /* Bank erase */ +#define FLASH_CTRL_BLKERS (1 << 3) /* Block erase */ +#define FLASH_CTRL_USDPRGM (1 << 4) /* User system data program */ +#define FLASH_CTRL_USDERS (1 << 5) /* User system data erase */ +#define FLASH_CTRL_ERSTR (1 << 6) /* Erasing start */ +#define FLASH_CTRL_OPLK (1 << 7) /* Operation lock */ +#define FLASH_CTRL_USDULKS (1 << 9) /* User system data unlock success */ +#define FLASH_CTRL_ERRIE (1 << 10) /* Error interrupt enable */ +#define FLASH_CTRL_ODFIE (1 << 12) /* Operation done flag interrupt enable */ +#endif + +/* Flash address Register(for bank1) */ + +#define FLASH_ADDR_FA_SHIFT (0) /* Flash address */ +#define FLASH_ADDR_FA_MASK (0xffffffff << FLASH_ADDR_FA_SHIFT) +#define FLASH_ADDR_FA(X) ((X) << FLASH_ADDR_FA_SHIFT) + +/* Flash continue read enable */ + +#define FLASH_CONTR_EN_SHIFT (31) +#define FLASH_CONTR_EN_MASK (1 << FLASH_CONTR_EN_SHIFT) +#define FLASH_CONTR_EN (1 << FLASH_CONTR_EN_SHIFT) + +/* Flash divider */ + +#define FLASH_DIVR_FDIV_SHIFT (0) /* Flash divider */ +#define FLASH_DIVR_FDIV_MASK (3 << FLASH_DIVR_FDIV_SHIFT) +#define FLASH_DIVR_FDIV_2 (0 << FLASH_DIVR_FDIV_SHIFT) +#define FLASH_DIVR_FDIV_3 (1 << FLASH_DIVR_FDIV_SHIFT) +#define FLASH_DIVR_FDIV_4 (2 << FLASH_DIVR_FDIV_SHIFT) + +#define FLASH_DIVR_FDIV_STS_SHIFT (4) /* Flash divider status */ +#define FLASH_DIVR_FDIV_STS_MASK (3 << FLASH_DIVR_FDIV_STS_SHIFT) +#define FLASH_DIVR_FDIV_STS_2 (0 << FLASH_DIVR_FDIV_STS_SHIFT) +#define FLASH_DIVR_FDIV_STS_3 (1 << FLASH_DIVR_FDIV_STS_SHIFT) +#define FLASH_DIVR_FDIV_STS_4 (2 << FLASH_DIVR_FDIV_STS_SHIFT) + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +int at32_flash_lock(void); +int at32_flash_unlock(void); + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_FLASH_H */ diff --git a/arch/arm/src/at32/hardware/at32_i2c.h b/arch/arm/src/at32/hardware/at32_i2c.h new file mode 100644 index 0000000000..00b189e649 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_i2c.h @@ -0,0 +1,237 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_i2c.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_I2C_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_I2C_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define AT32_I2C_CR1_OFFSET 0x0000 /* Control register 1 (32-bit) */ +#define AT32_I2C_CR2_OFFSET 0x0004 /* Control register 2 (32-bit) */ +#define AT32_I2C_OAR1_OFFSET 0x0008 /* Own address register 1 (16-bit) */ +#define AT32_I2C_OAR2_OFFSET 0x000c /* Own address register 2 (16-bit) */ +#define AT32_I2C_TIMINGR_OFFSET 0x0010 /* Timing register */ +#define AT32_I2C_TIMEOUTR_OFFSET 0x0014 /* Timeout register */ +#define AT32_I2C_ISR_OFFSET 0x0018 /* Interrupt and Status register */ +#define AT32_I2C_ICR_OFFSET 0x001c /* Interrupt clear register */ +#define AT32_I2C_PECR_OFFSET 0x0020 /* Packet error checking register */ +#define AT32_I2C_RXDR_OFFSET 0x0024 /* Receive data register */ +#define AT32_I2C_TXDR_OFFSET 0x0028 /* Transmit data register */ + +/* Register Addresses *******************************************************/ + +#if AT32_NI2C > 0 +# define AT32_I2C1_CR1 (AT32_I2C1_BASE+AT32_I2C_CR1_OFFSET) +# define AT32_I2C1_CR2 (AT32_I2C1_BASE+AT32_I2C_CR2_OFFSET) +# define AT32_I2C1_OAR1 (AT32_I2C1_BASE+AT32_I2C_OAR1_OFFSET) +# define AT32_I2C1_OAR2 (AT32_I2C1_BASE+AT32_I2C_OAR2_OFFSET) +# define AT32_I2C1_TIMINGR (AT32_I2C1_BASE+AT32_I2C_TIMINGR_OFFSET) +# define AT32_I2C1_TIMEOUTR (AT32_I2C1_BASE+AT32_I2C_TIMEOUTR_OFFSET) +# define AT32_I2C1_ISR (AT32_I2C1_BASE+AT32_I2C_ISR_OFFSET) +# define AT32_I2C1_ICR (AT32_I2C1_BASE+AT32_I2C_ICR_OFFSET) +# define AT32_I2C1_PECR (AT32_I2C1_BASE+AT32_I2C_PECR_OFFSET) +# define AT32_I2C1_RXDR (AT32_I2C1_BASE+AT32_I2C_RXDR_OFFSET) +# define AT32_I2C1_TXDR (AT32_I2C1_BASE+AT32_I2C_TXDR_OFFSET) +#endif + +#if AT32_NI2C > 1 +# define AT32_I2C2_CR1 (AT32_I2C2_BASE+AT32_I2C_CR1_OFFSET) +# define AT32_I2C2_CR2 (AT32_I2C2_BASE+AT32_I2C_CR2_OFFSET) +# define AT32_I2C2_OAR1 (AT32_I2C2_BASE+AT32_I2C_OAR1_OFFSET) +# define AT32_I2C2_OAR2 (AT32_I2C2_BASE+AT32_I2C_OAR2_OFFSET) +# define AT32_I2C2_TIMINGR (AT32_I2C2_BASE+AT32_I2C_TIMINGR_OFFSET) +# define AT32_I2C2_TIMEOUTR (AT32_I2C2_BASE+AT32_I2C_TIMEOUTR_OFFSET) +# define AT32_I2C2_ISR (AT32_I2C2_BASE+AT32_I2C_ISR_OFFSET) +# define AT32_I2C2_ICR (AT32_I2C2_BASE+AT32_I2C_ICR_OFFSET) +# define AT32_I2C2_PECR (AT32_I2C2_BASE+AT32_I2C_PECR_OFFSET) +# define AT32_I2C2_RXDR (AT32_I2C2_BASE+AT32_I2C_RXDR_OFFSET) +# define AT32_I2C2_TXDR (AT32_I2C2_BASE+AT32_I2C_TXDR_OFFSET) +#endif + +#if AT32_NI2C > 2 +# define AT32_I2C3_CR1 (AT32_I2C3_BASE+AT32_I2C_CR1_OFFSET) +# define AT32_I2C3_CR2 (AT32_I2C3_BASE+AT32_I2C_CR2_OFFSET) +# define AT32_I2C3_OAR1 (AT32_I2C3_BASE+AT32_I2C_OAR1_OFFSET) +# define AT32_I2C3_OAR2 (AT32_I2C3_BASE+AT32_I2C_OAR2_OFFSET) +# define AT32_I2C3_TIMINGR (AT32_I2C3_BASE+AT32_I2C_TIMINGR_OFFSET) +# define AT32_I2C3_TIMEOUTR (AT32_I2C3_BASE+AT32_I2C_TIMEOUTR_OFFSET) +# define AT32_I2C3_ISR (AT32_I2C3_BASE+AT32_I2C_ISR_OFFSET) +# define AT32_I2C3_ICR (AT32_I2C3_BASE+AT32_I2C_ICR_OFFSET) +# define AT32_I2C3_PECR (AT32_I2C3_BASE+AT32_I2C_PECR_OFFSET) +# define AT32_I2C3_RXDR (AT32_I2C3_BASE+AT32_I2C_RXDR_OFFSET) +# define AT32_I2C3_TXDR (AT32_I2C3_BASE+AT32_I2C_TXDR_OFFSET) +#endif + +/* Register Bitfield Definitions ********************************************/ + +/* Control register 1 */ + +#define I2C_CR1_PE (1 << 0) /* Bit 0: Peripheral Enable */ +#define I2C_CR1_TXIE (1 << 1) /* Bit 1: TX Interrupt enable */ +#define I2C_CR1_RXIE (1 << 2) /* Bit 2: RX Interrupt enable */ +#define I2C_CR1_ADDRIE (1 << 3) /* Bit 3: Address match interrupt enable (slave) */ +#define I2C_CR1_NACKIE (1 << 4) /* Bit 4: Not acknowledge received interrupt enable */ +#define I2C_CR1_STOPIE (1 << 5) /* Bit 5: STOP detection interrupt enable */ +#define I2C_CR1_TCIE (1 << 6) /* Bit 6: Transfer Complete interrupt enable */ +#define I2C_CR1_ERRIE (1 << 7) /* Bit 7: Error interrupts enable */ +#define I2C_CR1_DNF_SHIFT (8) /* Bits 8-11: Digital noise filter */ +#define I2C_CR1_DNF_MASK (15 << I2C_CR1_DNF_SHIFT) +# define I2C_CR1_DNF_DISABLE (0 << I2C_CR1_DNF_SHIFT) +# define I2C_CR1_DNF(n) ((n) << I2C_CR1_DNF_SHIFT) /* Up to n * Ti2cclk, n=1..15 */ +#define I2C_CR1_TXDMAEN (1 << 14) /* Bit 14: DMA transmission requests enable */ +#define I2C_CR1_RXDMAEN (1 << 15) /* Bit 15: DMA reception requests enable */ +#define I2C_CR1_SBC (1 << 16) /* Bit 16: Slave byte control */ +#define I2C_CR1_NOSTRETCH (1 << 17) /* Bit 17: Clock stretching disable */ +#define I2C_CR1_GCEN (1 << 19) /* Bit 19: General call enable */ +#define I2C_CR1_SMBHEN (1 << 20) /* Bit 20: SMBus Host address enable */ +#define I2C_CR1_SMBDEN (1 << 21) /* Bit 21: SMBus Device Default address enable */ +#define I2C_CR1_ALERTEN (1 << 22) /* Bit 22: SMBus alert enable */ +#define I2C_CR1_PECEN (1 << 23) /* Bit 23: PEC enable */ + +/* Control register 2 */ + +#define I2C_CR2_SADD10_SHIFT (0) /* Bits 0-9: Slave 10-bit address (master) */ +#define I2C_CR2_SADD10_MASK (0x3ff << I2C_CR2_SADD10_SHIFT) +#define I2C_CR2_SADD7_SHIFT (1) /* Bits 1-7: Slave 7-bit address (master) */ +#define I2C_CR2_SADD7_MASK (0x7f << I2C_CR2_SADD7_SHIFT) +#define I2C_CR2_RD_WRN (1 << 10) /* Bit 10: Transfer direction (master) */ +#define I2C_CR2_ADD10 (1 << 11) /* Bit 11: 10-bit addressing mode (master) */ +#define I2C_CR2_HEAD10R (1 << 12) /* Bit 12: 10-bit address header only read direction (master) */ +#define I2C_CR2_START (1 << 13) /* Bit 13: Start generation */ +#define I2C_CR2_STOP (1 << 14) /* Bit 14: Stop generation (master) */ +#define I2C_CR2_NACK (1 << 15) /* Bit 15: NACK generation (slave) */ +#define I2C_CR2_NBYTES_SHIFT (16) /* Bits 16-23: Number of bytes */ +#define I2C_CR2_NBYTES_MASK (0xff << I2C_CR2_NBYTES_SHIFT) +#define I2C_CR2_RELOAD (1 << 24) /* Bit 24: NBYTES reload mode */ +#define I2C_CR2_AUTOEND (1 << 25) /* Bit 25: Automatic end mode (master) */ +#define I2C_CR2_PECBYTE (1 << 26) /* Bit 26: Packet error checking byte */ + +/* Own address register 1 */ + +#define I2C_OAR1_OA1_10_SHIFT (0) /* Bits 0-9: 10-bit interface address */ +#define I2C_OAR1_OA1_10_MASK (0x3ff << I2C_OAR1_OA1_10_SHIFT) +#define I2C_OAR1_OA1_7_SHIFT (1) /* Bits 1-7: 7-bit interface address */ +#define I2C_OAR1_OA1_7_MASK (0x7f << I2C_OAR1_OA1_7_SHIFT) +#define I2C_OAR1_OA1MODE (1 << 10) /* Bit 10: Own Address 1 10-bit mode */ +#define I2C_OAR1_ONE (1 << 14) /* Bit 14: always keep on in software */ +#define I2C_OAR1_OA1EN (1 << 15) /* Bit 15: Own Address 1 enable */ + +/* Own address register 2 */ + +#define I2C_OAR2_OA2_SHIFT (1) /* Bits 1-7: 7-bit interface address */ +#define I2C_OAR2_OA2_MASK (0x7f << I2C_OAR2_OA2_SHIFT) +#define I2C_OAR2_OA2MSK_SHIFT (8) /* Bits 8-10: Own Address 2 masks */ +#define I2C_OAR2_OA2MSK_MASK (7 << I2C_OAR2_OA2MSK_SHIFT) +# define I2C_OAR2_OA2MSK_NONE (0 << I2C_OAR2_OA2MSK_SHIFT) /* No mask */ +# define I2C_OAR2_OA2MSK_2_7 (1 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7:2] are compared */ +# define I2C_OAR2_OA2MSK_3_7 (2 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7:3] are compared */ +# define I2C_OAR2_OA2MSK_4_7 (3 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7:4] are compared */ +# define I2C_OAR2_OA2MSK_5_7 (4 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7:5] are compared */ +# define I2C_OAR2_OA2MSK_6_7 (5 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7:6] are compared */ +# define I2C_OAR2_OA2MSK_7 (6 << I2C_OAR2_OA2MSK_SHIFT) /* Only OA2[7] is compared */ +# define I2C_OAR2_OA2MSK_ALL (7 << I2C_OAR2_OA2MSK_SHIFT) /* All 7-bit addresses acknowledged */ +#define I2C_OAR2_OA2EN (1 << 15) /* Bit 15: Own Address 2 enable */ + +/* Timing register */ + +#define I2C_TIMINGR_SCLL_SHIFT (0) /* Bits 0-7: SCL low period (master) */ +#define I2C_TIMINGR_SCLL_MASK (0xff << I2C_TIMINGR_SCLL_SHIFT) +# define I2C_TIMINGR_SCLL(n) (((n)-1) << I2C_TIMINGR_SCLL_SHIFT) /* tSCLL = n x tPRESC */ + +#define I2C_TIMINGR_SCLH_SHIFT (8) /* Bits 8-15: SCL high period (master) */ +#define I2C_TIMINGR_SCLH_MASK (0xff << I2C_TIMINGR_SCLH_SHIFT) +# define I2C_TIMINGR_SCLH(n) (((n)-1) << I2C_TIMINGR_SCLH_SHIFT) /* tSCLH = n x tPRESC */ + +#define I2C_TIMINGR_SDADEL_SHIFT (16) /* Bits 16-19: Data hold time */ +#define I2C_TIMINGR_SDADEL_MASK (15 << I2C_TIMINGR_SDADEL_SHIFT) +# define I2C_TIMINGR_SDADEL(n) ((n) << I2C_TIMINGR_SDADEL_SHIFT) /* tSDADEL= n x tPRESC */ + +#define I2C_TIMINGR_SCLDEL_SHIFT (20) /* Bits 20-23: Data setup time */ +#define I2C_TIMINGR_SCLDEL_MASK (15 << I2C_TIMINGR_SCLDEL_SHIFT) +# define I2C_TIMINGR_SCLDEL(n) (((n)-1) << I2C_TIMINGR_SCLDEL_SHIFT) /* tSCLDEL = n x tPRESC */ + +#define I2C_TIMINGR_PRESCH_SHIFT (24) /* Bits 24-27: Timing prescaler High*/ +#define I2C_TIMINGR_PRESCH_MASK (15 << I2C_TIMINGR_PRESCH_SHIFT) +# define I2C_TIMINGR_PRESCH(n) (((n)-1) << I2C_TIMINGR_PRESCH_SHIFT) /* tPRESC = n x tI2CCLK */ + +#define I2C_TIMINGR_PRESC_SHIFT (28) /* Bits 28-31: Timing prescaler Low*/ +#define I2C_TIMINGR_PRESC_MASK (15 << I2C_TIMINGR_PRESC_SHIFT) +# define I2C_TIMINGR_PRESC(n) (((n)-1) << I2C_TIMINGR_PRESC_SHIFT) /* tPRESC = n x tI2CCLK */ + +/* Timeout register */ + +#define I2C_TIMEOUTR_A_SHIFT (0) /* Bits 0-11: Bus Timeout A */ +#define I2C_TIMEOUTR_A_MASK (0x0fff << I2C_TIMEOUTR_A_SHIFT) +# define I2C_TIMEOUTR_A(n) ((n) << I2C_TIMEOUTR_A_SHIFT) +#define I2C_TIMEOUTR_TIDLE (1 << 12) /* Bit 12: Idle clock timeout detection */ +#define I2C_TIMEOUTR_TIMOUTEN (1 << 15) /* Bit 15: Clock timeout enable */ +#define I2C_TIMEOUTR_B_SHIFT (16) /* Bits 16-27: Bus Timeout B */ +#define I2C_TIMEOUTR_B_MASK (0x0fff << I2C_TIMEOUTR_B_SHIFT) +# define I2C_TIMEOUTR_B(n) ((n) << I2C_TIMEOUTR_B_SHIFT) +#define I2C_TIMEOUTR_TEXTEN (1 << 31) /* Bits 31: Extended clock timeout enable */ + +/* Interrupt and Status register and interrupt clear register */ + +/* Common interrupt bits */ + +#define I2C_INT_ADDR (1 << 3) /* Bit 3: Address matched (slave) */ +#define I2C_INT_NACK (1 << 4) /* Bit 4: Not Acknowledge received flag */ +#define I2C_INT_STOP (1 << 5) /* Bit 5: Stop detection flag */ +#define I2C_INT_BERR (1 << 8) /* Bit 8: Bus error */ +#define I2C_INT_ARLO (1 << 9) /* Bit 9: Arbitration lost */ +#define I2C_INT_OVR (1 << 10) /* Bit 10: Overrun/Underrun (slave) */ +#define I2C_INT_PECERR (1 << 11) /* Bit 11: PEC Error in reception */ +#define I2C_INT_TIMEOUT (1 << 12) /* Bit 12: Timeout or tLOW detection flag */ +#define I2C_INT_ALERT (1 << 13) /* Bit 13: SMBus alert */ + +/* Fields unique to the Interrupt and Status register */ + +#define I2C_ISR_TXE (1 << 0) /* Bit 0: Transmit data register empty (transmitters) */ +#define I2C_ISR_TXIS (1 << 1) /* Bit 1: Transmit interrupt status (transmitters) */ +#define I2C_ISR_RXNE (1 << 2) /* Bit 2: Receive data register not empty (receivers) */ +#define I2C_ISR_TC (1 << 6) /* Bit 6: Transfer Complete (master) */ +#define I2C_ISR_TCR (1 << 7) /* Bit 7: Transfer Complete Reload */ +#define I2C_ISR_BUSY (1 << 15) /* Bit 15: Bus busy */ +#define I2C_ISR_DIR (1 << 16) /* Bit 16: Transfer direction (slave) */ +#define I2C_ISR_ADDCODE_SHIFT (17) /* Bits 17-23: Address match code (slave) */ +#define I2C_ISR_ADDCODE_MASK (0x7f << I2C_ISR_ADDCODE_SHIFT) + +#define I2C_ISR_ERRORMASK (I2C_INT_BERR | I2C_INT_ARLO | I2C_INT_OVR | I2C_INT_PECERR | I2C_INT_TIMEOUT) + +#define I2C_ICR_CLEARMASK (I2C_INT_ADDR | I2C_INT_NACK | I2C_INT_STOP | I2C_INT_BERR | I2C_INT_ARLO \ + | I2C_INT_OVR | I2C_INT_PECERR | I2C_INT_TIMEOUT | I2C_INT_ALERT) + +/* Packet error checking register */ + +#define I2C_PECR_MASK (0xff) + +/* Receive data register */ + +#define I2C_RXDR_MASK (0xff) + +/* Transmit data register */ + +#define I2C_TXDR_MASK (0xff) + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_I2C_H */ diff --git a/arch/arm/src/at32/hardware/at32_memorymap.h b/arch/arm/src/at32/hardware/at32_memorymap.h new file mode 100644 index 0000000000..a9e1fdb28b --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_memorymap.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_memorymap.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_MEMORYMAP_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_MEMORYMAP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip.h" + +#if defined(CONFIG_AT32_AT32F43XX) +# include "hardware/at32f43xxx_memorymap.h" +#else +# error "Unsupported AT32 memory map" +#endif + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_MEMORYMAP_H */ diff --git a/arch/arm/src/at32/hardware/at32_pinmap.h b/arch/arm/src/at32/hardware/at32_pinmap.h new file mode 100644 index 0000000000..bbc2a91429 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_pinmap.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_pinmap.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_PINMAP_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_PINMAP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_AT32_AT32F43XX) +# include "hardware/at32f43xxx_pinmap.h" +#else +# error "No pinmap file for this AT32 chip" +#endif + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_PINMAP_H */ diff --git a/arch/arm/src/at32/hardware/at32_pwr.h b/arch/arm/src/at32/hardware/at32_pwr.h new file mode 100644 index 0000000000..641d9223a2 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_pwr.h @@ -0,0 +1,87 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_pwr.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_PWR_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_PWR_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define AT32_PWC_CTRL_OFFSET 0x0000 /* Power control register */ +#define AT32_PWC_CTRLSTS_OFFSET 0x0004 /* Power control/status register */ +#define AT32_PWC_LDOOV_OFFSET 0x0010 /* Ldo output voltage select */ + +/* Register Addresses *******************************************************/ + +#define AT32_PWC_CTRL (AT32_PWC_BASE+AT32_PWC_CTRL_OFFSET) +#define AT32_PWC_CTRLSTS (AT32_PWC_BASE+AT32_PWC_CTRLSTS_OFFSET) +#define AT32_PWC_LDOOV (AT32_PWC_BASE+AT32_PWC_LDOOV_OFFSET) + +/* Register Bitfield Definitions ********************************************/ + +/* Power control register */ + +#define PWC_CTRL_VRSEL (1 << 0) /* Voltage regulator state select when deepsleep mode */ +#define PWC_CTRL_LPSEL (1 << 1) /* Low power mode select when Cortexâ„¢-M4F sleepdeep*/ +#define PWC_CTRL_CLSWEF (1 << 2) /* Clear SWEF flag */ +#define PWC_CTRL_CLSEF (1 << 3) /* Clear SEF flag */ +#define PWC_CTRL_PVMEN (1 << 4) /* Power voltage monitoring enable */ + +#define PWC_CTRL_PVMSEL_SHIFT (5) /* Bits 7-5: PVD Level Selection */ +#define PWC_CTRL_PVMSEL_MASK (7 << PWC_CTRL_PVMSEL_SHIFT) /* Power voltage monitoring boundary select */ +# define PWC_CTRL_None (0 << PWC_CTRL_PVMSEL_SHIFT) /* 000: None */ +# define PWC_CTRL_2p3V (1 << PWC_CTRL_PVMSEL_SHIFT) /* 001: 2.3V */ +# define PWC_CTRL_2p4V (2 << PWC_CTRL_PVMSEL_SHIFT) /* 010: 2.4V */ +# define PWC_CTRL_2p5V (3 << PWC_CTRL_PVMSEL_SHIFT) /* 011: 2.5V */ +# define PWC_CTRL_2p6V (4 << PWC_CTRL_PVMSEL_SHIFT) /* 100: 2.6V */ +# define PWC_CTRL_2p7V (5 << PWC_CTRL_PVMSEL_SHIFT) /* 101: 2.7V */ +# define PWC_CTRL_2p8V (6 << PWC_CTRL_PVMSEL_SHIFT) /* 110: 2.8V */ +# define PWC_CTRL_2p9V (7 << PWC_CTRL_PVMSEL_SHIFT) /* 111: 2.9V */ + +#define PWC_CTRL_BPWEN (1 << 8) /* Battery powered domain write enable */ + +/* Power control/status register */ + +#define PWC_CTRLSTS_SWEF (1 << 0) /* Standby wake-up event flag */ +#define PWC_CTRLSTS_SEF (1 << 1) /* Standby mode entry flag */ +#define PWC_CTRLSTS_PVMOF (1 << 2) /* Power voltage monitoring output flag */ +#define PWC_CTRLSTS_SWPEN1 (1 << 8) /* Standby wake-up pin1 enable */ +#define PWC_CTRLSTS_SWPEN2 (1 << 9) /* Standby wake-up pin2 enable */ + +/* Power ldo output register */ + +#define PWC_LDOOV_SEL_SHIFT (0) +#define PWC_LDOOV_SEL_MASK (7 << PWC_LDOOV_SEL_SHIFT) /* LDO output voltage select*/ +# define PWC_LDOOV_1V0 (5 << PWC_LDOOV_SEL_SHIFT) /* 1.0V */ +# define PWC_LDOOV_1V1 (4 << PWC_LDOOV_SEL_SHIFT) /* 1.1V */ +# define PWC_LDOOV_1V3 (1 << PWC_LDOOV_SEL_SHIFT) /* 1.3V */ +# define PWC_LDOOV_1V2 (0 << PWC_LDOOV_SEL_SHIFT) /* 1.2V */ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_PWR_H */ \ No newline at end of file diff --git a/arch/arm/src/at32/hardware/at32_rtcc.h b/arch/arm/src/at32/hardware/at32_rtcc.h new file mode 100644 index 0000000000..7093e3ad2e --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_rtcc.h @@ -0,0 +1,365 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_rtcc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_RTCC_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_RTCC_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define AT32_RTC_TR_OFFSET 0x0000 /* RTC time register */ +#define AT32_RTC_DR_OFFSET 0x0004 /* RTC date register */ +#define AT32_RTC_CR_OFFSET 0x0008 /* RTC control register */ +#define AT32_RTC_ISR_OFFSET 0x000c /* RTC initialization and status register */ +#define AT32_RTC_PRER_OFFSET 0x0010 /* RTC prescaler register */ +#define AT32_RTC_WUTR_OFFSET 0x0014 /* RTC wakeup timer register */ +#define AT32_RTC_CALIBR_OFFSET 0x0018 /* RTC calibration register */ +#define AT32_RTC_ALRMAR_OFFSET 0x001c /* RTC alarm A register */ +#define AT32_RTC_ALRMBR_OFFSET 0x0020 /* RTC alarm B register */ +#define AT32_RTC_WPR_OFFSET 0x0024 /* RTC write protection register */ +#define AT32_RTC_SSR_OFFSET 0x0028 /* RTC sub second register */ +#define AT32_RTC_SHIFTR_OFFSET 0x002c /* RTC shift control register */ +#define AT32_RTC_TSTR_OFFSET 0x0030 /* RTC time stamp time register */ +#define AT32_RTC_TSDR_OFFSET 0x0034 /* RTC time stamp date register */ +#define AT32_RTC_TSSSR_OFFSET 0x0038 /* RTC timestamp sub second register */ +#define AT32_RTC_CALR_OFFSET 0x003c /* RTC calibration register */ +#define AT32_RTC_TAFCR_OFFSET 0x0040 /* RTC tamper and alternate function configuration register */ +#define AT32_RTC_ALRMASSR_OFFSET 0x0044 /* RTC alarm A sub second register */ +#define AT32_RTC_ALRMBSSR_OFFSET 0x0048 /* RTC alarm B sub second register */ + +#define AT32_RTC_BKR_OFFSET(n) (0x0050+((n)<<2)) +#define AT32_RTC_BK0R_OFFSET 0x0050 /* RTC backup register 0 */ +#define AT32_RTC_BK1R_OFFSET 0x0054 /* RTC backup register 1 */ +#define AT32_RTC_BK2R_OFFSET 0x0058 /* RTC backup register 2 */ +#define AT32_RTC_BK3R_OFFSET 0x005c /* RTC backup register 3 */ +#define AT32_RTC_BK4R_OFFSET 0x0060 /* RTC backup register 4 */ +#define AT32_RTC_BK5R_OFFSET 0x0064 /* RTC backup register 5 */ +#define AT32_RTC_BK6R_OFFSET 0x0068 /* RTC backup register 6 */ +#define AT32_RTC_BK7R_OFFSET 0x006c /* RTC backup register 7 */ +#define AT32_RTC_BK8R_OFFSET 0x0070 /* RTC backup register 8 */ +#define AT32_RTC_BK9R_OFFSET 0x0074 /* RTC backup register 9 */ +#define AT32_RTC_BK10R_OFFSET 0x0078 /* RTC backup register 10 */ +#define AT32_RTC_BK11R_OFFSET 0x007c /* RTC backup register 11 */ +#define AT32_RTC_BK12R_OFFSET 0x0080 /* RTC backup register 12 */ +#define AT32_RTC_BK13R_OFFSET 0x0084 /* RTC backup register 13 */ +#define AT32_RTC_BK14R_OFFSET 0x0088 /* RTC backup register 14 */ +#define AT32_RTC_BK15R_OFFSET 0x008c /* RTC backup register 15 */ + +#define AT32_RTC_BK16R_OFFSET 0x0090 /* RTC backup register 16 */ +#define AT32_RTC_BK17R_OFFSET 0x0094 /* RTC backup register 17 */ +#define AT32_RTC_BK18R_OFFSET 0x0098 /* RTC backup register 18 */ +#define AT32_RTC_BK19R_OFFSET 0x009c /* RTC backup register 19 */ + +/* Register Addresses *******************************************************/ + +#define AT32_RTC_TR (AT32_ERTC_BASE+AT32_RTC_TR_OFFSET) +#define AT32_RTC_DR (AT32_ERTC_BASE+AT32_RTC_DR_OFFSET) +#define AT32_RTC_CR (AT32_ERTC_BASE+AT32_RTC_CR_OFFSET) +#define AT32_RTC_ISR (AT32_ERTC_BASE+AT32_RTC_ISR_OFFSET) +#define AT32_RTC_PRER (AT32_ERTC_BASE+AT32_RTC_PRER_OFFSET) +#define AT32_RTC_WUTR (AT32_ERTC_BASE+AT32_RTC_WUTR_OFFSET) +#define AT32_RTC_CALIBR (AT32_ERTC_BASE+AT32_RTC_CALIBR_OFFSET) + +#define AT32_RTC_ALRMAR (AT32_ERTC_BASE+AT32_RTC_ALRMAR_OFFSET) +#define AT32_RTC_ALRMBR (AT32_ERTC_BASE+AT32_RTC_ALRMBR_OFFSET) +#define AT32_RTC_WPR (AT32_ERTC_BASE+AT32_RTC_WPR_OFFSET) +#define AT32_RTC_SSR (AT32_ERTC_BASE+AT32_RTC_SSR_OFFSET) +#define AT32_RTC_SHIFTR (AT32_ERTC_BASE+AT32_RTC_SHIFTR_OFFSET) +#define AT32_RTC_TSTR (AT32_ERTC_BASE+AT32_RTC_TSTR_OFFSET) +#define AT32_RTC_TSDR (AT32_ERTC_BASE+AT32_RTC_TSDR_OFFSET) +#define AT32_RTC_TSSSR (AT32_ERTC_BASE+AT32_RTC_TSSSR_OFFSET) +#define AT32_RTC_CALR (AT32_ERTC_BASE+AT32_RTC_CALR_OFFSET) +#define AT32_RTC_TAFCR (AT32_ERTC_BASE+AT32_RTC_TAFCR_OFFSET) +#define AT32_RTC_ALRMASSR (AT32_ERTC_BASE+AT32_RTC_ALRMASSR_OFFSET) +#define AT32_RTC_ALRMBSSR (AT32_ERTC_BASE+AT32_RTC_ALRMBSSR_OFFSET) + +#define AT32_RTC_BKR(n) (AT32_ERTC_BASE+AT32_RTC_BKR_OFFSET(n)) +#define AT32_RTC_BK0R (AT32_ERTC_BASE+AT32_RTC_BK0R_OFFSET) +#define AT32_RTC_BK1R (AT32_ERTC_BASE+AT32_RTC_BK1R_OFFSET) +#define AT32_RTC_BK2R (AT32_ERTC_BASE+AT32_RTC_BK2R_OFFSET) +#define AT32_RTC_BK3R (AT32_ERTC_BASE+AT32_RTC_BK3R_OFFSET) +#define AT32_RTC_BK4R (AT32_ERTC_BASE+AT32_RTC_BK4R_OFFSET) +#define AT32_RTC_BK5R (AT32_ERTC_BASE+AT32_RTC_BK5R_OFFSET) +#define AT32_RTC_BK6R (AT32_ERTC_BASE+AT32_RTC_BK6R_OFFSET) +#define AT32_RTC_BK7R (AT32_ERTC_BASE+AT32_RTC_BK7R_OFFSET) +#define AT32_RTC_BK8R (AT32_ERTC_BASE+AT32_RTC_BK8R_OFFSET) +#define AT32_RTC_BK9R (AT32_ERTC_BASE+AT32_RTC_BK9R_OFFSET) +#define AT32_RTC_BK10R (AT32_ERTC_BASE+AT32_RTC_BK10R_OFFSET) +#define AT32_RTC_BK11R (AT32_ERTC_BASE+AT32_RTC_BK11R_OFFSET) +#define AT32_RTC_BK12R (AT32_ERTC_BASE+AT32_RTC_BK12R_OFFSET) +#define AT32_RTC_BK13R (AT32_ERTC_BASE+AT32_RTC_BK13R_OFFSET) +#define AT32_RTC_BK14R (AT32_ERTC_BASE+AT32_RTC_BK14R_OFFSET) +#define AT32_RTC_BK15R (AT32_ERTC_BASE+AT32_RTC_BK15R_OFFSET) + +#define AT32_RTC_BK16R (AT32_ERTC_BASE+AT32_RTC_BK16R_OFFSET) +#define AT32_RTC_BK17R (AT32_ERTC_BASE+AT32_RTC_BK17R_OFFSET) +#define AT32_RTC_BK18R (AT32_ERTC_BASE+AT32_RTC_BK18R_OFFSET) +#define AT32_RTC_BK19R (AT32_ERTC_BASE+AT32_RTC_BK19R_OFFSET) + +#define AT32_RTC_BKCOUNT 20 + +/* Register Bitfield Definitions ********************************************/ + +/* RTC time register */ + +#define RTC_TR_SU_SHIFT (0) /* Bits 0-3: Second units in BCD format */ +#define RTC_TR_SU_MASK (15 << RTC_TR_SU_SHIFT) +#define RTC_TR_ST_SHIFT (4) /* Bits 4-6: Second tens in BCD format */ +#define RTC_TR_ST_MASK (7 << RTC_TR_ST_SHIFT) +#define RTC_TR_MNU_SHIFT (8) /* Bit 8-11: Minute units in BCD format */ +#define RTC_TR_MNU_MASK (15 << RTC_TR_MNU_SHIFT) +#define RTC_TR_MNT_SHIFT (12) /* Bits 12-14: Minute tens in BCD format */ +#define RTC_TR_MNT_MASK (7 << RTC_TR_MNT_SHIFT) +#define RTC_TR_HU_SHIFT (16) /* Bit 16-19: Hour units in BCD format */ +#define RTC_TR_HU_MASK (15 << RTC_TR_HU_SHIFT) +#define RTC_TR_HT_SHIFT (20) /* Bits 20-21: Hour tens in BCD format */ +#define RTC_TR_HT_MASK (3 << RTC_TR_HT_SHIFT) +#define RTC_TR_PM (1 << 22) /* Bit 22: AM/PM notation */ +#define RTC_TR_RESERVED_BITS (0xff808080) + +/* RTC date register */ + +#define RTC_DR_DU_SHIFT (0) /* Bits 0-3: Date units in BCD format */ +#define RTC_DR_DU_MASK (15 << RTC_DR_DU_SHIFT) +#define RTC_DR_DT_SHIFT (4) /* Bits 4-5: Date tens in BCD format */ +#define RTC_DR_DT_MASK (3 << RTC_DR_DT_SHIFT) +#define RTC_DR_MU_SHIFT (8) /* Bits 8-11: Month units in BCD format */ +#define RTC_DR_MU_MASK (15 << RTC_DR_MU_SHIFT) +#define RTC_DR_MT (1 << 12) /* Bit 12: Month tens in BCD format */ +#define RTC_DR_WDU_SHIFT (13) /* Bits 13-15: Week day units */ +#define RTC_DR_WDU_MASK (7 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_MONDAY (1 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_TUESDAY (2 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_WEDNESDAY (3 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_THURSDAY (4 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_FRIDAY (5 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_SATURDAY (6 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_SUNDAY (7 << RTC_DR_WDU_SHIFT) +#define RTC_DR_YU_SHIFT (16) /* Bits 16-19: Year units in BCD format */ +#define RTC_DR_YU_MASK (15 << RTC_DR_YU_SHIFT) +#define RTC_DR_YT_SHIFT (20) /* Bits 20-23: Year tens in BCD format */ +#define RTC_DR_YT_MASK (15 << RTC_DR_YT_SHIFT) +#define RTC_DR_RESERVED_BITS (0xff0000c0) + +/* RTC control register */ + +#define RTC_CR_WUCKSEL_SHIFT (0) /* Bits 0-2: Wakeup clock selection */ +#define RTC_CR_WUCKSEL_MASK (7 << RTC_CR_WUCKSEL_SHIFT) +# define RTC_CR_WUCKSEL_RTCDIV16 (0 << RTC_CR_WUCKSEL_SHIFT) /* 000: RTC/16 clock is selected */ +# define RTC_CR_WUCKSEL_RTCDIV8 (1 << RTC_CR_WUCKSEL_SHIFT) /* 001: RTC/8 clock is selected */ +# define RTC_CR_WUCKSEL_RTCDIV4 (2 << RTC_CR_WUCKSEL_SHIFT) /* 010: RTC/4 clock is selected */ +# define RTC_CR_WUCKSEL_RTCDIV2 (3 << RTC_CR_WUCKSEL_SHIFT) /* 011: RTC/2 clock is selected */ +# define RTC_CR_WUCKSEL_CKSPRE (4 << RTC_CR_WUCKSEL_SHIFT) /* 10x: ck_spre clock is selected */ +# define RTC_CR_WUCKSEL_CKSPREADD (6 << RTC_CR_WUCKSEL_SHIFT) /* 11x: ck_spr clock and 216 added WUT counter */ + +#define RTC_CR_TSEDGE (1 << 3) /* Bit 3: Timestamp event active edge */ +#define RTC_CR_REFCKON (1 << 4) /* Bit 4: Reference clock detection enable (50 or 60 Hz) */ +#define RTC_CR_BYPSHAD (1 << 5) /* Bit 5: Bypass the shadow registers */ +#define RTC_CR_FMT (1 << 6) /* Bit 6: Hour format */ +#define RTC_CR_DCE (1 << 7) /* Bit 7: Coarse digital calibration enable */ +#define RTC_CR_ALRAE (1 << 8) /* Bit 8: Alarm A enable */ +#define RTC_CR_ALRBE (1 << 9) /* Bit 9: Alarm B enable */ +#define RTC_CR_WUTE (1 << 10) /* Bit 10: Wakeup timer enable */ +#define RTC_CR_TSE (1 << 11) /* Bit 11: Time stamp enable */ +#define RTC_CR_ALRAIE (1 << 12) /* Bit 12: Alarm A interrupt enable */ +#define RTC_CR_ALRBIE (1 << 13) /* Bit 13: Alarm B interrupt enable */ +#define RTC_CR_WUTIE (1 << 14) /* Bit 14: Wakeup timer interrupt enable */ +#define RTC_CR_TSIE (1 << 15) /* Bit 15: Timestamp interrupt enable */ +#define RTC_CR_ADD1H (1 << 16) /* Bit 16: Add 1 hour (summer time change) */ +#define RTC_CR_SUB1H (1 << 17) /* Bit 17: Subtract 1 hour (winter time change) */ +#define RTC_CR_BKP (1 << 18) /* Bit 18: Backup */ +#define RTC_CR_COSEL (1 << 19) /* Bit 19: Calibration output selection */ +#define RTC_CR_POL (1 << 20) /* Bit 20: Output polarity */ +#define RTC_CR_OSEL_SHIFT (21) /* Bits 21-22: Output selection */ +#define RTC_CR_OSEL_MASK (3 << RTC_CR_OSEL_SHIFT) +# define RTC_CR_OSEL_DISABLED (0 << RTC_CR_OSEL_SHIFT) /* 00: Output disabled */ +# define RTC_CR_OSEL_ALRMA (1 << RTC_CR_OSEL_SHIFT) /* 01: Alarm A output enabled */ +# define RTC_CR_OSEL_ALRMB (2 << RTC_CR_OSEL_SHIFT) /* 10: Alarm B output enabled */ +# define RTC_CR_OSEL_WUT (3 << RTC_CR_OSEL_SHIFT) /* 11: Wakeup output enabled */ + +#define RTC_CR_COE (1 << 23) /* Bit 23: Calibration output enable */ + +/* RTC initialization and status register */ + +#define RTC_ISR_ALRAWF (1 << 0) /* Bit 0: Alarm A write flag */ +#define RTC_ISR_ALRBWF (1 << 1) /* Bit 1: Alarm B write flag */ +#define RTC_ISR_WUTWF (1 << 2) /* Bit 2: Wakeup timer write flag */ +#define RTC_ISR_SHPF (1 << 3) /* Bit 3: Shift operation pending */ +#define RTC_ISR_INITS (1 << 4) /* Bit 4: Initialization status flag */ +#define RTC_ISR_RSF (1 << 5) /* Bit 5: Registers synchronization flag */ +#define RTC_ISR_INITF (1 << 6) /* Bit 6: Initialization flag */ +#define RTC_ISR_INIT (1 << 7) /* Bit 7: Initialization mode */ +#define RTC_ISR_ALRAF (1 << 8) /* Bit 8: Alarm A flag */ +#define RTC_ISR_ALRBF (1 << 9) /* Bit 9: Alarm B flag */ +#define RTC_ISR_WUTF (1 << 10) /* Bit 10: Wakeup timer flag */ +#define RTC_ISR_TSF (1 << 11) /* Bit 11: Timestamp flag */ +#define RTC_ISR_TSOVF (1 << 12) /* Bit 12: Timestamp overflow flag */ +#define RTC_ISR_TAMP1F (1 << 13) /* Bit 13: Tamper detection flag */ +#define RTC_ISR_TAMP2F (1 << 14) /* Bit 14: TAMPER2 detection flag */ + +#define RTC_ISR_RECALPF (1 << 16) /* Bit 16: Recalibration pending flag */ +#define RTC_ISR_ALLFLAGS (0x00017fff) + +/* RTC prescaler register */ + +#define RTC_PRER_PREDIV_S_SHIFT (0) /* Bits 0-14: Synchronous prescaler factor */ +#define RTC_PRER_PREDIV_S_MASK (0x7fff << RTC_PRER_PREDIV_S_SHIFT) +#define RTC_PRER_PREDIV_A_SHIFT (16) /* Bits 16-22: Asynchronous prescaler factor */ +#define RTC_PRER_PREDIV_A_MASK (0x7f << RTC_PRER_PREDIV_A_SHIFT) + +/* RTC wakeup timer register */ + +#define RTC_WUTR_MASK (0xffff) /* Bits 15:0 Wakeup auto-reload value bits */ + +/* RTC calibration register */ + +#ifndef CONFIG_AT32_AT32F30XX +# define RTC_CALIBR_DCS (1 << 7) /* Bit 7 Digital calibration sign */ +# define RTC_CALIBR_DC_SHIFT (0) /* Bits 4:0 0-4: Digital calibration */ +# define RTC_CALIBR_DC_MASK (31 << RTC_CALIBR_DC_SHIFT) +# define RTC_CALIBR_DC(n) (((n) >> 2) << RTC_CALIBR_DC_SHIFT) /* n= 0, 4, 8, ... 126 */ +#endif + +/* RTC alarm A/B registers */ + +#define RTC_ALRMR_SU_SHIFT (0) /* Bits 0-3: Second units in BCD format. */ +#define RTC_ALRMR_SU_MASK (15 << RTC_ALRMR_SU_SHIFT) +#define RTC_ALRMR_ST_SHIFT (4) /* Bits 4-6: Second tens in BCD format. */ +#define RTC_ALRMR_ST_MASK (7 << RTC_ALRMR_ST_SHIFT) +#define RTC_ALRMR_MSK1 (1 << 7) /* Bit 7 : Alarm A seconds mask */ +#define RTC_ALRMR_MNU_SHIFT (8) /* Bits 8-11: Minute units in BCD format. */ +#define RTC_ALRMR_MNU_MASK (15 << RTC_ALRMR_MNU_SHIFT) +#define RTC_ALRMR_MNT_SHIFT (12) /* Bits 12-14: Minute tens in BCD format. */ +#define RTC_ALRMR_MNT_MASK (7 << RTC_ALRMR_MNT_SHIFT) +#define RTC_ALRMR_MSK2 (1 << 15) /* Bit 15 : Alarm A minutes mask */ +#define RTC_ALRMR_HU_SHIFT (16) /* Bits 16-19: Hour units in BCD format. */ +#define RTC_ALRMR_HU_MASK (15 << RTC_ALRMR_HU_SHIFT) +#define RTC_ALRMR_HT_SHIFT (20) /* Bits 20-21: Hour tens in BCD format. */ +#define RTC_ALRMR_HT_MASK (3 << RTC_ALRMR_HT_SHIFT) +#define RTC_ALRMR_PM (1 << 22) /* Bit 22 : AM/PM notation */ +#define RTC_ALRMR_MSK3 (1 << 23) /* Bit 23 : Alarm A hours mask */ +#define RTC_ALRMR_DU_SHIFT (24) /* Bits 24-27: Date units or day in BCD format. */ +#define RTC_ALRMR_DU_MASK (15 << RTC_ALRMR_DU_SHIFT) +#define RTC_ALRMR_DT_SHIFT (28) /* Bits 28-29: Date tens in BCD format. */ +#define RTC_ALRMR_DT_MASK (3 << RTC_ALRMR_DT_SHIFT) +#define RTC_ALRMR_WDSEL (1 << 30) /* Bit 30: Week day selection */ +#define RTC_ALRMR_MSK4 (1 << 31) /* Bit 31: Alarm A date mask */ + +/* RTC write protection register */ + +#define RTC_WPR_MASK (0xff) /* Bits 0-7: Write protection key */ + +/* RTC sub second register */ + +#define RTC_SSR_MASK (0xffff) /* Bits 0-15: Sub second value */ + +/* RTC shift control register */ + +#define RTC_SHIFTR_SUBFS_SHIFT (0) /* Bits 0-14: Subtract a fraction of a second */ +#define RTC_SHIFTR_SUBFS_MASK (0x7fff << RTC_SHIFTR_SUBFS_SHIFT) +#define RTC_SHIFTR_ADD1S (1 << 31) /* Bit 31: Add one second */ + +/* RTC time stamp time register */ + +#define RTC_TSTR_SU_SHIFT (0) /* Bits 0-3: Second units in BCD format. */ +#define RTC_TSTR_SU_MASK (15 << RTC_TSTR_SU_SHIFT) +#define RTC_TSTR_ST_SHIFT (4) /* Bits 4-6: Second tens in BCD format. */ +#define RTC_TSTR_ST_MASK (7 << RTC_TSTR_ST_SHIFT) +#define RTC_TSTR_MNU_SHIFT (8) /* Bits 8-11: Minute units in BCD format. */ +#define RTC_TSTR_MNU_MASK (15 << RTC_TSTR_MNU_SHIFT) +#define RTC_TSTR_MNT_SHIFT (12) /* Bits 12-14: Minute tens in BCD format. */ +#define RTC_TSTR_MNT_MASK (7 << RTC_TSTR_MNT_SHIFT) +#define RTC_TSTR_HU_SHIFT (16) /* Bits 16-19: Hour units in BCD format. */ +#define RTC_TSTR_HU_MASK (15 << RTC_TSTR_HU_SHIFT) +#define RTC_TSTR_HT_SHIFT (20) /* Bits 20-21: Hour tens in BCD format. */ +#define RTC_TSTR_HT_MASK (3 << RTC_TSTR_HT_SHIFT) +#define RTC_TSTR_PM (1 << 22) /* Bit 22: AM/PM notation */ + +/* RTC time stamp date register */ + +#define RTC_TSDR_DU_SHIFT (0) /* Bit 0-3: Date units in BCD format */ +#define RTC_TSDR_DU_MASK (15 << RTC_TSDR_DU_SHIFT) +#define RTC_TSDR_DT_SHIFT (4) /* Bits 4-5: Date tens in BCD format */ +#define RTC_TSDR_DT_MASK (3 << RTC_TSDR_DT_SHIFT) +#define RTC_TSDR_MU_SHIFT (8) /* Bits 8-11: Month units in BCD format */ +#define RTC_TSDR_MU_MASK (15 << RTC_TSDR_MU_SHIFT) +#define RTC_TSDR_MT (1 << 12) /* Bit 12: Month tens in BCD format */ +#define RTC_TSDR_WDU_SHIFT (13) /* Bits 13-15: Week day units */ +#define RTC_TSDR_WDU_MASK (7 << RTC_TSDR_WDU_SHIFT) + +/* RTC timestamp sub second register */ + +#define RTC_TSSSR_MASK (0xffff) /* Bits 0-15: Sub second value */ + +/* RTC calibration register */ + +#define RTC_CALR_CALM_SHIFT (0) /* Bits 0-8: Calibration minus */ +#define RTC_CALR_CALM_MASK (0x1ff << RTC_CALR_CALM_SHIFT) +#define RTC_CALR_CALW16 (1 << 13) /* Bit 13: Use a 16-second calibration cycle period */ +#define RTC_CALR_CALW8 (1 << 14) /* Bit 14: Use an 8-second calibration cycle period */ +#define RTC_CALR_CALP (1 << 15) /* Bit 15: Increase frequency of RTC by 488.5 ppm */ + +/* RTC tamper and alternate function configuration register */ + +#define RTC_TAFCR_TAMP1E (1 << 0) /* Bit 0: RTC_TAMP1 input detection enable */ +#define RTC_TAFCR_TAMP1TRG (1 << 1) /* Bit 1: Active level for RTC_TAMP1 input */ +#define RTC_TAFCR_TAMPIE (1 << 2) /* Bit 2: Tamper interrupt enable */ +#define RTC_TAFCR_TAMP3E (1 << 5) /* Bit 5: RTC_TAMP3 detection enable */ +#define RTC_TAFCR_TAMP3TRG (1 << 6) /* Bit 6: Active level for RTC_TAMP3 input */ +#define RTC_TAFCR_TAMPTS (1 << 7) /* Bit 7: Activate timestamp on tamper detection event */ +#define RTC_TAFCR_TAMPFREQ_SHIFT (8) /* Bits 8-10: Tamper sampling frequency */ +#define RTC_TAFCR_TAMPFREQ_MASK (7 << RTC_TAFCR_TAMPFREQ_SHIFT) +# define RTC_TAFCR_TAMPFREQ_DIV32768 (0 << RTC_TAFCR_TAMPFREQ_SHIFT) /* RTCCLK / 32768 (1 Hz) */ +# define RTC_TAFCR_TAMPFREQ_DIV16384 (1 << RTC_TAFCR_TAMPFREQ_SHIFT) /* RTCCLK / 16384 (2 Hz) */ +# define RTC_TAFCR_TAMPFREQ_DIV8192 (2 << RTC_TAFCR_TAMPFREQ_SHIFT) /* RTCCLK / 8192 (4 Hz) */ +# define RTC_TAFCR_TAMPFREQ_DIV4096 (3 << RTC_TAFCR_TAMPFREQ_SHIFT) /* RTCCLK / 4096 (8 Hz) */ +# define RTC_TAFCR_TAMPFREQ_DIV2048 (4 << RTC_TAFCR_TAMPFREQ_SHIFT) /* RTCCLK / 2048 (16 Hz) */ +# define RTC_TAFCR_TAMPFREQ_DIV1024 (5 << RTC_TAFCR_TAMPFREQ_SHIFT) /* RTCCLK / 1024 (32 Hz) */ +# define RTC_TAFCR_TAMPFREQ_DIV512 (6 << RTC_TAFCR_TAMPFREQ_SHIFT) /* RTCCLK / 512 (64 Hz) */ +# define RTC_TAFCR_TAMPFREQ_DIV256 (7 << RTC_TAFCR_TAMPFREQ_SHIFT) /* RTCCLK / 256 (128 Hz) */ + +#define RTC_TAFCR_TAMPFLT_SHIFT (11) /* Bits 11-12: RTC_TAMPx filter count */ +#define RTC_TAFCR_TAMPFLT_MASK (3 << RTC_TAFCR_TAMPFLT_SHIFT) +#define RTC_TAFCR_TAMPPRCH_SHIFT (13) /* Bits 13-14: RTC_TAMPx precharge duration */ +#define RTC_TAFCR_TAMPPRCH_MASK (3 << RTC_TAFCR_TAMPPRCH_SHIFT) +# define RTC_TAFCR_TAMPPRCH_1CYCLE (0 << RTC_TAFCR_TAMPPRCH_SHIFT) /* 1 RTCCLK cycle */ +# define RTC_TAFCR_TAMPPRCH_2CYCLES (1 << RTC_TAFCR_TAMPPRCH_SHIFT) /* 2 RTCCLK cycles */ +# define RTC_TAFCR_TAMPPRCH_4CYCLES (2 << RTC_TAFCR_TAMPPRCH_SHIFT) /* 4 RTCCLK cycles */ +# define RTC_TAFCR_TAMPPRCH_5CYCLES (3 << RTC_TAFCR_TAMPPRCH_SHIFT) /* 8 RTCCLK cycles */ + +#define RTC_TAFCR_TAMPPUDIS (1 << 15) /* Bit 15: RTC_TAMPx pull-up disable */ +#define RTC_TAFCR_PC13VALUE (1 << 18) /* Bit 18: RTC_ALARM output type/PC13 value */ +#define RTC_TAFCR_PC13MODE (1 << 19) /* Bit 19: PC13 mode */ +#define RTC_TAFCR_PC14VALUE (1 << 20) /* Bit 20: PC14 value */ +#define RTC_TAFCR_PC14MODE (1 << 21) /* Bit 21: PC14 mode */ +#define RTC_TAFCR_PC15VALUE (1 << 22) /* Bit 22: PC15 value */ +#define RTC_TAFCR_PC15MODE (1 << 23) /* Bit 23: PC15 mode */ + +/* RTC alarm A/B sub second register */ + +#define RTC_ALRMSSR_SS_SHIFT (0) /* Bits 0-14: Sub second value */ +#define RTC_ALRMSSR_SS_MASK (0x7fff << RTC_ALRMSSR_SS_SHIFT) +#define RTC_ALRMSSR_MASKSS_SHIFT (24) /* Bits 24-27: Mask the most-significant bits starting at this bit */ +#define RTC_ALRMSSR_MASKSS_MASK (0xf << RTC_ALRMSSR_MASKSS_SHIFT) + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_RTCC_H */ diff --git a/arch/arm/src/at32/hardware/at32_sdio.h b/arch/arm/src/at32/hardware/at32_sdio.h new file mode 100644 index 0000000000..70801c09d8 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_sdio.h @@ -0,0 +1,274 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_sdio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_SDIO_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_SDIO_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define AT32_SDIO_POWER_OFFSET 0x0000 /* SDIO power control register */ +#define AT32_SDIO_CLKCR_OFFSET 0x0004 /* SDI clock control register */ +#define AT32_SDIO_ARG_OFFSET 0x0008 /* SDIO argument register */ +#define AT32_SDIO_CMD_OFFSET 0x000c /* SDIO command register */ +#define AT32_SDIO_RESPCMD_OFFSET 0x0010 /* SDIO command response register */ +#define AT32_SDIO_RESP_OFFSET(n) (0x0010+4*(n)) +#define AT32_SDIO_RESP1_OFFSET 0x0014 /* SDIO response 1 register */ +#define AT32_SDIO_RESP2_OFFSET 0x0018 /* SDIO response 2 register */ +#define AT32_SDIO_RESP3_OFFSET 0x001c /* SDIO response 3 register */ +#define AT32_SDIO_RESP4_OFFSET 0x0020 /* SDIO response 4 register */ +#define AT32_SDIO_DTIMER_OFFSET 0x0024 /* SDIO data timer register */ +#define AT32_SDIO_DLEN_OFFSET 0x0028 /* SDIO data length register */ +#define AT32_SDIO_DCTRL_OFFSET 0x002c /* SDIO data control register */ +#define AT32_SDIO_DCOUNT_OFFSET 0x0030 /* SDIO data counter register */ +#define AT32_SDIO_STA_OFFSET 0x0034 /* SDIO status register */ +#define AT32_SDIO_ICR_OFFSET 0x0038 /* SDIO interrupt clear register */ +#define AT32_SDIO_MASK_OFFSET 0x003c /* SDIO mask register */ +#define AT32_SDIO_FIFOCNT_OFFSET 0x0048 /* SDIO FIFO counter register */ +#define AT32_SDIO_FIFO_OFFSET 0x0080 /* SDIO data FIFO register */ + +/* Register Addresses *******************************************************/ + +#define AT32_SDIO_POWER (AT32_SDIO1_BASE+AT32_SDIO_POWER_OFFSET) +#define AT32_SDIO_CLKCR (AT32_SDIO1_BASE+AT32_SDIO_CLKCR_OFFSET) +#define AT32_SDIO_ARG (AT32_SDIO1_BASE+AT32_SDIO_ARG_OFFSET) +#define AT32_SDIO_CMD (AT32_SDIO1_BASE+AT32_SDIO_CMD_OFFSET) +#define AT32_SDIO_RESPCMD (AT32_SDIO1_BASE+AT32_SDIO_RESPCMD_OFFSET) +#define AT32_SDIO_RESP(n) (AT32_SDIO1_BASE+AT32_SDIO_RESP_OFFSET(n)) +#define AT32_SDIO_RESP1 (AT32_SDIO1_BASE+AT32_SDIO_RESP1_OFFSET) +#define AT32_SDIO_RESP2 (AT32_SDIO1_BASE+AT32_SDIO_RESP2_OFFSET) +#define AT32_SDIO_RESP3 (AT32_SDIO1_BASE+AT32_SDIO_RESP3_OFFSET) +#define AT32_SDIO_RESP4 (AT32_SDIO1_BASE+AT32_SDIO_RESP4_OFFSET) +#define AT32_SDIO_DTIMER (AT32_SDIO1_BASE+AT32_SDIO_DTIMER_OFFSET) +#define AT32_SDIO_DLEN (AT32_SDIO1_BASE+AT32_SDIO_DLEN_OFFSET) +#define AT32_SDIO_DCTRL (AT32_SDIO1_BASE+AT32_SDIO_DCTRL_OFFSET) +#define AT32_SDIO_DCOUNT (AT32_SDIO1_BASE+AT32_SDIO_DCOUNT_OFFSET) +#define AT32_SDIO_STA (AT32_SDIO1_BASE+AT32_SDIO_STA_OFFSET) +#define AT32_SDIO_ICR (AT32_SDIO1_BASE+AT32_SDIO_ICR_OFFSET) +#define AT32_SDIO_MASK (AT32_SDIO1_BASE+AT32_SDIO_MASK_OFFSET) +#define AT32_SDIO_FIFOCNT (AT32_SDIO1_BASE+AT32_SDIO_FIFOCNT_OFFSET) +#define AT32_SDIO_FIFO (AT32_SDIO1_BASE+AT32_SDIO_FIFO_OFFSET) + +/* Bit-band (BB) base addresses *********************************************/ + +#define AT32_SDIO_OFFSET (AT32_SDIO1_BASE-AT32_PERIPH_BASE) + +#define AT32_SDIO_POWER_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_POWER_OFFSET)<<5)) +#define AT32_SDIO_CLKCR_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_CLKCR_OFFSET)<<5)) +#define AT32_SDIO_ARG_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_ARG_OFFSET)<<5)) +#define AT32_SDIO_CMD_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_CMD_OFFSET)<<5)) +#define AT32_SDIO_RESPCMD_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_RESPCMD_OFFSET)<<5)) +#define AT32_SDIO_RESP_BB(n) (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_RESP_OFFSET(n))<<5)) +#define AT32_SDIO_RESP1_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_RESP1_OFFSET)<<5)) +#define AT32_SDIO_RESP2_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_RESP2_OFFSET)<<5)) +#define AT32_SDIO_RESP3_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_RESP3_OFFSET)<<5)) +#define AT32_SDIO_RESP4_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_RESP4_OFFSET)<<5)) +#define AT32_SDIO_DTIMER_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_DTIMER_OFFSET)<<5)) +#define AT32_SDIO_DLEN_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_DLEN_OFFSET)<<5)) +#define AT32_SDIO_DCTRL_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_DCTRL_OFFSET)<<5)) +#define AT32_SDIO_DCOUNT_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_DCOUNT_OFFSET)<<5)) +#define AT32_SDIO_STA_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_STA_OFFSET)<<5)) +#define AT32_SDIO_ICR_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_ICR_OFFSET)<<5)) +#define AT32_SDIO_MASK_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_MASK_OFFSET)<<5)) +#define AT32_SDIO_FIFOCNT_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_FIFOCNT_OFFSET)<<5)) +#define AT32_SDIO_FIFO_BB (AT32_PERIPHBB_BASE+((AT32_SDIO_OFFSET+AT32_SDIO_FIFO_OFFSET)<<5)) + +/* Register Bitfield Definitions ********************************************/ + +#define SDIO_POWER_PWRCTRL_SHIFT (0) /* Bits 0-1: Power supply control bits */ +#define SDIO_POWER_PWRCTRL_MASK (3 << SDIO_POWER_PWRCTRL_SHIFT) +# define SDIO_POWER_PWRCTRL_OFF (0 << SDIO_POWER_PWRCTRL_SHIFT) /* 00: Power-off: card clock stopped */ +# define SDIO_POWER_PWRCTRL_PWRUP (2 << SDIO_POWER_PWRCTRL_SHIFT) /* 10: Reserved power-up */ +# define SDIO_POWER_PWRCTRL_ON (3 << SDIO_POWER_PWRCTRL_SHIFT) /* 11: Power-on: card is clocked */ + +#define SDIO_POWER_RESET (0) /* Reset value */ + +#define SDIO_CLKCR_CLKDIV_SHIFT (0) /* Bits 7-0: Clock divide factor */ +#define SDIO_CLKCR_CLKDIV_MASK (0xff << SDIO_CLKCR_CLKDIV_SHIFT) +#define SDIO_CLKCR_CLKEN (1 << 8) /* Bit 8: Clock enable bit */ +#define SDIO_CLKCR_PWRSAV (1 << 9) /* Bit 9: Power saving configuration bit */ +#define SDIO_CLKCR_BYPASS (1 << 10) /* Bit 10: Clock divider bypass enable bit */ +#define SDIO_CLKCR_WIDBUS_SHIFT (11) /* Bits 12-11: Wide bus mode enable bits */ +#define SDIO_CLKCR_WIDBUS_MASK (3 << SDIO_CLKCR_WIDBUS_SHIFT) +# define SDIO_CLKCR_WIDBUS_D1 (0 << SDIO_CLKCR_WIDBUS_SHIFT) /* 00: Default (SDIO_D0) */ +# define SDIO_CLKCR_WIDBUS_D4 (1 << SDIO_CLKCR_WIDBUS_SHIFT) /* 01: 4-wide (SDIO_D[3:0]) */ +# define SDIO_CLKCR_WIDBUS_D8 (2 << SDIO_CLKCR_WIDBUS_SHIFT) /* 10: 8-wide (SDIO_D[7:0]) */ + +#define SDIO_CLKCR_NEGEDGE (1 << 13) /* Bit 13: SDIO_CK dephasing selection bit */ +#define SDIO_CLKCR_HWFC_EN (1 << 14) /* Bit 14: HW Flow Control enable */ + +#define SDIO_CLKCR_CLKDIV89_SHIFT (15) /* Clock division bit8 ~ bit9 */ +#define SDIO_CLKCR_CLKDIV89_MASK (3 << SDIO_CLKCR_CLKDIV89_SHIFT) + +#define SDIO_CLKCR_RESET (0) /* Reset value */ +#define SDIO_ARG_RESET (0) /* Reset value */ + +#define SDIO_CLKCR_CLKEN_BB (AT32_SDIO_CLKCR_BB + (8 * 4)) +#define SDIO_CLKCR_PWRSAV_BB (AT32_SDIO_CLKCR_BB + (9 * 4)) +#define SDIO_CLKCR_BYPASS_BB (AT32_SDIO_CLKCR_BB + (10 * 4)) +#define SDIO_CLKCR_NEGEDGE_BB (AT32_SDIO_CLKCR_BB + (13 * 4)) +#define SDIO_CLKCR_HWFC_EN_BB (AT32_SDIO_CLKCR_BB + (14 * 4)) + +#define SDIO_CMD_CMDINDEX_SHIFT (0) +#define SDIO_CMD_CMDINDEX_MASK (0x3f << SDIO_CMD_CMDINDEX_SHIFT) +#define SDIO_CMD_WAITRESP_SHIFT (6) /* Bits 7-6: Wait for response bits */ +#define SDIO_CMD_WAITRESP_MASK (3 << SDIO_CMD_WAITRESP_SHIFT) +# define SDIO_CMD_NORESPONSE (0 << SDIO_CMD_WAITRESP_SHIFT) /* 00/10: No response */ +# define SDIO_CMD_SHORTRESPONSE (1 << SDIO_CMD_WAITRESP_SHIFT) /* 01: Short response */ +# define SDIO_CMD_LONGRESPONSE (3 << SDIO_CMD_WAITRESP_SHIFT) /* 11: Long response */ + +#define SDIO_CMD_WAITINT (1 << 8) /* Bit 8: CPSM waits for interrupt request */ +#define SDIO_CMD_WAITPEND (1 << 9) /* Bit 9: CPSM Waits for ends of data transfer */ +#define SDIO_CMD_CPSMEN (1 << 10) /* Bit 10: Command path state machine enable */ +#define SDIO_CMD_SUSPEND (1 << 11) /* Bit 11: SD I/O suspend command */ + +#define SDIO_CMD_RESET (0) /* Reset value */ + +#define SDIO_CMD_WAITINT_BB (AT32_SDIO_CMD_BB + (8 * 4)) +#define SDIO_CMD_WAITPEND_BB (AT32_SDIO_CMD_BB + (9 * 4)) +#define SDIO_CMD_CPSMEN_BB (AT32_SDIO_CMD_BB + (10 * 4)) +#define SDIO_CMD_SUSPEND_BB (AT32_SDIO_CMD_BB + (11 * 4)) +#define SDIO_CMD_ENCMD_BB (AT32_SDIO_CMD_BB + (12 * 4)) +#define SDIO_CMD_NIEN_BB (AT32_SDIO_CMD_BB + (13 * 4)) +#define SDIO_CMD_ATACMD_BB (AT32_SDIO_CMD_BB + (14 * 4)) + +#define SDIO_RESPCMD_SHIFT (0) +#define SDIO_RESPCMD_MASK (0x3f << SDIO_RESPCMD_SHIFT) + +#define SDIO_DTIMER_RESET (0) /* Reset value */ + +#define SDIO_DLEN_SHIFT (0) +#define SDIO_DLEN_MASK (0x01ffffff << SDIO_DLEN_SHIFT) + +#define SDIO_DLEN_RESET (0) /* Reset value */ + +#define SDIO_DCTRL_DTEN (1 << 0) /* Bit 0: Data transfer enabled bit */ +#define SDIO_DCTRL_DTDIR (1 << 1) /* Bit 1: Data transfer direction */ +#define SDIO_DCTRL_DTMODE (1 << 2) /* Bit 2: Data transfer mode */ +#define SDIO_DCTRL_DMAEN (1 << 3) /* Bit 3: DMA enable bit */ +#define SDIO_DCTRL_DBLOCKSIZE_SHIFT (4) /* Bits 7-4: Data block size */ +#define SDIO_DCTRL_DBLOCKSIZE_MASK (15 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_1BYTE (0 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_2BYTES (1 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_4BYTES (2 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_8BYTES (3 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_16BYTES (4 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_32BYTES (5 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_64BYTES (6 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_128BYTES (7 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_256BYTES (8 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_512BYTES (9 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_1KBYTE (10 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_2KBYTES (11 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_4KBYTES (12 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_8KBYTES (13 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +# define SDIO_DCTRL_16KBYTES (14 << SDIO_DCTRL_DBLOCKSIZE_SHIFT) +#define SDIO_DCTRL_RWSTART (1 << 8) /* Bit 8: Read wait start */ +#define SDIO_DCTRL_RWSTOP (1 << 9) /* Bit 9: Read wait stop */ +#define SDIO_DCTRL_RWMOD (1 << 10) /* Bit 10: Read wait mode */ +#define SDIO_DCTRL_SDIOEN (1 << 11) /* Bit 11: SD I/O enable functions */ + +#define SDIO_DCTRL_RESET (0) /* Reset value */ + +#define SDIO_DCTRL_DTEN_BB (AT32_SDIO_DCTRL_BB + (0 * 4)) +#define SDIO_DCTRL_DTDIR_BB (AT32_SDIO_DCTRL_BB + (1 * 4)) +#define SDIO_DCTRL_DTMODE_BB (AT32_SDIO_DCTRL_BB + (2 * 4)) +#define SDIO_DCTRL_DMAEN_BB (AT32_SDIO_DCTRL_BB + (3 * 4)) +#define SDIO_DCTRL_RWSTART_BB (AT32_SDIO_DCTRL_BB + (8 * 4)) +#define SDIO_DCTRL_RWSTOP_BB (AT32_SDIO_DCTRL_BB + (9 * 4)) +#define SDIO_DCTRL_RWMOD_BB (AT32_SDIO_DCTRL_BB + (10 * 4)) +#define SDIO_DCTRL_SDIOEN_BB (AT32_SDIO_DCTRL_BB + (11 * 4)) + +#define SDIO_DATACOUNT_SHIFT (0) +#define SDIO_DATACOUNT_MASK (0x01ffffff << SDIO_DATACOUNT_SHIFT) + +#define SDIO_STA_CCRCFAIL (1 << 0) /* Bit 0: Command response CRC fail */ +#define SDIO_STA_DCRCFAIL (1 << 1) /* Bit 1: Data block CRC fail */ +#define SDIO_STA_CTIMEOUT (1 << 2) /* Bit 2: Command response timeout */ +#define SDIO_STA_DTIMEOUT (1 << 3) /* Bit 3: Data timeout */ +#define SDIO_STA_TXUNDERR (1 << 4) /* Bit 4: Transmit FIFO underrun error */ +#define SDIO_STA_RXOVERR (1 << 5) /* Bit 5: Received FIFO overrun error */ +#define SDIO_STA_CMDREND (1 << 6) /* Bit 6: Command response received */ +#define SDIO_STA_CMDSENT (1 << 7) /* Bit 7: Command sent */ +#define SDIO_STA_DATAEND (1 << 8) /* Bit 8: Data end */ +#define SDIO_STA_STBITERR (1 << 9) /* Bit 9: Start bit not detected */ +#define SDIO_STA_DBCKEND (1 << 10) /* Bit 10: Data block sent/received */ +#define SDIO_STA_CMDACT (1 << 11) /* Bit 11: Command transfer in progress */ +#define SDIO_STA_TXACT (1 << 12) /* Bit 12: Data transmit in progress */ +#define SDIO_STA_RXACT (1 << 13) /* Bit 13: Data receive in progress */ +#define SDIO_STA_TXFIFOHE (1 << 14) /* Bit 14: Transmit FIFO half empty */ +#define SDIO_STA_RXFIFOHF (1 << 15) /* Bit 15: Receive FIFO half full */ +#define SDIO_STA_TXFIFOF (1 << 16) /* Bit 16: Transmit FIFO full */ +#define SDIO_STA_RXFIFOF (1 << 17) /* Bit 17: Receive FIFO full */ +#define SDIO_STA_TXFIFOE (1 << 18) /* Bit 18: Transmit FIFO empty */ +#define SDIO_STA_RXFIFOE (1 << 19) /* Bit 19: Receive FIFO empty */ +#define SDIO_STA_TXDAVL (1 << 20) /* Bit 20: Data available in transmit FIFO */ +#define SDIO_STA_RXDAVL (1 << 21) /* Bit 21: Data available in receive FIFO */ +#define SDIO_STA_SDIOIT (1 << 22) /* Bit 22: SDIO interrupt received */ + +#define SDIO_ICR_CCRCFAILC (1 << 0) /* Bit 0: CCRCFAIL flag clear bit */ +#define SDIO_ICR_DCRCFAILC (1 << 1) /* Bit 1: DCRCFAIL flag clear bit */ +#define SDIO_ICR_CTIMEOUTC (1 << 2) /* Bit 2: CTIMEOUT flag clear bit */ +#define SDIO_ICR_DTIMEOUTC (1 << 3) /* Bit 3: DTIMEOUT flag clear bit */ +#define SDIO_ICR_TXUNDERRC (1 << 4) /* Bit 4: TXUNDERR flag clear bit */ +#define SDIO_ICR_RXOVERRC (1 << 5) /* Bit 5: RXOVERR flag clear bit */ +#define SDIO_ICR_CMDRENDC (1 << 6) /* Bit 6: CMDREND flag clear bit */ +#define SDIO_ICR_CMDSENTC (1 << 7) /* Bit 7: CMDSENT flag clear bit */ +#define SDIO_ICR_DATAENDC (1 << 8) /* Bit 8: DATAEND flag clear bit */ +#define SDIO_ICR_STBITERRC (1 << 9) /* Bit 9: STBITERR flag clear bit */ +#define SDIO_ICR_DBCKENDC (1 << 10) /* Bit 10: DBCKEND flag clear bit */ +#define SDIO_ICR_SDIOITC (1 << 22) /* Bit 22: SDIOIT flag clear bit */ + +#define SDIO_ICR_RESET 0x004007ff +#define SDIO_ICR_STATICFLAGS 0x000005ff + +#define SDIO_MASK_CCRCFAILIE (1 << 0) /* Bit 0: Command CRC fail interrupt enable */ +#define SDIO_MASK_DCRCFAILIE (1 << 1) /* Bit 1: Data CRC fail interrupt enable */ +#define SDIO_MASK_CTIMEOUTIE (1 << 2) /* Bit 2: Command timeout interrupt enable */ +#define SDIO_MASK_DTIMEOUTIE (1 << 3) /* Bit 3: Data timeout interrupt enable */ +#define SDIO_MASK_TXUNDERRIE (1 << 4) /* Bit 4: Tx FIFO underrun error interrupt enable */ +#define SDIO_MASK_RXOVERRIE (1 << 5) /* Bit 5: Rx FIFO overrun error interrupt enable */ +#define SDIO_MASK_CMDRENDIE (1 << 6) /* Bit 6: Command response received interrupt enable */ +#define SDIO_MASK_CMDSENTIE (1 << 7) /* Bit 7: Command sent interrupt enable */ +#define SDIO_MASK_DATAENDIE (1 << 8) /* Bit 8: Data end interrupt enable */ +#define SDIO_MASK_STBITERRIE (1 << 9) /* Bit 9: Start bit error interrupt enable */ +#define SDIO_MASK_DBCKENDIE (1 << 10) /* Bit 10: Data block end interrupt enable */ +#define SDIO_MASK_CMDACTIE (1 << 11) /* Bit 11: Command acting interrupt enable */ +#define SDIO_MASK_TXACTIE (1 << 12) /* Bit 12: Data transmit acting interrupt enable */ +#define SDIO_MASK_RXACTIE (1 << 13) /* Bit 13: Data receive acting interrupt enable */ +#define SDIO_MASK_TXFIFOHEIE (1 << 14) /* Bit 14: Tx FIFO half empty interrupt enable */ +#define SDIO_MASK_RXFIFOHFIE (1 << 15) /* Bit 15: Rx FIFO half full interrupt enable */ +#define SDIO_MASK_TXFIFOFIE (1 << 16) /* Bit 16: Tx FIFO full interrupt enable */ +#define SDIO_MASK_RXFIFOFIE (1 << 17) /* Bit 17: Rx FIFO full interrupt enable */ +#define SDIO_MASK_TXFIFOEIE (1 << 18) /* Bit 18: Tx FIFO empty interrupt enable */ +#define SDIO_MASK_RXFIFOEIE (1 << 19) /* Bit 19: Rx FIFO empty interrupt enable */ +#define SDIO_MASK_TXDAVLIE (1 << 20) /* Bit 20: Data available in Tx FIFO interrupt enable */ +#define SDIO_MASK_RXDAVLIE (1 << 21) /* Bit 21: Data available in Rx FIFO interrupt enable */ +#define SDIO_MASK_SDIOITIE (1 << 22) /* Bit 22: SDIO mode interrupt received interrupt enable */ + +#define SDIO_MASK_RESET (0) + +#define SDIO_FIFOCNT_SHIFT (0) +#define SDIO_FIFOCNT_MASK (0x01ffffff << SDIO_FIFOCNT_SHIFT) + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_SDIO_H */ diff --git a/arch/arm/src/at32/hardware/at32_spi.h b/arch/arm/src/at32/hardware/at32_spi.h new file mode 100644 index 0000000000..2fa2567496 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_spi.h @@ -0,0 +1,181 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_spi.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_SPI_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_SPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* SPI version **************************************************************/ + +#define HAVE_SPI_I2S /* Some SPI peripherals have I2S mode */ +#define HAVE_SPI_I2S_ASTRT /* Supports I2S asynchronous start capability */ +#define HAVE_SPI_TI_MODE /* Have Motorola and TI frame modes */ +#define HAVE_SPI_ARB_DATA_SIZE /* Supports arbitrary data size from 4-16 bits */ +#define HAVE_SPI_FIFOS /* Have Tx/Rx FIFOs */ +#define HAVE_SPI_NSSP /* Have NSS Pulse Management in master mode */ + +/* Maximum allowed speed as per specifications for all SPIs */ + +#define AT32_SPI_CLK_MAX 14400000UL + +/* Register Offsets *********************************************************/ + +#define AT32_SPI_CTRL1_OFFSET 0x00 /* SPI Control Register 1 (16-bit) */ +#define AT32_SPI_CTRL2_OFFSET 0x04 /* SPI control register 2 (16-bit) */ +#define AT32_SPI_STS_OFFSET 0x08 /* SPI status register (16-bit) */ +#define AT32_SPI_DT_OFFSET 0x0c /* SPI data register (16-bit) */ +#define AT32_SPI_CPOLY_OFFSET 0x10 /* SPI CRC polynomial register (16-bit) */ +#define AT32_SPI_RCRC_OFFSET 0x14 /* SPI Rx CRC register (16-bit) */ +#define AT32_SPI_TCRC_OFFSET 0x18 /* SPI Tx CRC register (16-bit) */ + +#if defined(HAVE_SPI_I2S) +# define AT32_SPI_I2SCTRL_OFFSET 0x1c /* I2S configuration register */ +# define AT32_SPI_I2SCLKP_OFFSET 0x20 /* I2S prescaler register */ +#endif + +/* Register Addresses *******************************************************/ + +#if AT32_NSPI > 0 +# define AT32_SPI1_CTRL1 (AT32_SPI1_BASE + AT32_SPI_CTRL1_OFFSET) +# define AT32_SPI1_CTRL2 (AT32_SPI1_BASE + AT32_SPI_CTRL2_OFFSET) +# define AT32_SPI1_STS (AT32_SPI1_BASE + AT32_SPI_STS_OFFSET) +# define AT32_SPI1_DT (AT32_SPI1_BASE + AT32_SPI_DT_OFFSET) +# define AT32_SPI1_CPOLY (AT32_SPI1_BASE + AT32_SPI_CPOLY_OFFSET) +# define AT32_SPI1_RCRC (AT32_SPI1_BASE + AT32_SPI_RCRC_OFFSET) +# define AT32_SPI1_TCRC (AT32_SPI1_BASE + AT32_SPI_TCRC_OFFSET) +# if defined(HAVE_SPI_I2S) +# define AT32_SPI1_I2SCTRL (AT32_SPI1_BASE + AT32_SPI_I2SCTRL_OFFSET) +# define AT32_SPI1_I2SCLKP (AT32_SPI1_BASE + AT32_SPI_I2SCLKP_OFFSET) +# endif +#endif + +#if AT32_NSPI > 1 +# define AT32_SPI2_CTRL1 (AT32_SPI2_BASE + AT32_SPI_CTRL1_OFFSET) +# define AT32_SPI2_CTRL2 (AT32_SPI2_BASE + AT32_SPI_CTRL2_OFFSET) +# define AT32_SPI2_STS (AT32_SPI2_BASE + AT32_SPI_STS_OFFSET) +# define AT32_SPI2_DT (AT32_SPI2_BASE + AT32_SPI_DT_OFFSET) +# define AT32_SPI2_CPOLY (AT32_SPI2_BASE + AT32_SPI_CPOLY_OFFSET) +# define AT32_SPI2_RCRC (AT32_SPI2_BASE + AT32_SPI_RCRC_OFFSET) +# define AT32_SPI2_TCRC (AT32_SPI2_BASE + AT32_SPI_TCRC_OFFSET) +# if defined(HAVE_SPI_I2S) +# define AT32_SPI2_I2SCTRL (AT32_SPI2_BASE + AT32_SPI_I2SCTRL_OFFSET) +# define AT32_SPI2_I2SCLKP (AT32_SPI2_BASE + AT32_SPI_I2SCLKP_OFFSET) +# endif +#endif + +#if AT32_NSPI > 2 +# define AT32_SPI3_CTRL1 (AT32_SPI3_BASE + AT32_SPI_CTRL1_OFFSET) +# define AT32_SPI3_CTRL2 (AT32_SPI3_BASE + AT32_SPI_CTRL2_OFFSET) +# define AT32_SPI3_STS (AT32_SPI3_BASE + AT32_SPI_STS_OFFSET) +# define AT32_SPI3_DT (AT32_SPI3_BASE + AT32_SPI_DT_OFFSET) +# define AT32_SPI3_CPOLY (AT32_SPI3_BASE + AT32_SPI_CPOLY_OFFSET) +# define AT32_SPI3_RCRC (AT32_SPI3_BASE + AT32_SPI_RCRC_OFFSET) +# define AT32_SPI3_TCRC (AT32_SPI3_BASE + AT32_SPI_TCRC_OFFSET) +# if defined(HAVE_SPI_I2S) +# define AT32_SPI3_I2SCTRL (AT32_SPI3_BASE + AT32_SPI_I2SCTRL_OFFSET) +# define AT32_SPI3_I2SCLKP (AT32_SPI3_BASE + AT32_SPI_I2SCLKP_OFFSET) +# endif +#endif + +#if AT32_NSPI > 3 +# define AT32_SPI4_CTRL1 (AT32_SPI4_BASE + AT32_SPI_CTRL1_OFFSET) +# define AT32_SPI4_CTRL2 (AT32_SPI4_BASE + AT32_SPI_CTRL2_OFFSET) +# define AT32_SPI4_STS (AT32_SPI4_BASE + AT32_SPI_STS_OFFSET) +# define AT32_SPI4_DT (AT32_SPI4_BASE + AT32_SPI_DT_OFFSET) +# define AT32_SPI4_CPOLY (AT32_SPI4_BASE + AT32_SPI_CPOLY_OFFSET) +# define AT32_SPI4_RCRC (AT32_SPI4_BASE + AT32_SPI_RCRC_OFFSET) +# define AT32_SPI4_TCRC (AT32_SPI4_BASE + AT32_SPI_TCRC_OFFSET) +# if defined(HAVE_SPI_I2S) +# define AT32_SPI4_I2SCTRL (AT32_SPI4_BASE + AT32_SPI_I2SCTRL_OFFSET) +# define AT32_SPI4_I2SCLKP (AT32_SPI4_BASE + AT32_SPI_I2SCLKP_OFFSET) +# endif +#endif + +/* Register Bitfield Definitions ********************************************/ + +/* SPI Control Register 1 */ + +#define SPI_CTRL1_CLKPHA (1 << 0) /* Clock phase */ +#define SPI_CTRL1_CLKPOL (1 << 1) /* Clock polarity */ +#define SPI_CTRL1_MSTEN (1 << 2) /* Master enable */ + +#define SPI_CTRL1_MDIV_SHIFT (3) /* Master clock frequency division */ +#define SPI_CTRL1_MDIV_MASK (7 << SPI_CTRL1_MDIV_SHIFT) +# define SPI_CTRL1_MDIV_2 (0 << SPI_CTRL1_MDIV_SHIFT) /* Div 2 */ +# define SPI_CTRL1_MDIV_4 (1 << SPI_CTRL1_MDIV_SHIFT) /* Div 4 */ +# define SPI_CTRL1_MDIV_8 (2 << SPI_CTRL1_MDIV_SHIFT) /* Div 8 */ +# define SPI_CTRL1_MDIV_16 (3 << SPI_CTRL1_MDIV_SHIFT) /* Div 16 */ +# define SPI_CTRL1_MDIV_32 (4 << SPI_CTRL1_MDIV_SHIFT) /* Div 32 */ +# define SPI_CTRL1_MDIV_64 (5 << SPI_CTRL1_MDIV_SHIFT) /* Div 64 */ +# define SPI_CTRL1_MDIV_128 (6 << SPI_CTRL1_MDIV_SHIFT) /* Div 128 */ +# define SPI_CTRL1_MDIV_256 (7 << SPI_CTRL1_MDIV_SHIFT) /* Div 256 */ +# define SPI_CTRL1_MDIV_512 (8 << SPI_CTRL1_MDIV_SHIFT) /* Div 512 */ +# define SPI_CTRL1_MDIV_1024 (9 << SPI_CTRL1_MDIV_SHIFT) /* Div 1024 */ + +#define SPI_CTRL1_SPIEN (1 << 6) /* SPI enable */ +#define SPI_CTRL1_LTF (1 << 7) /* LSB transmit first */ +#define SPI_CTRL1_SWCSIL (1 << 8) /* Software CS internal level */ +#define SPI_CTRL1_SWCSEN (1 << 9) /* Software CS enable */ +#define SPI_CTRL1_ORA (1 << 10) /* Only receive active */ +#define SPI_CTRL1_FBN (1 << 11) /* frame bit num */ +#define SPI_CTRL1_NTC (1 << 12) /* Next transmission CRC */ +#define SPI_CTRL1_CCEN (1 << 13) /* CRC calculation enable */ +#define SPI_CTRL1_SLBTD (1 << 14) /* Single line bidirectional half-duplex transmission direction */ +#define SPI_CTRL1_SLBEN (1 << 15) /* Single line bidirectional halfduplex enable */ + +/* SPI Control Register 2 */ + +#define SPI_CTRL2_DMAREN (1 << 0) /* DMA receive enable */ +#define SPI_CTRL2_DMATEN (1 << 1) /* DMA transmit enable */ +#define SPI_CTRL2_HWCSOE (1 << 2) /* Hardware CS output enable */ +#define SPI_CTRL2_TIEN (1 << 4) /* TI mode enable */ +#define SPI_CTRL2_ERRIE (1 << 5) /* Error interrupt enable */ +#define SPI_CTRL2_RDBFIE (1 << 6) /* Receive data buffer full interrupt enable */ +#define SPI_CTRL2_TDBEIE (1 << 7) /* Transmit data buffer empty interrupt enable */ +#define SPI_CTRL2_MDIV (1 << 8) /* Master clock frequency division */ +#define SPI_CTRL2_MDIV3EN (1 << 9) /* Master clock frequency3 division enable */ + +/* SPI status register */ + +#define SPI_STS_RDBF (1 << 0) /* Receive data buffer full */ +#define SPI_STS_TDBE (1 << 1) /* Transmit data buffer empty */ +#define SPI_STS_ACS (1 << 2) /* Audio channel state */ +#define SPI_STS_TUERR (1 << 3) /* Transmitter underload error */ +#define SPI_STS_CCERR (1 << 4) /* CRC calculation error */ +#define SPI_STS_MMERR (1 << 5) /* Master mode error */ +#define SPI_STS_ROERR (1 << 6) /* Receiver overflow error */ +#define SPI_STS_BF (1 << 7) /* Busy flag */ +#define SPI_STS_CSPAS (1 << 8) /* CS pulse abnormal setting fiag */ + +/* I2S configuration register */ + +/* I2S prescaler register */ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_SPI_H */ diff --git a/arch/arm/src/at32/hardware/at32_tim.h b/arch/arm/src/at32/hardware/at32_tim.h new file mode 100644 index 0000000000..3e8835b0c5 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_tim.h @@ -0,0 +1,1057 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_tim.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_TIM_V1V2_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_TIM_V1V2_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +/* Basic Timers - TIM6 and TIM7 */ + +#define AT32_BTIM_CR1_OFFSET 0x0000 /* Control register 1 (16-bit) */ +#define AT32_BTIM_CR2_OFFSET 0x0004 /* Control register 2 (16-bit) */ +#define AT32_BTIM_DIER_OFFSET 0x000c /* DMA/Interrupt enable register (16-bit) */ +#define AT32_BTIM_SR_OFFSET 0x0010 /* Status register (16-bit) */ +#define AT32_BTIM_EGR_OFFSET 0x0014 /* Event generation register (16-bit) */ +#define AT32_BTIM_CNT_OFFSET 0x0024 /* Counter (16-bit) */ +#define AT32_BTIM_PSC_OFFSET 0x0028 /* Prescaler (16-bit) */ +#define AT32_BTIM_ARR_OFFSET 0x002c /* Auto-reload register (16-bit) */ + +/* 16-/32-bit General Timers with DMA: TIM2, TM3, TIM4, and TIM5 + * 16-bit General Timers without DMA: TIM9, TIM10, TIM11, TIM12, TIM13, + * and TIM14 + */ + +#define AT32_GTIM_CR1_OFFSET 0x0000 /* Control register 1 (16-bit) */ +#define AT32_GTIM_CR2_OFFSET 0x0004 /* Control register 2 (16-bit, TIM2-5 only) */ +#define AT32_GTIM_SMCR_OFFSET 0x0008 /* Slave mode control register (16-bit, TIM2-5 only) */ +#define AT32_GTIM_DIER_OFFSET 0x000c /* DMA/Interrupt enable register (16-bit) */ +#define AT32_GTIM_SR_OFFSET 0x0010 /* Status register (16-bit) */ +#define AT32_GTIM_EGR_OFFSET 0x0014 /* Event generation register (16-bit) */ +#define AT32_GTIM_CCMR1_OFFSET 0x0018 /* Capture/compare mode register 1 (16-bit) */ +#define AT32_GTIM_CCMR2_OFFSET 0x001c /* Capture/compare mode register 2 (16-bit, TIM2-5 only) */ +#define AT32_GTIM_CCER_OFFSET 0x0020 /* Capture/compare enable register (16-bit) */ +#define AT32_GTIM_CNT_OFFSET 0x0024 /* Counter (16-bit* or 32-bit AT32F43 TIM2 and 5 only) */ +#define AT32_GTIM_PSC_OFFSET 0x0028 /* Prescaler (16-bit) */ +#define AT32_GTIM_ARR_OFFSET 0x002c /* Auto-reload register (16-bit) */ +#define AT32_GTIM_CCR1_OFFSET 0x0034 /* Capture/compare register 1 (16-bit or 32-bit AT32F43 TIM2/5 only) */ +#define AT32_GTIM_CCR2_OFFSET 0x0038 /* Capture/compare register 2 (16-bit TIM2-5 only or 32-bit AT32 F4 TIM2/5 or STM2 F3 TIM15 only) */ +#define AT32_GTIM_CCR3_OFFSET 0x003c /* Capture/compare register 3 (16-bit TIM2-5 only or 32-bit AT32 F4 TIM2/5 only) */ +#define AT32_GTIM_CCR4_OFFSET 0x0040 /* Capture/compare register 4 (16-bit TIM2-5 only or 32-bit AT32 F4 TIM2/5 only) */ +#define AT32_GTIM_DCR_OFFSET 0x0048 /* DMA control register (16-bit, TIM2-5 only) */ +#define AT32_GTIM_DMAR_OFFSET 0x004c /* DMA address for burst mode (16-bit, TIM2-5 only) */ + +#define AT32_GTIM_OR_OFFSET 0x0050 /* Timer 2/5/11/16 option register */ + +/* Advanced Timers - TIM1, TIM8 and TIM20 */ + +#define AT32_ATIM_CR1_OFFSET 0x0000 /* Control register 1 (16-bit) */ +#define AT32_ATIM_CR2_OFFSET 0x0004 /* Control register 2 (16-bit*) */ +#define AT32_ATIM_SMCR_OFFSET 0x0008 /* Slave mode control register (16-bit) */ +#define AT32_ATIM_DIER_OFFSET 0x000c /* DMA/Interrupt enable register (16-bit) */ +#define AT32_ATIM_SR_OFFSET 0x0010 /* Status register (16-bit*) */ +#define AT32_ATIM_EGR_OFFSET 0x0014 /* Event generation register (16-bit) */ +#define AT32_ATIM_CCMR1_OFFSET 0x0018 /* Capture/compare mode register 1 (16-bit*) */ +#define AT32_ATIM_CCMR2_OFFSET 0x001c /* Capture/compare mode register 2 (16-bit*) */ +#define AT32_ATIM_CCER_OFFSET 0x0020 /* Capture/compare enable register (16-bit*) */ +#define AT32_ATIM_CNT_OFFSET 0x0024 /* Counter (16-bit) */ +#define AT32_ATIM_PSC_OFFSET 0x0028 /* Prescaler (16-bit) */ +#define AT32_ATIM_ARR_OFFSET 0x002c /* Auto-reload register (16-bit) */ +#define AT32_ATIM_RCR_OFFSET 0x0030 /* Repetition counter register (16-bit) */ +#define AT32_ATIM_CCR1_OFFSET 0x0034 /* Capture/compare register 1 (16-bit) */ +#define AT32_ATIM_CCR2_OFFSET 0x0038 /* Capture/compare register 2 (16-bit) */ +#define AT32_ATIM_CCR3_OFFSET 0x003c /* Capture/compare register 3 (16-bit) */ +#define AT32_ATIM_CCR4_OFFSET 0x0040 /* Capture/compare register 4 (16-bit) */ +#define AT32_ATIM_BDTR_OFFSET 0x0044 /* Break and dead-time register (16-bit*) */ +#define AT32_ATIM_DCR_OFFSET 0x0048 /* DMA control register (16-bit) */ +#define AT32_ATIM_DMAR_OFFSET 0x004c /* DMA address for burst mode (16-bit) */ + +/* Note that many of the above registers are 32-bits wide on the F3 */ + +#define AT32_ATIM_CCMR3_OFFSET 0x0070 /* Capture/compare mode register 3 (32-bit) */ +#define AT32_ATIM_CCR5_OFFSET 0x0074 /* Capture/compare register 5 (32-bit) */ + +/* Register Addresses *******************************************************/ + +/* Advanced Timers - TIM1 and TIM8 TIM20 */ + +#if AT32_NATIM > 0 +# define AT32_TIM1_CR1 (AT32_TMR1_BASE+AT32_ATIM_CR1_OFFSET) +# define AT32_TIM1_CR2 (AT32_TMR1_BASE+AT32_ATIM_CR2_OFFSET) +# define AT32_TIM1_SMCR (AT32_TMR1_BASE+AT32_ATIM_SMCR_OFFSET) +# define AT32_TIM1_DIER (AT32_TMR1_BASE+AT32_ATIM_DIER_OFFSET) +# define AT32_TIM1_SR (AT32_TMR1_BASE+AT32_ATIM_SR_OFFSET) +# define AT32_TIM1_EGR (AT32_TMR1_BASE+AT32_ATIM_EGR_OFFSET) +# define AT32_TIM1_CCMR1 (AT32_TMR1_BASE+AT32_ATIM_CCMR1_OFFSET) +# define AT32_TIM1_CCMR2 (AT32_TMR1_BASE+AT32_ATIM_CCMR2_OFFSET) +# define AT32_TIM1_CCER (AT32_TMR1_BASE+AT32_ATIM_CCER_OFFSET) +# define AT32_TIM1_CNT (AT32_TMR1_BASE+AT32_ATIM_CNT_OFFSET) +# define AT32_TIM1_PSC (AT32_TMR1_BASE+AT32_ATIM_PSC_OFFSET) +# define AT32_TIM1_ARR (AT32_TMR1_BASE+AT32_ATIM_ARR_OFFSET) +# define AT32_TIM1_RCR (AT32_TMR1_BASE+AT32_ATIM_RCR_OFFSET) +# define AT32_TIM1_CCR1 (AT32_TMR1_BASE+AT32_ATIM_CCR1_OFFSET) +# define AT32_TIM1_CCR2 (AT32_TMR1_BASE+AT32_ATIM_CCR2_OFFSET) +# define AT32_TIM1_CCR3 (AT32_TMR1_BASE+AT32_ATIM_CCR3_OFFSET) +# define AT32_TIM1_CCR4 (AT32_TMR1_BASE+AT32_ATIM_CCR4_OFFSET) +# define AT32_TIM1_BDTR (AT32_TMR1_BASE+AT32_ATIM_BDTR_OFFSET) +# define AT32_TIM1_DCR (AT32_TMR1_BASE+AT32_ATIM_DCR_OFFSET) +# define AT32_TIM1_DMAR (AT32_TMR1_BASE+AT32_ATIM_DMAR_OFFSET) +# define AT32_TIM1_CCMR3 (AT32_TMR1_BASE+AT32_ATIM_CCMR3_OFFSET) +# define AT32_TIM1_CCR5 (AT32_TMR1_BASE+AT32_ATIM_CCR5_OFFSET) +#endif + +#if AT32_NATIM > 1 +# define AT32_TIM8_CR1 (AT32_TMR8_BASE+AT32_ATIM_CR1_OFFSET) +# define AT32_TIM8_CR2 (AT32_TMR8_BASE+AT32_ATIM_CR2_OFFSET) +# define AT32_TIM8_SMCR (AT32_TMR8_BASE+AT32_ATIM_SMCR_OFFSET) +# define AT32_TIM8_DIER (AT32_TMR8_BASE+AT32_ATIM_DIER_OFFSET) +# define AT32_TIM8_SR (AT32_TMR8_BASE+AT32_ATIM_SR_OFFSET) +# define AT32_TIM8_EGR (AT32_TMR8_BASE+AT32_ATIM_EGR_OFFSET) +# define AT32_TIM8_CCMR1 (AT32_TMR8_BASE+AT32_ATIM_CCMR1_OFFSET) +# define AT32_TIM8_CCMR2 (AT32_TMR8_BASE+AT32_ATIM_CCMR2_OFFSET) +# define AT32_TIM8_CCER (AT32_TMR8_BASE+AT32_ATIM_CCER_OFFSET) +# define AT32_TIM8_CNT (AT32_TMR8_BASE+AT32_ATIM_CNT_OFFSET) +# define AT32_TIM8_PSC (AT32_TMR8_BASE+AT32_ATIM_PSC_OFFSET) +# define AT32_TIM8_ARR (AT32_TMR8_BASE+AT32_ATIM_ARR_OFFSET) +# define AT32_TIM8_RCR (AT32_TMR8_BASE+AT32_ATIM_RCR_OFFSET) +# define AT32_TIM8_CCR1 (AT32_TMR8_BASE+AT32_ATIM_CCR1_OFFSET) +# define AT32_TIM8_CCR2 (AT32_TMR8_BASE+AT32_ATIM_CCR2_OFFSET) +# define AT32_TIM8_CCR3 (AT32_TMR8_BASE+AT32_ATIM_CCR3_OFFSET) +# define AT32_TIM8_CCR4 (AT32_TMR8_BASE+AT32_ATIM_CCR4_OFFSET) +# define AT32_TIM8_BDTR (AT32_TMR8_BASE+AT32_ATIM_BDTR_OFFSET) +# define AT32_TIM8_DCR (AT32_TMR8_BASE+AT32_ATIM_DCR_OFFSET) +# define AT32_TIM8_DMAR (AT32_TMR8_BASE+AT32_ATIM_DMAR_OFFSET) +# define AT32_TIM8_CCMR3 (AT32_TMR8_BASE+AT32_ATIM_CCMR3_OFFSET) +# define AT32_TIM8_CCR5 (AT32_TMR8_BASE+AT32_ATIM_CCR5_OFFSET) +#endif + +#if AT32_NATIM > 2 +# define AT32_TIM20_CR1 (AT32_TMR20_BASE+AT32_ATIM_CR1_OFFSET) +# define AT32_TIM20_CR2 (AT32_TMR20_BASE+AT32_ATIM_CR2_OFFSET) +# define AT32_TIM20_SMCR (AT32_TMR20_BASE+AT32_ATIM_SMCR_OFFSET) +# define AT32_TIM20_DIER (AT32_TMR20_BASE+AT32_ATIM_DIER_OFFSET) +# define AT32_TIM20_SR (AT32_TMR20_BASE+AT32_ATIM_SR_OFFSET) +# define AT32_TIM20_EGR (AT32_TMR20_BASE+AT32_ATIM_EGR_OFFSET) +# define AT32_TIM20_CCMR1 (AT32_TMR20_BASE+AT32_ATIM_CCMR1_OFFSET) +# define AT32_TIM20_CCMR2 (AT32_TMR20_BASE+AT32_ATIM_CCMR2_OFFSET) +# define AT32_TIM20_CCER (AT32_TMR20_BASE+AT32_ATIM_CCER_OFFSET) +# define AT32_TIM20_CNT (AT32_TMR20_BASE+AT32_ATIM_CNT_OFFSET) +# define AT32_TIM20_PSC (AT32_TMR20_BASE+AT32_ATIM_PSC_OFFSET) +# define AT32_TIM20_ARR (AT32_TMR20_BASE+AT32_ATIM_ARR_OFFSET) +# define AT32_TIM20_RCR (AT32_TMR20_BASE+AT32_ATIM_RCR_OFFSET) +# define AT32_TIM20_CCR1 (AT32_TMR20_BASE+AT32_ATIM_CCR1_OFFSET) +# define AT32_TIM20_CCR2 (AT32_TMR20_BASE+AT32_ATIM_CCR2_OFFSET) +# define AT32_TIM20_CCR3 (AT32_TMR20_BASE+AT32_ATIM_CCR3_OFFSET) +# define AT32_TIM20_CCR4 (AT32_TMR20_BASE+AT32_ATIM_CCR4_OFFSET) +# define AT32_TIM20_BDTR (AT32_TMR20_BASE+AT32_ATIM_BDTR_OFFSET) +# define AT32_TIM20_DCR (AT32_TMR20_BASE+AT32_ATIM_DCR_OFFSET) +# define AT32_TIM20_DMAR (AT32_TMR20_BASE+AT32_ATIM_DMAR_OFFSET) +# define AT32_TIM20_CCMR3 (AT32_TMR20_BASE+AT32_ATIM_CCMR3_OFFSET) +# define AT32_TIM20_CCR5 (AT32_TMR20_BASE+AT32_ATIM_CCR5_OFFSET) +#endif + +/* 16-/32-bit General Timers - TIM2, TIM3, TIM4, and TIM5 with DMA. */ + +#if AT32_NGTIM > 0 +# define AT32_TIM2_CR1 (AT32_TMR2_BASE+AT32_GTIM_CR1_OFFSET) +# define AT32_TIM2_CR2 (AT32_TMR2_BASE+AT32_GTIM_CR2_OFFSET) +# define AT32_TIM2_SMCR (AT32_TMR2_BASE+AT32_GTIM_SMCR_OFFSET) +# define AT32_TIM2_DIER (AT32_TMR2_BASE+AT32_GTIM_DIER_OFFSET) +# define AT32_TIM2_SR (AT32_TMR2_BASE+AT32_GTIM_SR_OFFSET) +# define AT32_TIM2_EGR (AT32_TMR2_BASE+AT32_GTIM_EGR_OFFSET) +# define AT32_TIM2_CCMR1 (AT32_TMR2_BASE+AT32_GTIM_CCMR1_OFFSET) +# define AT32_TIM2_CCMR2 (AT32_TMR2_BASE+AT32_GTIM_CCMR2_OFFSET) +# define AT32_TIM2_CCER (AT32_TMR2_BASE+AT32_GTIM_CCER_OFFSET) +# define AT32_TIM2_CNT (AT32_TMR2_BASE+AT32_GTIM_CNT_OFFSET) +# define AT32_TIM2_PSC (AT32_TMR2_BASE+AT32_GTIM_PSC_OFFSET) +# define AT32_TIM2_ARR (AT32_TMR2_BASE+AT32_GTIM_ARR_OFFSET) +# define AT32_TIM2_CCR1 (AT32_TMR2_BASE+AT32_GTIM_CCR1_OFFSET) +# define AT32_TIM2_CCR2 (AT32_TMR2_BASE+AT32_GTIM_CCR2_OFFSET) +# define AT32_TIM2_CCR3 (AT32_TMR2_BASE+AT32_GTIM_CCR3_OFFSET) +# define AT32_TIM2_CCR4 (AT32_TMR2_BASE+AT32_GTIM_CCR4_OFFSET) +# define AT32_TIM2_DCR (AT32_TMR2_BASE+AT32_GTIM_DCR_OFFSET) +# define AT32_TIM2_DMAR (AT32_TMR2_BASE+AT32_GTIM_DMAR_OFFSET) +# if defined(CONFIG_AT32_AT32F43XX) +# define AT32_TIM2_OR (AT32_TMR2_BASE+AT32_GTIM_OR_OFFSET) +# endif +#endif + +#if AT32_NGTIM > 1 +# define AT32_TIM3_CR1 (AT32_TMR3_BASE+AT32_GTIM_CR1_OFFSET) +# define AT32_TIM3_CR2 (AT32_TMR3_BASE+AT32_GTIM_CR2_OFFSET) +# define AT32_TIM3_SMCR (AT32_TMR3_BASE+AT32_GTIM_SMCR_OFFSET) +# define AT32_TIM3_DIER (AT32_TMR3_BASE+AT32_GTIM_DIER_OFFSET) +# define AT32_TIM3_SR (AT32_TMR3_BASE+AT32_GTIM_SR_OFFSET) +# define AT32_TIM3_EGR (AT32_TMR3_BASE+AT32_GTIM_EGR_OFFSET) +# define AT32_TIM3_CCMR1 (AT32_TMR3_BASE+AT32_GTIM_CCMR1_OFFSET) +# define AT32_TIM3_CCMR2 (AT32_TMR3_BASE+AT32_GTIM_CCMR2_OFFSET) +# define AT32_TIM3_CCER (AT32_TMR3_BASE+AT32_GTIM_CCER_OFFSET) +# define AT32_TIM3_CNT (AT32_TMR3_BASE+AT32_GTIM_CNT_OFFSET) +# define AT32_TIM3_PSC (AT32_TMR3_BASE+AT32_GTIM_PSC_OFFSET) +# define AT32_TIM3_ARR (AT32_TMR3_BASE+AT32_GTIM_ARR_OFFSET) +# define AT32_TIM3_CCR1 (AT32_TMR3_BASE+AT32_GTIM_CCR1_OFFSET) +# define AT32_TIM3_CCR2 (AT32_TMR3_BASE+AT32_GTIM_CCR2_OFFSET) +# define AT32_TIM3_CCR3 (AT32_TMR3_BASE+AT32_GTIM_CCR3_OFFSET) +# define AT32_TIM3_CCR4 (AT32_TMR3_BASE+AT32_GTIM_CCR4_OFFSET) +# define AT32_TIM3_DCR (AT32_TMR3_BASE+AT32_GTIM_DCR_OFFSET) +# define AT32_TIM3_DMAR (AT32_TMR3_BASE+AT32_GTIM_DMAR_OFFSET) +#endif + +#if AT32_NGTIM > 2 +# define AT32_TIM4_CR1 (AT32_TMR4_BASE+AT32_GTIM_CR1_OFFSET) +# define AT32_TIM4_CR2 (AT32_TMR4_BASE+AT32_GTIM_CR2_OFFSET) +# define AT32_TIM4_SMCR (AT32_TMR4_BASE+AT32_GTIM_SMCR_OFFSET) +# define AT32_TIM4_DIER (AT32_TMR4_BASE+AT32_GTIM_DIER_OFFSET) +# define AT32_TIM4_SR (AT32_TMR4_BASE+AT32_GTIM_SR_OFFSET) +# define AT32_TIM4_EGR (AT32_TMR4_BASE+AT32_GTIM_EGR_OFFSET) +# define AT32_TIM4_CCMR1 (AT32_TMR4_BASE+AT32_GTIM_CCMR1_OFFSET) +# define AT32_TIM4_CCMR2 (AT32_TMR4_BASE+AT32_GTIM_CCMR2_OFFSET) +# define AT32_TIM4_CCER (AT32_TMR4_BASE+AT32_GTIM_CCER_OFFSET) +# define AT32_TIM4_CNT (AT32_TMR4_BASE+AT32_GTIM_CNT_OFFSET) +# define AT32_TIM4_PSC (AT32_TMR4_BASE+AT32_GTIM_PSC_OFFSET) +# define AT32_TIM4_ARR (AT32_TMR4_BASE+AT32_GTIM_ARR_OFFSET) +# define AT32_TIM4_CCR1 (AT32_TMR4_BASE+AT32_GTIM_CCR1_OFFSET) +# define AT32_TIM4_CCR2 (AT32_TMR4_BASE+AT32_GTIM_CCR2_OFFSET) +# define AT32_TIM4_CCR3 (AT32_TMR4_BASE+AT32_GTIM_CCR3_OFFSET) +# define AT32_TIM4_CCR4 (AT32_TMR4_BASE+AT32_GTIM_CCR4_OFFSET) +# define AT32_TIM4_DCR (AT32_TMR4_BASE+AT32_GTIM_DCR_OFFSET) +# define AT32_TIM4_DMAR (AT32_TMR4_BASE+AT32_GTIM_DMAR_OFFSET) +#endif + +#if AT32_NGTIM > 3 +# define AT32_TIM5_CR1 (AT32_TMR5_BASE+AT32_GTIM_CR1_OFFSET) +# define AT32_TIM5_CR2 (AT32_TMR5_BASE+AT32_GTIM_CR2_OFFSET) +# define AT32_TIM5_SMCR (AT32_TMR5_BASE+AT32_GTIM_SMCR_OFFSET) +# define AT32_TIM5_DIER (AT32_TMR5_BASE+AT32_GTIM_DIER_OFFSET) +# define AT32_TIM5_SR (AT32_TMR5_BASE+AT32_GTIM_SR_OFFSET) +# define AT32_TIM5_EGR (AT32_TMR5_BASE+AT32_GTIM_EGR_OFFSET) +# define AT32_TIM5_CCMR1 (AT32_TMR5_BASE+AT32_GTIM_CCMR1_OFFSET) +# define AT32_TIM5_CCMR2 (AT32_TMR5_BASE+AT32_GTIM_CCMR2_OFFSET) +# define AT32_TIM5_CCER (AT32_TMR5_BASE+AT32_GTIM_CCER_OFFSET) +# define AT32_TIM5_CNT (AT32_TMR5_BASE+AT32_GTIM_CNT_OFFSET) +# define AT32_TIM5_PSC (AT32_TMR5_BASE+AT32_GTIM_PSC_OFFSET) +# define AT32_TIM5_ARR (AT32_TMR5_BASE+AT32_GTIM_ARR_OFFSET) +# define AT32_TIM5_CCR1 (AT32_TMR5_BASE+AT32_GTIM_CCR1_OFFSET) +# define AT32_TIM5_CCR2 (AT32_TMR5_BASE+AT32_GTIM_CCR2_OFFSET) +# define AT32_TIM5_CCR3 (AT32_TMR5_BASE+AT32_GTIM_CCR3_OFFSET) +# define AT32_TIM5_CCR4 (AT32_TMR5_BASE+AT32_GTIM_CCR4_OFFSET) +# define AT32_TIM5_DCR (AT32_TMR5_BASE+AT32_GTIM_DCR_OFFSET) +# define AT32_TIM5_DMAR (AT32_TMR5_BASE+AT32_GTIM_DMAR_OFFSET) +# if defined(CONFIG_AT32_AT32F43XX) +# define AT32_TIM5_OR (AT32_TMR5_BASE+AT32_GTIM_OR_OFFSET) +# endif +#endif + +/* 16-bit General Timers - TIM9-14 without DMA. Note that (1) these timers + * support only a subset of the general timer registers are supported, and + * (2) TIM9 and TIM12 differ from the others. + */ + +#if AT32_NGTIMNDMA > 0 +# define AT32_TIM9_CR1 (AT32_TMR9_BASE+AT32_GTIM_CR1_OFFSET) +# define AT32_TIM9_CR2 (AT32_TMR9_BASE+AT32_GTIM_CR2_OFFSET) +# define AT32_TIM9_DIER (AT32_TMR9_BASE+AT32_GTIM_DIER_OFFSET) +# define AT32_TIM9_SR (AT32_TMR9_BASE+AT32_GTIM_SR_OFFSET) +# define AT32_TIM9_EGR (AT32_TMR9_BASE+AT32_GTIM_EGR_OFFSET) +# define AT32_TIM9_CCMR1 (AT32_TMR9_BASE+AT32_GTIM_CCMR1_OFFSET) +# define AT32_TIM9_CCER (AT32_TMR9_BASE+AT32_GTIM_CCER_OFFSET) +# define AT32_TIM9_CNT (AT32_TMR9_BASE+AT32_GTIM_CNT_OFFSET) +# define AT32_TIM9_PSC (AT32_TMR9_BASE+AT32_GTIM_PSC_OFFSET) +# define AT32_TIM9_ARR (AT32_TMR9_BASE+AT32_GTIM_ARR_OFFSET) +# define AT32_TIM9_CCR1 (AT32_TMR9_BASE+AT32_GTIM_CCR1_OFFSET) +# define AT32_TIM9_CCR2 (AT32_TMR9_BASE+AT32_GTIM_CCR2_OFFSET) +#endif + +#if AT32_NGTIMNDMA > 1 +# define AT32_TIM10_CR1 (AT32_TMR10_BASE+AT32_GTIM_CR1_OFFSET) +# define AT32_TIM10_DIER (AT32_TMR10_BASE+AT32_GTIM_DIER_OFFSET) +# define AT32_TIM10_SR (AT32_TMR10_BASE+AT32_GTIM_SR_OFFSET) +# define AT32_TIM10_EGR (AT32_TMR10_BASE+AT32_GTIM_EGR_OFFSET) +# define AT32_TIM10_CCMR1 (AT32_TMR10_BASE+AT32_GTIM_CCMR1_OFFSET) +# define AT32_TIM10_CCER (AT32_TMR10_BASE+AT32_GTIM_CCER_OFFSET) +# define AT32_TIM10_CNT (AT32_TMR10_BASE+AT32_GTIM_CNT_OFFSET) +# define AT32_TIM10_PSC (AT32_TMR10_BASE+AT32_GTIM_PSC_OFFSET) +# define AT32_TIM10_ARR (AT32_TMR10_BASE+AT32_GTIM_ARR_OFFSET) +# define AT32_TIM10_CCR1 (AT32_TMR10_BASE+AT32_GTIM_CCR1_OFFSET) +#endif + +#if AT32_NGTIMNDMA > 2 +# define AT32_TIM11_CR1 (AT32_TMR11_BASE+AT32_GTIM_CR1_OFFSET) +# define AT32_TIM11_DIER (AT32_TMR11_BASE+AT32_GTIM_DIER_OFFSET) +# define AT32_TIM11_SR (AT32_TMR11_BASE+AT32_GTIM_SR_OFFSET) +# define AT32_TIM11_EGR (AT32_TMR11_BASE+AT32_GTIM_EGR_OFFSET) +# define AT32_TIM11_CCMR1 (AT32_TMR11_BASE+AT32_GTIM_CCMR1_OFFSET) +# define AT32_TIM11_CCER (AT32_TMR11_BASE+AT32_GTIM_CCER_OFFSET) +# define AT32_TIM11_CNT (AT32_TMR11_BASE+AT32_GTIM_CNT_OFFSET) +# define AT32_TIM11_PSC (AT32_TMR11_BASE+AT32_GTIM_PSC_OFFSET) +# define AT32_TIM11_ARR (AT32_TMR11_BASE+AT32_GTIM_ARR_OFFSET) +# define AT32_TIM11_CCR1 (AT32_TMR11_BASE+AT32_GTIM_CCR1_OFFSET) +# define AT32_TIM11_OR (AT32_TMR11_BASE+AT32_GTIM_OR_OFFSET) +#endif + +#if AT32_NGTIMNDMA > 3 +# define AT32_TIM12_CR1 (AT32_TMR12_BASE+AT32_GTIM_CR1_OFFSET) +# define AT32_TIM12_CR2 (AT32_TMR12_BASE+AT32_GTIM_CR2_OFFSET) +# define AT32_TIM12_DIER (AT32_TMR12_BASE+AT32_GTIM_DIER_OFFSET) +# define AT32_TIM12_SR (AT32_TMR12_BASE+AT32_GTIM_SR_OFFSET) +# define AT32_TIM12_EGR (AT32_TMR12_BASE+AT32_GTIM_EGR_OFFSET) +# define AT32_TIM12_CCMR1 (AT32_TMR12_BASE+AT32_GTIM_CCMR1_OFFSET) +# define AT32_TIM12_CCER (AT32_TMR12_BASE+AT32_GTIM_CCER_OFFSET) +# define AT32_TIM12_CNT (AT32_TMR12_BASE+AT32_GTIM_CNT_OFFSET) +# define AT32_TIM12_PSC (AT32_TMR12_BASE+AT32_GTIM_PSC_OFFSET) +# define AT32_TIM12_ARR (AT32_TMR12_BASE+AT32_GTIM_ARR_OFFSET) +# define AT32_TIM12_CCR1 (AT32_TMR12_BASE+AT32_GTIM_CCR1_OFFSET) +# define AT32_TIM12_CCR2 (AT32_TMR12_BASE+AT32_GTIM_CCR2_OFFSET) +#endif + +#if AT32_NGTIMNDMA > 4 +# define AT32_TIM13_CR1 (AT32_TMR13_BASE+AT32_GTIM_CR1_OFFSET) +# define AT32_TIM13_DIER (AT32_TMR13_BASE+AT32_GTIM_DIER_OFFSET) +# define AT32_TIM13_SR (AT32_TMR13_BASE+AT32_GTIM_SR_OFFSET) +# define AT32_TIM13_EGR (AT32_TMR13_BASE+AT32_GTIM_EGR_OFFSET) +# define AT32_TIM13_CCMR1 (AT32_TMR13_BASE+AT32_GTIM_CCMR1_OFFSET) +# define AT32_TIM13_CCER (AT32_TMR13_BASE+AT32_GTIM_CCER_OFFSET) +# define AT32_TIM13_CNT (AT32_TMR13_BASE+AT32_GTIM_CNT_OFFSET) +# define AT32_TIM13_PSC (AT32_TMR13_BASE+AT32_GTIM_PSC_OFFSET) +# define AT32_TIM13_ARR (AT32_TMR13_BASE+AT32_GTIM_ARR_OFFSET) +# define AT32_TIM13_CCR1 (AT32_TMR13_BASE+AT32_GTIM_CCR1_OFFSET) +#endif + +#if AT32_NGTIMNDMA > 5 +# define AT32_TIM14_CR1 (AT32_TMR14_BASE+AT32_GTIM_CR1_OFFSET) +# define AT32_TIM14_DIER (AT32_TMR14_BASE+AT32_GTIM_DIER_OFFSET) +# define AT32_TIM14_SR (AT32_TMR14_BASE+AT32_GTIM_SR_OFFSET) +# define AT32_TIM14_EGR (AT32_TMR14_BASE+AT32_GTIM_EGR_OFFSET) +# define AT32_TIM14_CCMR1 (AT32_TMR14_BASE+AT32_GTIM_CCMR1_OFFSET) +# define AT32_TIM14_CCER (AT32_TMR14_BASE+AT32_GTIM_CCER_OFFSET) +# define AT32_TIM14_CNT (AT32_TMR14_BASE+AT32_GTIM_CNT_OFFSET) +# define AT32_TIM14_PSC (AT32_TMR14_BASE+AT32_GTIM_PSC_OFFSET) +# define AT32_TIM14_ARR (AT32_TMR14_BASE+AT32_GTIM_ARR_OFFSET) +# define AT32_TIM14_CCR1 (AT32_TMR14_BASE+AT32_GTIM_CCR1_OFFSET) +#endif + +/* Basic Timers - TIM6 and TIM7 */ + +#if AT32_NBTIM > 0 +# define AT32_TIM6_CR1 (AT32_TMR6_BASE+AT32_BTIM_CR1_OFFSET) +# define AT32_TIM6_CR2 (AT32_TMR6_BASE+AT32_BTIM_CR2_OFFSET) +# define AT32_TIM6_DIER (AT32_TMR6_BASE+AT32_BTIM_DIER_OFFSET) +# define AT32_TIM6_SR (AT32_TMR6_BASE+AT32_BTIM_SR_OFFSET) +# define AT32_TIM6_EGR (AT32_TMR6_BASE+AT32_BTIM_EGR_OFFSET) +# define AT32_TIM6_CNT (AT32_TMR6_BASE+AT32_BTIM_CNT_OFFSET) +# define AT32_TIM6_PSC (AT32_TMR6_BASE+AT32_BTIM_PSC_OFFSET) +# define AT32_TIM6_ARR (AT32_TMR6_BASE+AT32_BTIM_ARR_OFFSET) +#endif + +#if AT32_NBTIM > 1 +# define AT32_TIM7_CR1 (AT32_TMR7_BASE+AT32_BTIM_CR1_OFFSET) +# define AT32_TIM7_CR2 (AT32_TMR7_BASE+AT32_BTIM_CR2_OFFSET) +# define AT32_TIM7_DIER (AT32_TMR7_BASE+AT32_BTIM_DIER_OFFSET) +# define AT32_TIM7_SR (AT32_TMR7_BASE+AT32_BTIM_SR_OFFSET) +# define AT32_TIM7_EGR (AT32_TMR7_BASE+AT32_BTIM_EGR_OFFSET) +# define AT32_TIM7_CNT (AT32_TMR7_BASE+AT32_BTIM_CNT_OFFSET) +# define AT32_TIM7_PSC (AT32_TMR7_BASE+AT32_BTIM_PSC_OFFSET) +# define AT32_TIM7_ARR (AT32_TMR7_BASE+AT32_BTIM_ARR_OFFSET) +#endif + +/* Register Bitfield Definitions ********************************************/ + +/* Control register 1 */ + +#define ATIM_CR1_CEN (1 << 0) /* Bit 0: Counter enable */ +#define ATIM_CR1_UDIS (1 << 1) /* Bit 1: Update disable */ +#define ATIM_CR1_URS (1 << 2) /* Bit 2: Update request source */ +#define ATIM_CR1_OPM (1 << 3) /* Bit 3: One pulse mode */ +#define ATIM_CR1_DIR (1 << 4) /* Bit 4: Direction */ +#define ATIM_CR1_CMS_SHIFT (5) /* Bits 6-5: Center-aligned mode selection */ +#define ATIM_CR1_CMS_MASK (3 << ATIM_CR1_CMS_SHIFT) +# define ATIM_CR1_EDGE (0 << ATIM_CR1_CMS_SHIFT) /* 00: Edge-aligned mode */ +# define ATIM_CR1_CENTER1 (1 << ATIM_CR1_CMS_SHIFT) /* 01: Center-aligned mode 1 */ +# define ATIM_CR1_CENTER2 (2 << ATIM_CR1_CMS_SHIFT) /* 10: Center-aligned mode 2 */ +# define ATIM_CR1_CENTER3 (3 << ATIM_CR1_CMS_SHIFT) /* 11: Center-aligned mode 3 */ +#define ATIM_CR1_ARPE (1 << 7) /* Bit 7: Auto-reload preload enable */ +#define ATIM_CR1_CKD_SHIFT (8) /* Bits 9-8: Clock division */ +#define ATIM_CR1_CKD_MASK (3 << ATIM_CR1_CKD_SHIFT) +# define ATIM_CR1_TCKINT (0 << ATIM_CR1_CKD_SHIFT) /* 00: tDTS=tCK_INT */ +# define ATIM_CR1_2TCKINT (1 << ATIM_CR1_CKD_SHIFT) /* 01: tDTS=2*tCK_INT */ +# define ATIM_CR1_4TCKINT (2 << ATIM_CR1_CKD_SHIFT) /* 10: tDTS=4*tCK_INT */ + +/* Control register 2 */ + +#define ATIM_CR2_CCPC (1 << 0) /* Bit 0: Capture/Compare Preloaded Control */ +#define ATIM_CR2_CCUS (1 << 2) /* Bit 2: Capture/Compare Control Update Selection */ +#define ATIM_CR2_CCDS (1 << 3) /* Bit 3: Capture/Compare DMA Selection */ +#define ATIM_CR2_MMS_SHIFT (4) /* Bits 6-4: Master Mode Selection */ +#define ATIM_CR2_MMS_MASK (7 << ATIM_CR2_MMS_SHIFT) +# define ATIM_CR2_MMS_RESET (0 << ATIM_CR2_MMS_SHIFT) /* 000: Reset - TIMx_EGR UG bit is TRGO */ +# define ATIM_CR2_MMS_ENABLE (1 << ATIM_CR2_MMS_SHIFT) /* 001: Enable - CNT_EN is TRGO */ +# define ATIM_CR2_MMS_UPDATE (2 << ATIM_CR2_MMS_SHIFT) /* 010: Update event is TRGO */ +# define ATIM_CR2_MMS_COMPP (3 << ATIM_CR2_MMS_SHIFT) /* 010: Compare Pulse - CC1IF flag */ +# define ATIM_CR2_MMS_OC1REF (4 << ATIM_CR2_MMS_SHIFT) /* 100: Compare OC1REF is TRGO */ +# define ATIM_CR2_MMS_OC2REF (5 << ATIM_CR2_MMS_SHIFT) /* 101: Compare OC2REF is TRGO */ +# define ATIM_CR2_MMS_OC3REF (6 << ATIM_CR2_MMS_SHIFT) /* 110: Compare OC3REF is TRGO */ +# define ATIM_CR2_MMS_OC4REF (7 << ATIM_CR2_MMS_SHIFT) /* 111: Compare OC4REF is TRGO */ +#define ATIM_CR2_TI1S (1 << 7) /* Bit 7: TI1 Selection */ +#define ATIM_CR2_OIS1 (1 << 8) /* Bit 8: Output Idle state 1 (OC1 output) */ +#define ATIM_CR2_OIS1N (1 << 9) /* Bit 9: Output Idle state 1 (OC1N output) */ +#define ATIM_CR2_OIS2 (1 << 10) /* Bit 10: Output Idle state 2 (OC2 output) */ +#define ATIM_CR2_OIS2N (1 << 11) /* Bit 11: Output Idle state 2 (OC2N output) */ +#define ATIM_CR2_OIS3 (1 << 12) /* Bit 12: Output Idle state 3 (OC3 output) */ +#define ATIM_CR2_OIS3N (1 << 13) /* Bit 13: Output Idle state 3 (OC3N output) */ +#define ATIM_CR2_OIS4 (1 << 14) /* Bit 14: Output Idle state 4 (OC4 output) */ + +#define ATIM_CR2_TRGOUT2EN (1 << 31) /* TRGOUT2 enable */ + +/* Slave mode control register */ + +#define ATIM_SMCR_SMS_SHIFT (0) /* Bits 0-2: Slave mode selection */ +#define ATIM_SMCR_SMS_MASK (7 << ATIM_SMCR_SMS_SHIFT) +# define ATIM_SMCR_DISAB (0 << ATIM_SMCR_SMS_SHIFT) /* 000: Slave mode disabled */ +# define ATIM_SMCR_ENCMD1 (1 << ATIM_SMCR_SMS_SHIFT) /* 001: Encoder mode 1 */ +# define ATIM_SMCR_ENCMD2 (2 << ATIM_SMCR_SMS_SHIFT) /* 010: Encoder mode 2 */ +# define ATIM_SMCR_ENCMD3 (3 << ATIM_SMCR_SMS_SHIFT) /* 011: Encoder mode 3 */ +# define ATIM_SMCR_RESET (4 << ATIM_SMCR_SMS_SHIFT) /* 100: Reset Mode */ +# define ATIM_SMCR_GATED (5 << ATIM_SMCR_SMS_SHIFT) /* 101: Gated Mode */ +# define ATIM_SMCR_TRIGGER (6 << ATIM_SMCR_SMS_SHIFT) /* 110: Trigger Mode */ +# define ATIM_SMCR_EXTCLK1 (7 << ATIM_SMCR_SMS_SHIFT) /* 111: External Clock Mode 1 */ + +#define ATIM_SMCR_TS_SHIFT (4) /* Bits 4-6: Trigger selection */ +#define ATIM_SMCR_TS_MASK (7 << ATIM_SMCR_TS_SHIFT) +# define ATIM_SMCR_ITR0 (0 << ATIM_SMCR_TS_SHIFT) /* 000: Internal trigger 0 (ITR0) */ +# define ATIM_SMCR_ITR1 (1 << ATIM_SMCR_TS_SHIFT) /* 001: Internal trigger 1 (ITR1) */ +# define ATIM_SMCR_ITR2 (2 << ATIM_SMCR_TS_SHIFT) /* 010: Internal trigger 2 (ITR2) */ +# define ATIM_SMCR_ITR3 (3 << ATIM_SMCR_TS_SHIFT) /* 011: Internal trigger 3 (ITR3) */ +# define ATIM_SMCR_T1FED (4 << ATIM_SMCR_TS_SHIFT) /* 100: TI1 Edge Detector (TI1F_ED) */ +# define ATIM_SMCR_TI1FP1 (5 << ATIM_SMCR_TS_SHIFT) /* 101: Filtered Timer Input 1 (TI1FP1) */ +# define ATIM_SMCR_T12FP2 (6 << ATIM_SMCR_TS_SHIFT) /* 110: Filtered Timer Input 2 (TI2FP2) */ +# define ATIM_SMCR_ETRF (7 << ATIM_SMCR_TS_SHIFT) /* 111: External Trigger input (ETRF) */ +#define ATIM_SMCR_MSM (1 << 7) /* Bit 7: Master/slave mode */ +#define ATIM_SMCR_ETF_SHIFT (8) /* Bits 8-11: External trigger filter */ +#define ATIM_SMCR_ETF_MASK (0x0f << ATIM_SMCR_ETF_SHIFT) +# define ATIM_SMCR_NOFILT (0 << ATIM_SMCR_ETF_SHIFT) /* 0000: No filter, sampling is done at fDTS */ +# define ATIM_SMCR_FCKINT2 (1 << ATIM_SMCR_ETF_SHIFT) /* 0001: fSAMPLING=fCK_INT, N=2 */ +# define ATIM_SMCR_FCKINT4 (2 << ATIM_SMCR_ETF_SHIFT) /* 0010: fSAMPLING=fCK_INT, N=4 */ +# define ATIM_SMCR_FCKINT8 (3 << ATIM_SMCR_ETF_SHIFT) /* 0011: fSAMPLING=fCK_INT, N=8 */ +# define ATIM_SMCR_FDTSd26 (4 << ATIM_SMCR_ETF_SHIFT) /* 0100: fSAMPLING=fDTS/2, N=6 */ +# define ATIM_SMCR_FDTSd28 (5 << ATIM_SMCR_ETF_SHIFT) /* 0101: fSAMPLING=fDTS/2, N=8 */ +# define ATIM_SMCR_FDTSd46 (6 << ATIM_SMCR_ETF_SHIFT) /* 0110: fSAMPLING=fDTS/4, N=6 */ +# define ATIM_SMCR_FDTSd48 (7 << ATIM_SMCR_ETF_SHIFT) /* 0111: fSAMPLING=fDTS/4, N=8 */ +# define ATIM_SMCR_FDTSd86 (8 << ATIM_SMCR_ETF_SHIFT) /* 1000: fSAMPLING=fDTS/8, N=6 */ +# define ATIM_SMCR_FDTSd88 (9 << ATIM_SMCR_ETF_SHIFT) /* 1001: fSAMPLING=fDTS/8, N=8 */ +# define ATIM_SMCR_FDTSd165 (10 << ATIM_SMCR_ETF_SHIFT) /* 1010: fSAMPLING=fDTS/16, N=5 */ +# define ATIM_SMCR_FDTSd166 (11 << ATIM_SMCR_ETF_SHIFT) /* 1011: fSAMPLING=fDTS/16, N=6 */ +# define ATIM_SMCR_FDTSd168 (12 << ATIM_SMCR_ETF_SHIFT) /* 1100: fSAMPLING=fDTS/16, N=8 */ +# define ATIM_SMCR_FDTSd325 (13 << ATIM_SMCR_ETF_SHIFT) /* 1101: fSAMPLING=fDTS/32, N=5 */ +# define ATIM_SMCR_FDTSd326 (14 << ATIM_SMCR_ETF_SHIFT) /* 1110: fSAMPLING=fDTS/32, N=6 */ +# define ATIM_SMCR_FDTSd328 (15 << ATIM_SMCR_ETF_SHIFT) /* 1111: fSAMPLING=fDTS/32, N=8 */ +#define ATIM_SMCR_ETPS_SHIFT (12) /* Bits 12-13: External trigger prescaler */ +#define ATIM_SMCR_ETPS_MASK (3 << ATIM_SMCR_ETPS_SHIFT) +# define ATIM_SMCR_PSCOFF (0 << ATIM_SMCR_ETPS_SHIFT) /* 00: Prescaler OFF */ +# define ATIM_SMCR_ETRPd2 (1 << ATIM_SMCR_ETPS_SHIFT) /* 01: ETRP frequency divided by 2 */ +# define ATIM_SMCR_ETRPd4 (2 << ATIM_SMCR_ETPS_SHIFT) /* 10: ETRP frequency divided by 4 */ +# define ATIM_SMCR_ETRPd8 (3 << ATIM_SMCR_ETPS_SHIFT) /* 11: ETRP frequency divided by 8 */ +#define ATIM_SMCR_ECE (1 << 14) /* Bit 14: External clock enable */ +#define ATIM_SMCR_ETP (1 << 15) /* Bit 15: External trigger polarity */ + +/* DMA/Interrupt enable register */ + +#define ATIM_DIER_UIE (1 << 0) /* Bit 0: Update interrupt enable */ +#define ATIM_DIER_CC1IE (1 << 1) /* Bit 1: Capture/Compare 1 interrupt enable */ +#define ATIM_DIER_CC2IE (1 << 2) /* Bit 2: Capture/Compare 2 interrupt enable */ +#define ATIM_DIER_CC3IE (1 << 3) /* Bit 3: Capture/Compare 3 interrupt enable */ +#define ATIM_DIER_CC4IE (1 << 4) /* Bit 4: Capture/Compare 4 interrupt enable */ +#define ATIM_DIER_COMIE (1 << 5) /* Bit 5: COM interrupt enable */ +#define ATIM_DIER_TIE (1 << 6) /* Bit 6: Trigger interrupt enable */ +#define ATIM_DIER_BIE (1 << 7) /* Bit 7: Break interrupt enable */ +#define ATIM_DIER_UDE (1 << 8) /* Bit 8: Update DMA request enable */ +#define ATIM_DIER_CC1DE (1 << 9) /* Bit 9: Capture/Compare 1 DMA request enable */ +#define ATIM_DIER_CC2DE (1 << 10) /* Bit 10: Capture/Compare 2 DMA request enable */ +#define ATIM_DIER_CC3DE (1 << 11) /* Bit 11: Capture/Compare 3 DMA request enable */ +#define ATIM_DIER_CC4DE (1 << 12) /* Bit 12: Capture/Compare 4 DMA request enable */ +#define ATIM_DIER_COMDE (1 << 13) /* Bit 13: COM DMA request enable */ +#define ATIM_DIER_TDE (1 << 14) /* Bit 14: Trigger DMA request enable */ + +/* Status register */ + +#define ATIM_SR_UIF (1 << 0) /* Bit 0: Update interrupt Flag */ +#define ATIM_SR_CC1IF (1 << 1) /* Bit 1: Capture/Compare 1 interrupt Flag */ +#define ATIM_SR_CC2IF (1 << 2) /* Bit 2: Capture/Compare 2 interrupt Flag */ +#define ATIM_SR_CC3IF (1 << 3) /* Bit 3: Capture/Compare 3 interrupt Flag */ +#define ATIM_SR_CC4IF (1 << 4) /* Bit 4: Capture/Compare 4 interrupt Flag */ +#define ATIM_SR_COMIF (1 << 5) /* Bit 5: COM interrupt Flag */ +#define ATIM_SR_TIF (1 << 6) /* Bit 6: Trigger interrupt Flag */ +#define ATIM_SR_BIF (1 << 7) /* Bit 7: Break interrupt Flag */ +#define ATIM_SR_CC1OF (1 << 9) /* Bit 9: Capture/Compare 1 Overcapture Flag */ +#define ATIM_SR_CC2OF (1 << 10) /* Bit 10: Capture/Compare 2 Overcapture Flag */ +#define ATIM_SR_CC3OF (1 << 11) /* Bit 11: Capture/Compare 3 Overcapture Flag */ +#define ATIM_SR_CC4OF (1 << 12) /* Bit 12: Capture/Compare 4 Overcapture Flag */ + +/* Event generation register */ + +#define ATIM_EGR_UG (1 << 0) /* Bit 0: Update Generation */ +#define ATIM_EGR_CC1G (1 << 1) /* Bit 1: Capture/Compare 1 Generation */ +#define ATIM_EGR_CC2G (1 << 2) /* Bit 2: Capture/Compare 2 Generation */ +#define ATIM_EGR_CC3G (1 << 3) /* Bit 3: Capture/Compare 3 Generation */ +#define ATIM_EGR_CC4G (1 << 4) /* Bit 4: Capture/Compare 4 Generation */ +#define ATIM_EGR_COMG (1 << 5) /* Bit 5: Capture/Compare Control Update Generation */ +#define ATIM_EGR_TG (1 << 6) /* Bit 6: Trigger Generation */ +#define ATIM_EGR_BG (1 << 7) /* Bit 7: Break Generation */ + +/* Capture/compare mode register 1 -- Output compare mode */ + +#define ATIM_CCMR1_CC1S_SHIFT (0) /* Bits 1-0: Capture/Compare 1 Selection */ +#define ATIM_CCMR1_CC1S_MASK (3 << ATIM_CCMR1_CC1S_SHIFT) + /* (See common (unshifted) bit field definitions below) */ +#define ATIM_CCMR1_OC1FE (1 << 2) /* Bit 2: Output Compare 1 Fast enable */ +#define ATIM_CCMR1_OC1PE (1 << 3) /* Bit 3: Output Compare 1 Preload enable */ +#define ATIM_CCMR1_OC1M_SHIFT (4) /* Bits 6-4: Output Compare 1 Mode */ +#define ATIM_CCMR1_OC1M_MASK (7 << ATIM_CCMR1_OC1M_SHIFT) + /* (See common (unshifted) bit field definitions below) */ +#define ATIM_CCMR1_OC1CE (1 << 7) /* Bit 7: Output Compare 1Clear Enable */ +#define ATIM_CCMR1_CC2S_SHIFT (8) /* Bits 8-9: Capture/Compare 2 Selection */ +#define ATIM_CCMR1_CC2S_MASK (3 << ATIM_CCMR1_CC2S_SHIFT) + /* (See common (unshifted) bit field definitions below) */ +#define ATIM_CCMR1_OC2FE (1 << 10) /* Bit 10: Output Compare 2 Fast enable */ +#define ATIM_CCMR1_OC2PE (1 << 11) /* Bit 11: Output Compare 2 Preload enable */ +#define ATIM_CCMR1_OC2M_SHIFT (12) /* Bits 14-12: Output Compare 2 Mode */ +#define ATIM_CCMR1_OC2M_MASK (7 << ATIM_CCMR1_OC2M_SHIFT) + /* (See common (unshifted) bit field definitions below) */ +#define ATIM_CCMR1_OC2CE (1 << 15) /* Bit 15: Output Compare 2 Clear Enable */ + +/* Common CCMR (unshifted) Capture/Compare Selection bit-field definitions */ + +#define ATIM_CCMR_CCS_CCOUT (0) /* 00: CCx channel output */ +#define ATIM_CCMR_CCS_CCIN1 (1) /* 01: CCx channel input, ICx is TIx */ +#define ATIM_CCMR_CCS_CCIN2 (2) /* 10: CCx channel input, ICx is TIy */ +#define ATIM_CCMR_CCS_CCINTRC (3) /* 11: CCx channel input, ICx is TRC */ + +/* Common CCMR (unshifted) Compare Mode bit field definitions */ + +#define ATIM_CCMR_MODE_FRZN (0) /* 000: Frozen */ +#define ATIM_CCMR_MODE_CHACT (1) /* 001: Channel x active on match */ +#define ATIM_CCMR_MODE_CHINACT (2) /* 010: Channel x inactive on match */ +#define ATIM_CCMR_MODE_OCREFTOG (3) /* 011: OCxREF toggle ATIM_CNT=ATIM_CCRx */ +#define ATIM_CCMR_MODE_OCREFLO (4) /* 100: OCxREF forced low */ +#define ATIM_CCMR_MODE_OCREFHI (5) /* 101: OCxREF forced high */ +#define ATIM_CCMR_MODE_PWM1 (6) /* 110: PWM mode 1 */ +#define ATIM_CCMR_MODE_PWM2 (7) /* 111: PWM mode 2 */ + +/* Capture/compare mode register 1 -- Input capture mode */ + +/* Bits 1-0: + * (same as output compare mode) + */ + +#define ATIM_CCMR1_IC1PSC_SHIFT (2) /* Bits 3-2: Input Capture 1 Prescaler */ +#define ATIM_CCMR1_IC1PSC_MASK (3 << ATIM_CCMR1_IC1PSC_SHIFT) + /* (See common (unshifted) bit field definitions below) */ +#define ATIM_CCMR1_IC1F_SHIFT (4) /* Bits 7-4: Input Capture 1 Filter */ +#define ATIM_CCMR1_IC1F_MASK (0x0f << ATIM_CCMR1_IC1F_SHIFT) + /* (See common (unshifted) bit field definitions below) */ + /* Bits 9:8 (same as output compare mode) */ +#define ATIM_CCMR1_IC2PSC_SHIFT (10) /* Bits 11:10: Input Capture 2 Prescaler */ +#define ATIM_CCMR1_IC2PSC_MASK (3 << ATIM_CCMR1_IC2PSC_SHIFT) + /* (See common (unshifted) bit field definitions below) */ +#define ATIM_CCMR1_IC2F_SHIFT (12) /* Bits 15-12: Input Capture 2 Filter */ +#define ATIM_CCMR1_IC2F_MASK (0x0f << ATIM_CCMR1_IC2F_SHIFT) + /* (See common (unshifted) bit field definitions below) */ + +/* Common CCMR (unshifted) Input Capture Prescaler bit-field definitions */ + +#define ATIM_CCMR_ICPSC_NOPSC (0) /* 00: no prescaler, capture each edge */ +#define ATIM_CCMR_ICPSC_EVENTS2 (1) /* 01: capture once every 2 events */ +#define ATIM_CCMR_ICPSC_EVENTS4 (2) /* 10: capture once every 4 events */ +#define ATIM_CCMR_ICPSC_EVENTS8 (3) /* 11: capture once every 8 events */ + +/* Common CCMR (unshifted) Input Capture Filter bit-field definitions */ + +#define ATIM_CCMR_ICF_NOFILT (0) /* 0000: No filter, sampling at fDTS */ +#define ATIM_CCMR_ICF_FCKINT2 (1) /* 0001: fSAMPLING=fCK_INT, N=2 */ +#define ATIM_CCMR_ICF_FCKINT4 (2) /* 0010: fSAMPLING=fCK_INT, N=4 */ +#define ATIM_CCMR_ICF_FCKINT8 (3) /* 0011: fSAMPLING=fCK_INT, N=8 */ +#define ATIM_CCMR_ICF_FDTSd26 (4) /* 0100: fSAMPLING=fDTS/2, N=6 */ +#define ATIM_CCMR_ICF_FDTSd28 (5) /* 0101: fSAMPLING=fDTS/2, N=8 */ +#define ATIM_CCMR_ICF_FDTSd46 (6) /* 0110: fSAMPLING=fDTS/4, N=6 */ +#define ATIM_CCMR_ICF_FDTSd48 (7) /* 0111: fSAMPLING=fDTS/4, N=8 */ +#define ATIM_CCMR_ICF_FDTSd86 (8) /* 1000: fSAMPLING=fDTS/8, N=6 */ +#define ATIM_CCMR_ICF_FDTSd88 (9) /* 1001: fSAMPLING=fDTS/8, N=8 */ +#define ATIM_CCMR_ICF_FDTSd165 (10) /* 1010: fSAMPLING=fDTS/16, N=5 */ +#define ATIM_CCMR_ICF_FDTSd166 (11) /* 1011: fSAMPLING=fDTS/16, N=6 */ +#define ATIM_CCMR_ICF_FDTSd168 (12) /* 1100: fSAMPLING=fDTS/16, N=8 */ +#define ATIM_CCMR_ICF_FDTSd325 (13) /* 1101: fSAMPLING=fDTS/32, N=5 */ +#define ATIM_CCMR_ICF_FDTSd326 (14) /* 1110: fSAMPLING=fDTS/32, N=6 */ +#define ATIM_CCMR_ICF_FDTSd328 (15) /* 1111: fSAMPLING=fDTS/32, N=8 */ + +/* Capture/compare mode register 2 - Output Compare mode */ + +#define ATIM_CCMR2_CC3S_SHIFT (0) /* Bits 1-0: Capture/Compare 3 Selection */ +#define ATIM_CCMR2_CC3S_MASK (3 << ATIM_CCMR2_CC3S_SHIFT) + /* (See common (unshifted) bit field definitions above) */ +#define ATIM_CCMR2_OC3FE (1 << 2) /* Bit 2: Output Compare 3 Fast enable */ +#define ATIM_CCMR2_OC3PE (1 << 3) /* Bit 3: Output Compare 3 Preload enable */ +#define ATIM_CCMR2_OC3M_SHIFT (4) /* Bits 6-4: Output Compare 3 Mode */ +#define ATIM_CCMR2_OC3M_MASK (7 << ATIM_CCMR2_OC3M_SHIFT) + /* (See common (unshifted) bit field definitions above) */ +#define ATIM_CCMR2_OC3CE (1 << 7) /* Bit 7: Output Compare 3 Clear Enable */ +#define ATIM_CCMR2_CC4S_SHIFT (8) /* Bits 9-8: Capture/Compare 4 Selection */ +#define ATIM_CCMR2_CC4S_MASK (3 << ATIM_CCMR2_CC4S_SHIFT) + /* (See common (unshifted) bit field definitions above) */ +#define ATIM_CCMR2_OC4FE (1 << 10) /* Bit 10: Output Compare 4 Fast enable */ +#define ATIM_CCMR2_OC4PE (1 << 11) /* Bit 11: Output Compare 4 Preload enable */ +#define ATIM_CCMR2_OC4M_SHIFT (12) /* Bits 14-12: Output Compare 4 Mode */ +#define ATIM_CCMR2_OC4M_MASK (7 << ATIM_CCMR2_OC4M_SHIFT) + /* (See common (unshifted) bit field definitions above) */ +#define ATIM_CCMR2_OC4CE (1 << 15) /* Bit 15: Output Compare 4 Clear Enable */ + +/* Capture/compare mode register 2 - Input Capture Mode */ + +/* Bits 1-0: + * (same as output compare mode) + */ + +#define ATIM_CCMR2_IC3PSC_SHIFT (2) /* Bits 3-2: Input Capture 3 Prescaler */ +#define ATIM_CCMR1_IC3PSC_MASK (3 << ATIM_CCMR2_IC3PSC_SHIFT) + /* (See common (unshifted) bit field definitions above) */ +#define ATIM_CCMR2_IC3F_SHIFT (4) /* Bits 7-4: Input Capture 3 Filter */ +#define ATIM_CCMR2_IC3F_MASK (0x0f << ATIM_CCMR2_IC3F_SHIFT) + /* (See common (unshifted) bit field definitions above) */ + /* Bits 9:8 (same as output compare mode) */ +#define ATIM_CCMR2_IC4PSC_SHIFT (10) /* Bits 11:10: Input Capture 4 Prescaler */ +#define ATIM_CCMR2_IC4PSC_MASK (3 << ATIM_CCMR2_IC4PSC_SHIFT) + /* (See common (unshifted) bit field definitions above) */ +#define ATIM_CCMR2_IC4F_SHIFT (12) /* Bits 15-12: Input Capture 4 Filter */ +#define ATIM_CCMR2_IC4F_MASK (0x0f << ATIM_CCMR2_IC4F_SHIFT) + /* (See common (unshifted) bit field definitions above) */ + +/* Capture/compare mode register 3 -- Output compare mode */ + +#define ATIM_CCMR3_OC5FE (1 << 2) /* Bit 2: Output Compare 5 Fast enable */ +#define ATIM_CCMR3_OC5PE (1 << 3) /* Bit 3: Output Compare 5 Preload enable */ +#define ATIM_CCMR3_OC5M_SHIFT (4) /* Bits 6-4: Output Compare 5 Mode */ +#define ATIM_CCMR3_OC5M_MASK (7 << ATIM_CCMR3_OC5M_SHIFT) + /* (See common (unshifted) bit field definitions below) */ + +#define ATIM_CCMR3_OC5CE (1 << 7) /* Bit 7: Output Compare 5 Clear Enable */ + +/* Capture/compare enable register */ + +#define ATIM_CCER_CC1E (1 << 0) /* Bit 0: Capture/Compare 1 output enable */ +#define ATIM_CCER_CC1P (1 << 1) /* Bit 1: Capture/Compare 1 output Polarity */ +#define ATIM_CCER_CC1NE (1 << 2) /* Bit 2: Capture/Compare 1 Complementary output enable */ +#define ATIM_CCER_CC1NP (1 << 3) /* Bit 3: Capture/Compare 1 Complementary output polarity */ +#define ATIM_CCER_CC2E (1 << 4) /* Bit 4: Capture/Compare 2 output enable */ +#define ATIM_CCER_CC2P (1 << 5) /* Bit 5: Capture/Compare 2 output Polarity */ +#define ATIM_CCER_CC2NE (1 << 6) /* Bit 6: Capture/Compare 2 Complementary output enable */ +#define ATIM_CCER_CC2NP (1 << 7) /* Bit 7: Capture/Compare 2 Complementary output polarity */ +#define ATIM_CCER_CC3E (1 << 8) /* Bit 8: Capture/Compare 3 output enable */ +#define ATIM_CCER_CC3P (1 << 9) /* Bit 9: Capture/Compare 3 output Polarity */ +#define ATIM_CCER_CC3NE (1 << 10) /* Bit 10: Capture/Compare 3 Complementary output enable */ +#define ATIM_CCER_CC3NP (1 << 11) /* Bit 11: Capture/Compare 3 Complementary output polarity */ +#define ATIM_CCER_CC4E (1 << 12) /* Bit 12: Capture/Compare 4 output enable */ +#define ATIM_CCER_CC4P (1 << 13) /* Bit 13: Capture/Compare 4 output Polarity */ + +#define ATIM_CCER_CCXBASE(ch) (ch << 2) /* Each channel uses 4-bits */ + +/* 16-bit counter register */ + +#define ATIM_CNT_SHIFT (0) /* Bits 0-15: Timer counter value */ +#define ATIM_CNT_MASK (0xffff << ATIM_CNT_SHIFT) + +/* Repetition counter register */ + +#define ATIM_RCR_REP_SHIFT (0) /* Bits 0-15: Repetition Counter Value */ +#define ATIM_RCR_REP_MASK (0xffff << ATIM_RCR_REP_SHIFT) +#define ATIM_RCR_REP_MAX 32768 /* REVISIT */ + +/* Capture/compare registers (CCR) */ + +#define ATIM_CCR_MASK (0xffff) + +/* Break and dead-time register */ + +#define ATIM_BDTR_DTG_SHIFT (0) /* Bits 7:0 [7:0]: Dead-Time Generator set-up */ +#define ATIM_BDTR_DTG_MASK (0xff << ATIM_BDTR_DTG_SHIFT) +#define ATIM_BDTR_LOCK_SHIFT (8) /* Bits 9:8 [1:0]: Lock Configuration */ +#define ATIM_BDTR_LOCK_MASK (3 << ATIM_BDTR_LOCK_SHIFT) +# define ATIM_BDTR_LOCKOFF (0 << ATIM_BDTR_LOCK_SHIFT) /* 00: LOCK OFF - No bit is write protected */ +# define ATIM_BDTR_LOCK1 (1 << ATIM_BDTR_LOCK_SHIFT) /* 01: LOCK Level 1 protection */ +# define ATIM_BDTR_LOCK2 (2 << ATIM_BDTR_LOCK_SHIFT) /* 10: LOCK Level 2 protection */ +# define ATIM_BDTR_LOCK3 (3 << ATIM_BDTR_LOCK_SHIFT) /* 11: LOCK Level 3 protection */ */ +#define ATIM_BDTR_OSSI (1 << 10) /* Bit 10: Off-State Selection for Idle mode */ +#define ATIM_BDTR_OSSR (1 << 11) /* Bit 11: Off-State Selection for Run mode */ +#define ATIM_BDTR_BKE (1 << 12) /* Bit 12: Break enable */ +#define ATIM_BDTR_BKP (1 << 13) /* Bit 13: Break Polarity */ +#define ATIM_BDTR_AOE (1 << 14) /* Bit 14: Automatic Output enable */ +#define ATIM_BDTR_MOE (1 << 15) /* Bit 15: Main Output enable */ + +/* DMA control register */ + +#define ATIM_DCR_DBA_SHIFT (0) /* Bits 4-0: DMA Base Address */ +#define ATIM_DCR_DBA_MASK (0x1f << ATIM_DCR_DBA_SHIFT) +#define ATIM_DCR_DBL_SHIFT (8) /* Bits 12-8: DMA Burst Length */ +#define ATIM_DCR_DBL_MASK (0x1f << ATIM_DCR_DBL_SHIFT) +# define ATIM_DCR_DBL(n) (((n)-1) << ATIM_DCR_DBL_SHIFT) /* n transfers, n = 1..18 */ + +/* Control register 1 (TIM2-5 and TIM9-14) */ + +#define GTIM_CR1_CEN (1 << 0) /* Bit 0: Counter enable */ +#define GTIM_CR1_UDIS (1 << 1) /* Bit 1: Update Disable */ +#define GTIM_CR1_URS (1 << 2) /* Bit 2: Update Request Source */ +#define GTIM_CR1_OPM (1 << 3) /* Bit 3: One Pulse Mode (TIM2-5, 9, and 12 only) */ +#define GTIM_CR1_DIR (1 << 4) /* Bit 4: Direction (TIM2-5 only) */ +#define GTIM_CR1_CMS_SHIFT (5) /* Bits 6-5: Center-aligned Mode Selection (TIM2-5 only) */ +#define GTIM_CR1_CMS_MASK (3 << GTIM_CR1_CMS_SHIFT) +# define GTIM_CR1_EDGE (0 << GTIM_CR1_CMS_SHIFT) /* 00: Edge-aligned mode. */ +# define GTIM_CR1_CENTER1 (1 << GTIM_CR1_CMS_SHIFT) /* 01: Center-aligned mode 1 */ +# define GTIM_CR1_CENTER2 (2 << GTIM_CR1_CMS_SHIFT) /* 10: Center-aligned mode 2 */ +# define GTIM_CR1_CENTER3 (3 << GTIM_CR1_CMS_SHIFT) /* 11: Center-aligned mode 3 */ +#define GTIM_CR1_ARPE (1 << 7) /* Bit 7: Auto-Reload Preload enable */ +#define GTIM_CR1_CKD_SHIFT (8) /* Bits 9-8: Clock Division */ +#define GTIM_CR1_CKD_MASK (3 << GTIM_CR1_CKD_SHIFT) +# define GTIM_CR1_TCKINT (0 << GTIM_CR1_CKD_SHIFT) /* 00: tDTS = tCK_INT */ +# define GTIM_CR1_2TCKINT (1 << GTIM_CR1_CKD_SHIFT) /* 01: tDTS = 2 x tCK_INT */ +# define GTIM_CR1_4TCKINT (2 << GTIM_CR1_CKD_SHIFT) /* 10: tDTS = 4 x tCK_INT */ + +/* Control register 2 (TIM2-5, TIM9-12, and TIM15-17 only) */ + +#define GTIM_CR2_CCPC (1 << 0) /* Bit 0: Capture/compare preloaded control (TIM15-17 only) */ +#define GTIM_CR2_CCUS (1 << 2) /* Bit 2: Capture/compare control update selection (TIM15-17 only) */ +#define GTIM_CR2_CCDS (1 << 3) /* Bit 3: Capture/Compare DMA Selection (TIM2-5,1,&16 only) */ +#define GTIM_CR2_MMS_SHIFT (4) /* Bits 6-4: Master Mode Selection (not TIM16) */ +#define GTIM_CR2_MMS_MASK (7 << GTIM_CR2_MMS_SHIFT) +# define GTIM_CR2_MMS_RESET (0 << GTIM_CR2_MMS_SHIFT) /* 000: Reset */ +# define GTIM_CR2_MMS_ENABLE (1 << GTIM_CR2_MMS_SHIFT) /* 001: Enable */ +# define GTIM_CR2_MMS_UPDATE (2 << GTIM_CR2_MMS_SHIFT) /* 010: Update */ +# define GTIM_CR2_MMS_COMPP (3 << GTIM_CR2_MMS_SHIFT) /* 011: Compare Pulse */ +# define GTIM_CR2_MMS_OC1REF (4 << GTIM_CR2_MMS_SHIFT) /* 100: Compare - OC1REF signal is used as trigger output (TRGO) */ +# define GTIM_CR2_MMS_OC2REF (5 << GTIM_CR2_MMS_SHIFT) /* 101: Compare - OC2REF signal is used as trigger output (TRGO) */ +# define GTIM_CR2_MMS_OC3REF (6 << GTIM_CR2_MMS_SHIFT) /* 110: Compare - OC3REF signal is used as trigger output (TRGO, TIM2-5 and TIM15 only) */ +# define GTIM_CR2_MMS_OC4REF (7 << GTIM_CR2_MMS_SHIFT) /* 111: Compare - OC4REF signal is used as trigger output (TRGO, TIM2-5 and TIM15 only) */ +#define GTIM_CR2_TI1S (1 << 7) /* Bit 7: TI1 Selection (not TIM16) */ + +/* Slave mode control register (TIM2-5 and TIM15 only) */ + +#define GTIM_SMCR_SMS_SHIFT (0) /* Bits 2-0: Slave Mode Selection */ +#define GTIM_SMCR_SMS_MASK (7 << GTIM_SMCR_SMS_SHIFT) +# define GTIM_SMCR_DISAB (0 << GTIM_SMCR_SMS_SHIFT) /* 000: Slave mode disabled */ +# define GTIM_SMCR_ENCMD1 (1 << GTIM_SMCR_SMS_SHIFT) /* 001: Encoder mode 1 */ +# define GTIM_SMCR_ENCMD2 (2 << GTIM_SMCR_SMS_SHIFT) /* 010: Encoder mode 2 */ +# define GTIM_SMCR_ENCMD3 (3 << GTIM_SMCR_SMS_SHIFT) /* 011: Encoder mode 3 */ +# define GTIM_SMCR_RESET (4 << GTIM_SMCR_SMS_SHIFT) /* 100: Reset Mode */ +# define GTIM_SMCR_GATED (5 << GTIM_SMCR_SMS_SHIFT) /* 101: Gated Mode */ +# define GTIM_SMCR_TRIGGER (6 << GTIM_SMCR_SMS_SHIFT) /* 110: Trigger Mode */ +# define GTIM_SMCR_EXTCLK1 (7 << GTIM_SMCR_SMS_SHIFT) /* 111: External Clock Mode 1 */ +#define GTIM_SMCR_TS_SHIFT (4) /* Bits 6-4: Trigger Selection */ +#define GTIM_SMCR_TS_MASK (7 << GTIM_SMCR_TS_SHIFT) +# define GTIM_SMCR_ITR0 (0 << GTIM_SMCR_TS_SHIFT) /* 000: Internal Trigger 0 (ITR0). TIM1 */ +# define GTIM_SMCR_ITR1 (1 << GTIM_SMCR_TS_SHIFT) /* 001: Internal Trigger 1 (ITR1). TIM2 */ +# define GTIM_SMCR_ITR2 (2 << GTIM_SMCR_TS_SHIFT) /* 010: Internal Trigger 2 (ITR2). TIM3 */ +# define GTIM_SMCR_ITR3 (3 << GTIM_SMCR_TS_SHIFT) /* 011: Internal Trigger 3 (ITR3). TIM4 */ +# define GTIM_SMCR_TI1FED (4 << GTIM_SMCR_TS_SHIFT) /* 100: TI1 Edge Detector (TI1F_ED) */ +# define GTIM_SMCR_TI1FP1 (5 << GTIM_SMCR_TS_SHIFT) /* 101: Filtered Timer Input 1 (TI1FP1) */ +# define GTIM_SMCR_TI2FP2 (6 << GTIM_SMCR_TS_SHIFT) /* 110: Filtered Timer Input 2 (TI2FP2) */ +# define GTIM_SMCR_ETRF (7 << GTIM_SMCR_TS_SHIFT) /* 111: External Trigger input (ETRF) */ +#define GTIM_SMCR_MSM (1 << 7) /* Bit 7: Master/Slave mode */ +#define GTIM_SMCR_ETF_SHIFT (8) /* Bits 11-8: External Trigger Filter (not TIM15) */ +#define GTIM_SMCR_ETF_MASK (0x0f << GTIM_SMCR_ETF_SHIFT) +# define GTIM_SMCR_NOFILT (0 << GTIM_SMCR_ETF_SHIFT) /* 0000: No filter, sampling is done at fDTS */ +# define GTIM_SMCR_FCKINT2 (1 << GTIM_SMCR_ETF_SHIFT) /* 0001: fSAMPLING=fCK_INT, N=2 */ +# define GTIM_SMCR_FCKINT4 (2 << GTIM_SMCR_ETF_SHIFT) /* 0010: fSAMPLING=fCK_INT, N=4 */ +# define GTIM_SMCR_FCKINT8 (3 << GTIM_SMCR_ETF_SHIFT) /* 0011: fSAMPLING=fCK_INT, N=8 */ +# define GTIM_SMCR_FDTSd26 (4 << GTIM_SMCR_ETF_SHIFT) /* 0100: fSAMPLING=fDTS/2, N=6 */ +# define GTIM_SMCR_FDTSd28 (5 << GTIM_SMCR_ETF_SHIFT) /* 0101: fSAMPLING=fDTS/2, N=8 */ +# define GTIM_SMCR_FDTSd36 (6 << GTIM_SMCR_ETF_SHIFT) /* 0110: fSAMPLING=fDTS/4, N=6 */ +# define GTIM_SMCR_FDTSd38 (7 << GTIM_SMCR_ETF_SHIFT) /* 0111: fSAMPLING=fDTS/4, N=8 */ +# define GTIM_SMCR_FDTSd86 (8 << GTIM_SMCR_ETF_SHIFT) /* 1000: fSAMPLING=fDTS/8, N=6 */ +# define GTIM_SMCR_FDTSd88 (9 << GTIM_SMCR_ETF_SHIFT) /* 1001: fSAMPLING=fDTS/8, N=8 */ +# define GTIM_SMCR_FDTSd165 (10 << GTIM_SMCR_ETF_SHIFT) /* 1010: fSAMPLING=fDTS/16, N=5 */ +# define GTIM_SMCR_FDTSd166 (11 << GTIM_SMCR_ETF_SHIFT) /* 1011: fSAMPLING=fDTS/16, N=6 */ +# define GTIM_SMCR_FDTSd168 (12 << GTIM_SMCR_ETF_SHIFT) /* 1100: fSAMPLING=fDTS/16, N=8 */ +# define GTIM_SMCR_FDTSd325 (13 << GTIM_SMCR_ETF_SHIFT) /* 1101: fSAMPLING=fDTS/32, N=5 */ +# define GTIM_SMCR_FDTSd326 (14 << GTIM_SMCR_ETF_SHIFT) /* 1110: fSAMPLING=fDTS/32, N=6 */ +# define GTIM_SMCR_FDTSd328 (15 << GTIM_SMCR_ETF_SHIFT) /* 1111: fSAMPLING=fDTS/32, N=8 */ +#define GTIM_SMCR_ETPS_SHIFT (12) /* Bits 13-12: External Trigger Prescaler (not TIM15) */ +#define GTIM_SMCR_ETPS_MASK (3 << GTIM_SMCR_ETPS_SHIFT) +# define GTIM_SMCR_PSCOFF (0 << GTIM_SMCR_ETPS_SHIFT) /* 00: Prescaler OFF */ +# define GTIM_SMCR_ETRPd2 (1 << GTIM_SMCR_ETPS_SHIFT) /* 01: ETRP frequency divided by 2 */ +# define GTIM_SMCR_ETRPd4 (2 << GTIM_SMCR_ETPS_SHIFT) /* 10: ETRP frequency divided by 4 */ +# define GTIM_SMCR_ETRPd8 (3 << GTIM_SMCR_ETPS_SHIFT) /* 11: ETRP frequency divided by 8 */ +#define GTIM_SMCR_ECE (1 << 14) /* Bit 14: External Clock enable */ +#define GTIM_SMCR_ETP (1 << 15) /* Bit 15: External Trigger Polarity */ + +/* DMA/Interrupt enable register (TIM2-5 and TIM9-14) */ + +#define GTIM_DIER_UIE (1 << 0) /* Bit 0: Update interrupt enable */ +#define GTIM_DIER_CC1IE (1 << 1) /* Bit 1: Capture/Compare 1 interrupt enable */ +#define GTIM_DIER_CC2IE (1 << 2) /* Bit 2: Capture/Compare 2 interrupt enable (TIM2-5,9,12,&15 only) */ +#define GTIM_DIER_CC3IE (1 << 3) /* Bit 3: Capture/Compare 3 interrupt enable (TIM2-5 only) */ +#define GTIM_DIER_CC4IE (1 << 4) /* Bit 4: Capture/Compare 4 interrupt enable (TIM2-5 only) */ +#define GTIM_DIER_COMIE (1 << 5) /* Bit 5: COM interrupt enable (TIM15-17 only) */ +#define GTIM_DIER_TIE (1 << 6) /* Bit 6: Trigger interrupt enable (TIM2-5,9,&12 only) */ +#define GTIM_DIER_BIE (1 << 7) /* Bit 7: Break interrupt enable (TIM15-17 only) */ +#define GTIM_DIER_UDE (1 << 8) /* Bit 8: Update DMA request enable (TIM2-5&15-17 only) */ +#define GTIM_DIER_CC1DE (1 << 9) /* Bit 9: Capture/Compare 1 DMA request enable (TIM2-5&15-17 only) */ +#define GTIM_DIER_CC2DE (1 << 10) /* Bit 10: Capture/Compare 2 DMA request enable (TIM2-5&15 only) */ +#define GTIM_DIER_CC3DE (1 << 11) /* Bit 11: Capture/Compare 3 DMA request enable (TIM2-5 only) */ +#define GTIM_DIER_CC4DE (1 << 12) /* Bit 12: Capture/Compare 4 DMA request enable (TIM2-5 only) */ +#define GTIM_DIER_COMDE (1 << 13) /* Bit 13: COM DMA request enable (TIM15-17 only) */ +#define GTIM_DIER_TDE (1 << 14) /* Bit 14: Trigger DMA request enable (TIM2-5&15-17 only) */ + +/* Status register */ + +#define GTIM_SR_UIF (1 << 0) /* Bit 0: Update interrupt flag */ +#define GTIM_SR_CC1IF (1 << 1) /* Bit 1: Capture/compare 1 interrupt flag */ +#define GTIM_SR_CC2IF (1 << 2) /* Bit 2: Capture/Compare 2 interrupt flag (TIM2-5,9,12,&15 only) */ +#define GTIM_SR_CC3IF (1 << 3) /* Bit 3: Capture/Compare 3 interrupt flag (TIM2-5 only) */ +#define GTIM_SR_CC4IF (1 << 4) /* Bit 4: Capture/Compare 4 interrupt flag (TIM2-5 only) */ +#define GTIM_SR_COMIF (1 << 5) /* Bit 5: COM interrupt flag (TIM15-17 only) */ +#define GTIM_SR_TIF (1 << 6) /* Bit 6: Trigger interrupt Flag (TIM2-5,9,12&15-17 only) */ +#define GTIM_SR_BIF (1 << 7) /* Bit 7: Break interrupt flag (TIM15-17 only) */ +#define GTIM_SR_CC1OF (1 << 9) /* Bit 9: Capture/Compare 1 Overcapture flag */ +#define GTIM_SR_CC2OF (1 << 10) /* Bit 10: Capture/Compare 2 Overcapture flag (TIM2-5,9,12&15 only) */ +#define GTIM_SR_CC3OF (1 << 11) /* Bit 11: Capture/Compare 3 Overcapture flag (TIM2-5 only) */ +#define GTIM_SR_CC4OF (1 << 12) /* Bit 12: Capture/Compare 4 Overcapture flag (TIM2-5 only) */ + +/* Event generation register (TIM2-5 and TIM9-14) */ + +#define GTIM_EGR_UG (1 << 0) /* Bit 0: Update generation */ +#define GTIM_EGR_CC1G (1 << 1) /* Bit 1: Capture/compare 1 generation */ +#define GTIM_EGR_CC2G (1 << 2) /* Bit 2: Capture/compare 2 generation (TIM2-5,9,12,&15 only) */ +#define GTIM_EGR_CC3G (1 << 3) /* Bit 3: Capture/compare 3 generation (TIM2-5 only) */ +#define GTIM_EGR_CC4G (1 << 4) /* Bit 4: Capture/compare 4 generation (TIM2-5 only) */ +#define GTIM_EGR_COMG (1 << 5) /* Bit 5: Capture/Compare control update generation (TIM15-17 only) */ +#define GTIM_EGR_TG (1 << 6) /* Bit 6: Trigger generation (TIM2-5,9,12&16-17 only) */ +#define GTIM_EGR_BG (1 << 7) /* Bit 7: Break generation (TIM15-17 only) */ + +/* Capture/compare mode register 1 - Output compare mode + * (TIM2-5 and TIM9-14) + */ + +#define GTIM_CCMR1_CC1S_SHIFT (0) /* Bits 1-0: Capture/Compare 1 Selection */ +#define GTIM_CCMR1_CC1S_MASK (3 << GTIM_CCMR1_CC1S_SHIFT) + /* (See common CCMR Capture/Compare Selection definitions below) */ +#define GTIM_CCMR1_OC1FE (1 << 2) /* Bit 2: Output Compare 1 Fast enable */ +#define GTIM_CCMR1_OC1PE (1 << 3) /* Bit 3: Output Compare 1 Preload enable */ +#define GTIM_CCMR1_OC1M_SHIFT (4) /* Bits 6-4: Output Compare 1 Mode */ +#define GTIM_CCMR1_OC1M_MASK (7 << GTIM_CCMR1_OC1M_SHIFT) + /* (See common CCMR Output Compare Mode definitions below) */ +#define GTIM_CCMR1_OC1CE (1 << 7) /* Bit 7: Output Compare 1Clear Enable */ +#define GTIM_CCMR1_CC2S_SHIFT (8) /* Bits 9-8: Capture/Compare 2 Selection */ +#define GTIM_CCMR1_CC2S_MASK (3 << GTIM_CCMR1_CC2S_SHIFT) + /* (See common CCMR Capture/Compare Selection definitions below) */ +#define GTIM_CCMR1_OC2FE (1 << 10) /* Bit 10: Output Compare 2 Fast enable */ +#define GTIM_CCMR1_OC2PE (1 << 11) /* Bit 11: Output Compare 2 Preload enable */ +#define GTIM_CCMR1_OC2M_SHIFT (12) /* Bits 14-12: Output Compare 2 Mode */ +#define GTIM_CCMR1_OC2M_MASK (7 << GTIM_CCMR1_OC2M_SHIFT) + /* (See common CCMR Output Compare Mode definitions below) */ +#define GTIM_CCMR1_OC2CE (1 << 15) /* Bit 15: Output Compare 2 Clear Enable */ + +/* Common CCMR (unshifted) Capture/Compare Selection bit-field definitions */ + +#define GTIM_CCMR_CCS_CCOUT (0) /* 00: CCx channel output */ +#define GTIM_CCMR_CCS_CCIN1 (1) /* 01: CCx channel input, ICx is TIx */ +#define GTIM_CCMR_CCS_CCIN2 (2) /* 10: CCx channel input, ICx is TIy */ +#define GTIM_CCMR_CCS_CCINTRC (3) /* 11: CCx channel input, ICx is TRC */ + +/* Common CCMR (unshifted) Compare Mode bit field definitions */ + +#define GTIM_CCMR_MODE_FRZN (0) /* 000: Frozen */ +#define GTIM_CCMR_MODE_CHACT (1) /* 001: Channel x active on match */ +#define GTIM_CCMR_MODE_CHINACT (2) /* 010: Channel x inactive on match */ +#define GTIM_CCMR_MODE_OCREFTOG (3) /* 011: OCxREF toggle ATIM_CNT=ATIM_CCRx */ +#define GTIM_CCMR_MODE_OCREFLO (4) /* 100: OCxREF forced low */ +#define GTIM_CCMR_MODE_OCREFHI (5) /* 101: OCxREF forced high */ +#define GTIM_CCMR_MODE_PWM1 (6) /* 110: PWM mode 1 */ +#define GTIM_CCMR_MODE_PWM2 (7) /* 111: PWM mode 2 */ + +/* Capture/compare mode register 1 - Input capture mode + * (TIM2-5 and TIM9-14) + */ + +/* Bits 1-0 + * (Same as Output Compare Mode) + */ +#define GTIM_CCMR1_IC1PSC_SHIFT (2) /* Bits 3-2: Input Capture 1 Prescaler */ +#define GTIM_CCMR1_IC1PSC_MASK (3 << GTIM_CCMR1_IC1PSC_SHIFT) + /* (See common CCMR Input Capture Prescaler definitions below) */ +#define GTIM_CCMR1_IC1F_SHIFT (4) /* Bits 7-4: Input Capture 1 Filter */ +#define GTIM_CCMR1_IC1F_MASK (0x0f << GTIM_CCMR1_IC1F_SHIFT) + /* (See common CCMR Input Capture Filter definitions below) */ + /* Bits 9-8: (Same as Output Compare Mode) */ +#define GTIM_CCMR1_IC2PSC_SHIFT (10) /* Bits 11-10: Input Capture 2 Prescaler */ +#define GTIM_CCMR1_IC2PSC_MASK (3 << GTIM_CCMR1_IC2PSC_SHIFT) + /* (See common CCMR Input Capture Prescaler definitions below) */ +#define GTIM_CCMR1_IC2F_SHIFT (12) /* Bits 15-12: Input Capture 2 Filter */ +#define GTIM_CCMR1_IC2F_MASK (0x0f << GTIM_CCMR1_IC2F_SHIFT) + /* (See common CCMR Input Capture Filter definitions below) */ + +/* Common CCMR (unshifted) Input Capture Prescaler bit-field definitions */ + +#define GTIM_CCMR_ICPSC_NOPSC (0) /* 00: no prescaler, capture each edge */ +#define GTIM_CCMR_ICPSC_EVENTS2 (1) /* 01: capture once every 2 events */ +#define GTIM_CCMR_ICPSC_EVENTS4 (2) /* 10: capture once every 4 events */ +#define GTIM_CCMR_ICPSC_EVENTS8 (3) /* 11: capture once every 8 events */ + +/* Common CCMR (unshifted) Input Capture Filter bit-field definitions */ + +#define GTIM_CCMR_ICF_NOFILT (0) /* 0000: No filter, sampling at fDTS */ +#define GTIM_CCMR_ICF_FCKINT2 (1) /* 0001: fSAMPLING=fCK_INT, N=2 */ +#define GTIM_CCMR_ICF_FCKINT4 (2) /* 0010: fSAMPLING=fCK_INT, N=4 */ +#define GTIM_CCMR_ICF_FCKINT8 (3) /* 0011: fSAMPLING=fCK_INT, N=8 */ +#define GTIM_CCMR_ICF_FDTSd26 (4) /* 0100: fSAMPLING=fDTS/2, N=6 */ +#define GTIM_CCMR_ICF_FDTSd28 (5) /* 0101: fSAMPLING=fDTS/2, N=8 */ +#define GTIM_CCMR_ICF_FDTSd46 (6) /* 0110: fSAMPLING=fDTS/4, N=6 */ +#define GTIM_CCMR_ICF_FDTSd48 (7) /* 0111: fSAMPLING=fDTS/4, N=8 */ +#define GTIM_CCMR_ICF_FDTSd86 (8) /* 1000: fSAMPLING=fDTS/8, N=6 */ +#define GTIM_CCMR_ICF_FDTSd88 (9) /* 1001: fSAMPLING=fDTS/8, N=8 */ +#define GTIM_CCMR_ICF_FDTSd165 (10) /* 1010: fSAMPLING=fDTS/16, N=5 */ +#define GTIM_CCMR_ICF_FDTSd166 (11) /* 1011: fSAMPLING=fDTS/16, N=6 */ +#define GTIM_CCMR_ICF_FDTSd168 (12) /* 1100: fSAMPLING=fDTS/16, N=8 */ +#define GTIM_CCMR_ICF_FDTSd325 (13) /* 1101: fSAMPLING=fDTS/32, N=5 */ +#define GTIM_CCMR_ICF_FDTSd326 (14) /* 1110: fSAMPLING=fDTS/32, N=6 */ +#define GTIM_CCMR_ICF_FDTSd328 (15) /* 1111: fSAMPLING=fDTS/32, N=8 */ + +/* Capture/compare mode register 2 - Output Compare mode (TIM2-5 only) */ + +#define GTIM_CCMR2_CC3S_SHIFT (0) /* Bits 1-0: Capture/Compare 3 Selection */ +#define GTIM_CCMR2_CC3S_MASK (3 << GTIM_CCMR2_CC3S_SHIFT) + /* (See common CCMR Capture/Compare Selection definitions above) */ +#define GTIM_CCMR2_OC3FE (1 << 2) /* Bit 2: Output Compare 3 Fast enable */ +#define GTIM_CCMR2_OC3PE (1 << 3) /* Bit 3: Output Compare 3 Preload enable */ +#define GTIM_CCMR2_OC3M_SHIFT (4) /* Bits 6-4: Output Compare 3 Mode */ +#define GTIM_CCMR2_OC3M_MASK (7 << GTIM_CCMR2_OC3M_SHIFT) + /* (See common CCMR Output Compare Mode definitions above) */ +#define GTIM_CCMR2_OC3CE (1 << 7) /* Bit 7: Output Compare 3 Clear Enable */ +#define GTIM_CCMR2_CC4S_SHIFT (8) /* Bits 9-8: Capture/Compare 4 Selection */ +#define GTIM_CCMR2_CC4S_MASK (3 << GTIM_CCMR2_CC4S_SHIFT) + /* (See common CCMR Capture/Compare Selection definitions above) */ +#define GTIM_CCMR2_OC4FE (1 << 10) /* Bit 10: Output Compare 4 Fast enable */ +#define GTIM_CCMR2_OC4PE (1 << 11) /* Bit 11: Output Compare 4 Preload enable */ +#define GTIM_CCMR2_OC4M_SHIFT (12) /* Bits 14-12: Output Compare 4 Mode */ +#define GTIM_CCMR2_OC4M_MASK (7 << GTIM_CCMR2_OC4M_SHIFT) + /* (See common CCMR Output Compare Mode definitions above) */ +#define GTIM_CCMR2_OC4CE (1 << 15) /* Bit 15: Output Compare 4 Clear Enable */ + +/* Capture/compare mode register 2 - Input capture mode (TIM2-5 only) */ + +/* Bits 1-0 + * (Same as Output Compare Mode) + */ +#define GTIM_CCMR2_IC3PSC_SHIFT (2) /* Bits 3-2: Input Capture 3 Prescaler */ +#define GTIM_CCMR2_IC3PSC_MASK (3 << GTIM_CCMR2_IC3PSC_SHIFT) + /* (See common CCMR Input Capture Prescaler definitions below) */ +#define GTIM_CCMR2_IC3F_SHIFT (4) /* Bits 7-4: Input Capture 3 Filter */ +#define GTIM_CCMR2_IC3F_MASK (0x0f << GTIM_CCMR2_IC3F_SHIFT) + /* (See common CCMR Input Capture Filter definitions below) */ + /* Bits 9-8: (Same as Output Compare Mode) */ +#define GTIM_CCMR2_IC4PSC_SHIFT (10) /* Bits 11-10: Input Capture 4 Prescaler */ +#define GTIM_CCMR2_IC4PSC_MASK (3 << GTIM_CCMR2_IC4PSC_SHIFT) + /* (See common CCMR Input Capture Prescaler definitions below) */ +#define GTIM_CCMR2_IC4F_SHIFT (12) /* Bits 15-12: Input Capture 4 Filter */ +#define GTIM_CCMR2_IC4F_MASK (0x0f << GTIM_CCMR2_IC4F_SHIFT) + /* (See common CCMR Input Capture Filter definitions below) */ + +/* Capture/compare enable register (TIM2-5 and TIM9-14) */ + +#define GTIM_CCER_CC1E (1 << 0) /* Bit 0: Capture/Compare 1 output enable */ +#define GTIM_CCER_CC1P (1 << 1) /* Bit 1: Capture/Compare 1 output polarity */ + +#define GTIM_CCER_CC1NP (1 << 3) /* Bit 3: Capture/Compare 1 output Polarity (F2,F3,F4 and TIM15-17) */ + +#define GTIM_CCER_CC2E (1 << 4) /* Bit 4: Capture/Compare 2 output enable (TIM2-5,9&12 only) */ +#define GTIM_CCER_CC2P (1 << 5) /* Bit 5: Capture/Compare 2 output polarity (TIM2-5,9&12 only) */ +#define GTIM_CCER_CC2NE (1 << 6) /* Bit 6: Capture/Compare 2 complementary output enable (TIM1 and TIM8 only) */ + +#define GTIM_CCER_CC2NP (1 << 7) /* Bit 7: Capture/Compare 2 output Polarity (F2,F3,F4 and TIM2-5,9,12&15 only) */ + +#define GTIM_CCER_CC3E (1 << 8) /* Bit 8: Capture/Compare 3 output enable (TIM2-5 only) */ +#define GTIM_CCER_CC3P (1 << 9) /* Bit 9: Capture/Compare 3 output Polarity (TIM2-5 only) */ + +#define GTIM_CCER_CC3NP (1 << 11) /* Bit 11: Capture/Compare 3 output Polarity (F2,F4 and TIM2-5 only) */ + +#define GTIM_CCER_CC4E (1 << 12) /* Bit 12: Capture/Compare 4 output enable (TIM2-5 only) */ +#define GTIM_CCER_CC4P (1 << 13) /* Bit 13: Capture/Compare 4 output Polarity (TIM2-5 only) */ + +#define GTIM_CCER_CCXBASE(ch) (ch << 2) /* Each channel uses 4-bits */ + +/* 16-bit counter register */ + +#define GTIM_CNT_SHIFT (0) /* Bits 0-15: Timer counter value */ +#define GTIM_CNT_MASK (0xffff << ATIM_CNT_SHIFT) + +/* DMA control register */ + +#define GTIM_DCR_DBA_SHIFT (0) /* Bits 4-0: DMA Base Address */ +#define GTIM_DCR_DBA_MASK (0x1f << GTIM_DCR_DBA_SHIFT) +#define GTIM_DCR_DBL_SHIFT (8) /* Bits 12-8: DMA Burst Length */ +#define GTIM_DCR_DBL_MASK (0x1f << GTIM_DCR_DBL_SHIFT) + +/* Timer 2/5 option register */ + +#if defined(CONFIG_AT32_AT32F43XX) +# define TIM2_OR_ITR1_RMP_SHIFT (10) /* Bits 10-11: Internal trigger 1 remap */ +# define TIM2_OR_ITR1_RMP_MASK (3 << TIM2_OR_ITR1_RMP_SHIFT) +# define TIM2_OR_ITR1_TIM8_TRGOUT (0 << TIM2_OR_ITR1_RMP_SHIFT) /* 00: TIM2_ITR1 input connected to TIM8_TRGOUT */ +# define TIM2_OR_ITR1_PTP (1 << TIM2_OR_ITR1_RMP_SHIFT) /* 01: TIM2_ITR1 input connected to PTP trigger output */ +# define TIM2_OR_ITR1_OTGFS1SOF (2 << TIM2_OR_ITR1_RMP_SHIFT) /* 10: TIM2_ITR1 input connected to OTG FS SOF */ +# define TIM2_OR_ITR1_OTGFS2SOF (3 << TIM2_OR_ITR1_RMP_SHIFT) /* 11: TIM2_ITR1 input connected to OTG HS SOF */ + +# define TIM5_OR_TI4_RMP_SHIFT (6) /* Bits 6-7: Internal trigger 4 remap */ +# define TIM5_OR_TI4_RMP_MASK (3 << TIM5_OR_TI4_RMP_SHIFT) +# define TIM5_OR_TI4_GPIO (0 << TIM5_OR_TI4_RMP_SHIFT) /* 00: TIM5_CH4 input connected to GPIO */ +# define TIM5_OR_TI4_LSI (1 << TIM5_OR_TI4_RMP_SHIFT) /* 01: TIM5_CH4 input connected to LSI internal clock */ +# define TIM5_OR_TI4_LSE (2 << TIM5_OR_TI4_RMP_SHIFT) /* 10: TIM5_CH4 input connected to LSE internal clock */ +# define TIM5_OR_TI4_RTC (3 << TIM5_OR_TI4_RMP_SHIFT) /* 11: TIM5_CH4 input connected to RTC output event */ +#endif + +/* Control register 1 */ + +#define BTIM_CR1_CEN (1 << 0) /* Bit 0: Counter enable */ +#define BTIM_CR1_UDIS (1 << 1) /* Bit 1: Update Disable */ +#define BTIM_CR1_URS (1 << 2) /* Bit 2: Update Request Source */ +#define BTIM_CR1_OPM (1 << 3) /* Bit 3: One Pulse Mode */ +#define BTIM_CR1_ARPE (1 << 7) /* Bit 7: Auto-Reload Preload enable */ + +/* Control register 2 */ + +#define BTIM_CR2_MMS_SHIFT (4) /* Bits 6-4: Master Mode Selection */ +#define BTIM_CR2_MMS_MASK (7 << BTIM_CR2_MMS_SHIFT) +# define BTIM_CR2_RESET (0 << BTIM_CR2_MMS_SHIFT) /* 000: Reset */ +# define BTIM_CR2_ENAB (1 << BTIM_CR2_MMS_SHIFT) /* 001: Enable */ +# define BTIM_CR2_UPDT (2 << BTIM_CR2_MMS_SHIFT) /* 010: Update */ + +/* DMA/Interrupt enable register */ + +#define BTIM_DIER_UIE (1 << 0) /* Bit 0: Update interrupt enable */ +#define BTIM_DIER_UDE (1 << 8) /* Bit 8: Update DMA request enable */ + +/* Status register */ + +#define BTIM_SR_UIF (1 << 0) /* Bit 0: Update interrupt flag */ + +/* Event generation register */ + +#define BTIM_EGR_UG (1 << 0) /* Bit 0: Update generation */ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_TIM_V1V2_H */ diff --git a/arch/arm/src/at32/hardware/at32_wdg.h b/arch/arm/src/at32/hardware/at32_wdg.h new file mode 100644 index 0000000000..112b25576a --- /dev/null +++ b/arch/arm/src/at32/hardware/at32_wdg.h @@ -0,0 +1,140 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32_wdg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32_WDG_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32_WDG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define AT32_IWDG_KR_OFFSET 0x0000 /* Key register (32-bit) */ +#define AT32_IWDG_PR_OFFSET 0x0004 /* Prescaler register (32-bit) */ +#define AT32_IWDG_RLR_OFFSET 0x0008 /* Reload register (32-bit) */ +#define AT32_IWDG_SR_OFFSET 0x000c /* Status register (32-bit) */ +#define AT32_IWDG_WINR_OFFSET 0x000c /* Window register (32-bit) */ + +#define AT32_WWDG_CR_OFFSET 0x0000 /* Control Register (32-bit) */ +#define AT32_WWDG_CFR_OFFSET 0x0004 /* Configuration register (32-bit) */ +#define AT32_WWDG_SR_OFFSET 0x0008 /* Status register (32-bit) */ + +/* Register Addresses *******************************************************/ + +#define AT32_IWDG_KR (AT32_WDT_BASE+AT32_IWDG_KR_OFFSET) +#define AT32_IWDG_PR (AT32_WDT_BASE+AT32_IWDG_PR_OFFSET) +#define AT32_IWDG_RLR (AT32_WDT_BASE+AT32_IWDG_RLR_OFFSET) +#define AT32_IWDG_SR (AT32_WDT_BASE+AT32_IWDG_SR_OFFSET) +#define AT32_IWDG_WINR (AT32_WDT_BASE+AT32_IWDG_WINR_OFFSET) + +#define AT32_WWDG_CR (AT32_WWDT_BASE+AT32_WWDG_CR_OFFSET) +#define AT32_WWDG_CFR (AT32_WWDT_BASE+AT32_WWDG_CFR_OFFSET) +#define AT32_WWDG_SR (AT32_WWDT_BASE+AT32_WWDG_SR_OFFSET) + +/* Register Bitfield Definitions ********************************************/ + +/* Key register (32-bit) */ + +#define IWDG_KR_KEY_SHIFT (0) /* Bits 15-0: Key value (write only, read 0000h) */ +#define IWDG_KR_KEY_MASK (0xffff << IWDG_KR_KEY_SHIFT) + +#define IWDG_KR_KEY_ENABLE (0x5555) /* Enable register access */ +#define IWDG_KR_KEY_DISABLE (0x0000) /* Disable register access */ +#define IWDG_KR_KEY_RELOAD (0xaaaa) /* Reload the counter */ +#define IWDG_KR_KEY_START (0xcccc) /* Start the watchdog */ + +/* Prescaler register (32-bit) */ + +#define IWDG_PR_SHIFT (0) /* Bits 2-0: Prescaler divider */ +#define IWDG_PR_MASK (7 << IWDG_PR_SHIFT) +# define IWDG_PR_DIV4 (0 << IWDG_PR_SHIFT) /* 000: divider /4 */ +# define IWDG_PR_DIV8 (1 << IWDG_PR_SHIFT) /* 001: divider /8 */ +# define IWDG_PR_DIV16 (2 << IWDG_PR_SHIFT) /* 010: divider /16 */ +# define IWDG_PR_DIV32 (3 << IWDG_PR_SHIFT) /* 011: divider /32 */ +# define IWDG_PR_DIV64 (4 << IWDG_PR_SHIFT) /* 100: divider /64 */ +# define IWDG_PR_DIV128 (5 << IWDG_PR_SHIFT) /* 101: divider /128 */ +# define IWDG_PR_DIV256 (6 << IWDG_PR_SHIFT) /* 11x: divider /256 */ + +/* Reload register (32-bit) */ + +#define IWDG_RLR_RL_SHIFT (0) /* Bits11:0 RL[11:0]: Watchdog counter reload value */ +#define IWDG_RLR_RL_MASK (0x0fff << IWDG_RLR_RL_SHIFT) + +#define IWDG_RLR_MAX (0xfff) + +/* Status register (32-bit) */ + +#define IWDG_SR_PVU (1 << 0) /* Bit 0: Watchdog prescaler value update */ +#define IWDG_SR_RVU (1 << 1) /* Bit 1: Watchdog counter reload value update */ + +#define IWDG_SR_WVU (1 << 2) /* Bit 2: */ + +/* Window register (32-bit) */ + +#define IWDG_WINR_SHIFT (0) +#define IWDG_WINR_MASK (0x0fff << IWDG_WINR_SHIFT) + +/* Control Register (32-bit) */ + +#define WWDG_CR_T_SHIFT (0) /* Bits 6:0 T[6:0]: 7-bit counter (MSB to LSB) */ +#define WWDG_CR_T_MASK (0x7f << WWDG_CR_T_SHIFT) +# define WWDG_CR_T_MAX (0x3f << WWDG_CR_T_SHIFT) +# define WWDG_CR_T_RESET (0x40 << WWDG_CR_T_SHIFT) +#define WWDG_CR_WDGA (1 << 7) /* Bit 7: Activation bit */ + +/* Configuration register (32-bit) */ + +#define WWDG_CFR_W_SHIFT (0) /* Bits 6:0 W[6:0] 7-bit window value */ +#define WWDG_CFR_W_MASK (0x7f << WWDG_CFR_W_SHIFT) +#define WWDG_CFR_WDGTB_SHIFT (7) /* Bits 8:7 [1:0]: Timer Base */ +#define WWDG_CFR_WDGTB_MASK (3 << WWDG_CFR_WDGTB_SHIFT) +# define WWDG_CFR_PCLK1 (0 << WWDG_CFR_WDGTB_SHIFT) /* 00: CK Counter Clock (PCLK1 div 4096) div 1 */ +# define WWDG_CFR_PCLK1d2 (1 << WWDG_CFR_WDGTB_SHIFT) /* 01: CK Counter Clock (PCLK1 div 4096) div 2 */ +# define WWDG_CFR_PCLK1d4 (2 << WWDG_CFR_WDGTB_SHIFT) /* 10: CK Counter Clock (PCLK1 div 4096) div 4 */ +# define WWDG_CFR_PCLK1d8 (3 << WWDG_CFR_WDGTB_SHIFT) /* 11: CK Counter Clock (PCLK1 div 4096) div 8 */ + +#define WWDG_CFR_EWI (1 << 9) /* Bit 9: Early Wakeup Interrupt */ + +/* Status register (32-bit) */ + +#define WWDG_SR_EWIF (1 << 0) /* Bit 0: Early Wakeup Interrupt Flag */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32_WDG_H */ diff --git a/arch/arm/src/at32/hardware/at32f43xxx_dmamux.h b/arch/arm/src/at32/hardware/at32f43xxx_dmamux.h new file mode 100644 index 0000000000..3e2b76d277 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32f43xxx_dmamux.h @@ -0,0 +1,132 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32f43xxx_dmamux.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_DMAMUX_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_DMAMUX_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* DMAMUX1 mapping **********************************************************/ + +#define DMAMUX_REQ_MEM2MEM (0) /* Memory to memory transfer */ +#define DMAMUX_REQ_GEN0 (1) /* DMAMUX Request Generator 0 */ +#define DMAMUX_REQ_GEN1 (2) /* DMAMUX Request Generator 1 */ +#define DMAMUX_REQ_GEN2 (3) /* DMAMUX Request Generator 2 */ +#define DMAMUX_REQ_GEN3 (4) /* DMAMUX Request Generator 3 */ +#define DMAMUX_ADC1 (5) /* DMAMUX ADC1 request */ +#define DMAMUX_DAC1_CH1 (6) /* DMAMUX DAC1 Channel 1 request */ +#define DMAMUX_TIM6_UP (8) /* DMAMUX TIM6 Update request */ +#define DMAMUX_TIM7_UP (9) /* DMAMUX TIM7 Update request */ +#define DMAMUX_SPI1_RX (10) /* DMAMUX SPI1 Rx request */ +#define DMAMUX_SPI1_TX (11) /* DMAMUX SPI1 Tx request */ +#define DMAMUX_SPI2_RX (12) /* DMAMUX SPI2 Rx request */ +#define DMAMUX_SPI2_TX (13) /* DMAMUX SPI2 Tx request */ +#define DMAMUX_SPI3_RX (14) /* DMAMUX SPI3 Rx request */ +#define DMAMUX_SPI3_TX (15) /* DMAMUX SPI3 Tx request */ +#define DMAMUX_I2C1_RX (16) /* DMAMUX I2C1 Rx request */ +#define DMAMUX_I2C1_TX (17) /* DMAMUX I2C1 Tx request */ +#define DMAMUX_I2C2_RX (18) /* DMAMUX I2C2 Rx request */ +#define DMAMUX_I2C2_TX (19) /* DMAMUX I2C2 Tx request */ +#define DMAMUX_I2C3_RX (20) /* DMAMUX I2C3 Rx request */ +#define DMAMUX_I2C3_TX (21) /* DMAMUX I2C3 Tx request */ +#define DMAMUX_USART1_RX (24) /* DMAMUX USART1 Rx request */ +#define DMAMUX_USART1_TX (25) /* DMAMUX USART1 Tx request */ +#define DMAMUX_USART2_RX (26) /* DMAMUX USART2 Rx request */ +#define DMAMUX_USART2_TX (27) /* DMAMUX USART2 Tx request */ +#define DMAMUX_USART3_RX (28) /* DMAMUX USART3 Rx request */ +#define DMAMUX_USART3_TX (29) /* DMAMUX USART3 Tx request */ +#define DMAMUX_UART4_RX (30) /* DMAMUX UART4 Rx request */ +#define DMAMUX_UART4_TX (31) /* DMAMUX UART4 Tx request */ +#define DMAMUX_UART5_RX (32) /* DMAMUX UART5 Rx request */ +#define DMAMUX_UART5_TX (33) /* DMAMUX UART5 Tx request */ +#define DMAMUX_ADC2 (36) /* DMAMUX ADC2 request */ +#define DMAMUX_ADC3 (37) /* DMAMUX ADC3 request */ +#define DMAMUX_SDIO (39) /* DMAMUX SDIO1 request */ +#define DMAMUX_QSPI (40) /* DMAMUX QSPI request */ +#define DMAMUX_DAC2_CH1 (41) /* DMAMUX DAC2 Channel 1 request */ +#define DMAMUX_TIM1_CH1 (42) /* DMAMUX TIM1 Channel 1 request */ +#define DMAMUX_TIM1_CH2 (43) /* DMAMUX TIM1 Channel 2 request */ +#define DMAMUX_TIM1_CH3 (44) /* DMAMUX TIM1 Channel 3 request */ +#define DMAMUX_TIM1_CH4 (45) /* DMAMUX TIM1 Channel 4 request */ +#define DMAMUX_TIM1_UP (46) /* DMAMUX TIM1 Update request */ +#define DMAMUX_TIM1_TRIG (47) /* DMAMUX TIM1 Trigger request */ +#define DMAMUX_TIM1_COM (48) /* DMAMUX TIM1 Commutation request */ +#define DMAMUX_TIM8_CH1 (49) /* DMAMUX TIM8 Channel 1 request */ +#define DMAMUX_TIM8_CH2 (50) /* DMAMUX TIM8 Channel 2 request */ +#define DMAMUX_TIM8_CH3 (51) /* DMAMUX TIM8 Channel 3 request */ +#define DMAMUX_TIM8_CH4 (52) /* DMAMUX TIM8 Channel 4 request */ +#define DMAMUX_TIM8_UP (53) /* DMAMUX TIM8 Update request */ +#define DMAMUX_TIM8_TRIG (54) /* DMAMUX TIM8 Trigger request */ +#define DMAMUX_TIM8_COM (55) /* DMAMUX TIM8 Commutation request */ +#define DMAMUX_TIM2_CH1 (56) /* DMAMUX TIM2 Channel 1 request */ +#define DMAMUX_TIM2_CH2 (57) /* DMAMUX TIM2 Channel 2 request */ +#define DMAMUX_TIM2_CH3 (58) /* DMAMUX TIM2 Channel 3 request */ +#define DMAMUX_TIM2_CH4 (59) /* DMAMUX TIM2 Channel 4 request */ +#define DMAMUX_TIM2_UP (60) /* DMAMUX TIM2 Update request */ +#define DMAMUX_TIM3_CH1 (61) /* DMAMUX TIM3 Channel 1 request */ +#define DMAMUX_TIM3_CH2 (62) /* DMAMUX TIM3 Channel 2 request */ +#define DMAMUX_TIM3_CH3 (63) /* DMAMUX TIM3 Channel 3 request */ +#define DMAMUX_TIM3_CH4 (64) /* DMAMUX TIM3 Channel 4 request */ +#define DMAMUX_TIM3_UP (65) /* DMAMUX TIM3 Update request */ +#define DMAMUX_TIM3_TRIG (66) /* DMAMUX TIM3 Trigger request */ +#define DMAMUX_TIM4_CH1 (67) /* DMAMUX TIM4 Channel 1 request */ +#define DMAMUX_TIM4_CH2 (68) /* DMAMUX TIM4 Channel 2 request */ +#define DMAMUX_TIM4_CH3 (69) /* DMAMUX TIM4 Channel 3 request */ +#define DMAMUX_TIM4_CH4 (70) /* DMAMUX TIM4 Channel 4 request */ +#define DMAMUX_TIM4_UP (71) /* DMAMUX TIM4 Update request */ +#define DMAMUX_TIM5_CH1 (72) /* DMAMUX TIM5 Channel 1 request */ +#define DMAMUX_TIM5_CH2 (73) /* DMAMUX TIM5 Channel 2 request */ +#define DMAMUX_TIM5_CH3 (74) /* DMAMUX TIM5 Channel 3 request */ +#define DMAMUX_TIM5_CH4 (75) /* DMAMUX TIM5 Channel 4 request */ +#define DMAMUX_TIM5_UP (76) /* DMAMUX TIM5 Update request */ +#define DMAMUX_TIM5_TRIG (77) /* DMAMUX TIM5 Trigger request */ +#define DMAMUX_TIM20_CH1 (86) /* DMAMUX TIM20 Channel 1 request */ +#define DMAMUX_TIM20_CH2 (87) /* DMAMUX TIM20 Channel 2 request */ +#define DMAMUX_TIM20_CH3 (88) /* DMAMUX TIM20 Channel 3 request */ +#define DMAMUX_TIM20_CH4 (89) /* DMAMUX TIM20 Channel 4 request */ +#define DMAMUX_TIM20_UP (90) /* DMAMUX TIM20 Update request */ +#define DMAMUX_TIM20_TRIG (93) /* DMAMUX TIM20 Trigger request */ +#define DMAMUX_TIM20_COM (94) /* DMAMUX TIM20 Commutation request */ +#define DMAMUX_SDIO2 (103) /* DMAMUX DAC3 Channel 2 request */ +#define DMAMUX_QSPI2 (104) /* DMAMUX DAC4 Channel 1 request */ +#define DMAMUX_DVP (105) /* DMAMUX DAC4 Channel 2 request */ +#define DMAMUX_SPI4_RX (106) /* DMAMUX SPI4 Rx request */ +#define DMAMUX_SPI4_TX (107) /* DMAMUX SPI4 Tx request */ +#define DMAMUX_I2S2_EXT_RX (110) /* DMAMUX I2S2_EXT_RX request */ +#define DMAMUX_I2S2_EXT_TX (111) /* DMAMUX I2S2_EXT_TX request */ +#define DMAMUX_I2S3_EXT_RX (112) /* DMAMUX I2S3_EXT_RX request */ +#define DMAMUX_I2S3_EXT_TX (113) /* DMAMUX I2S3_EXT_TX request */ +#define DMAMUX_USART6_RX (114) /* DMAMUX UART6 Rx request */ +#define DMAMUX_USART6_TX (115) /* DMAMUX UART6 Tx request */ +#define DMAMUX_UART7_RX (116) /* DMAMUX UART7 Rx request */ +#define DMAMUX_UART7_TX (117) /* DMAMUX UART7 Tx request */ +#define DMAMUX_UART8_RX (118) /* DMAMUX UART8 Rx request */ +#define DMAMUX_UART8_TX (119) /* DMAMUX UART8 Tx request */ +#define DMAMUX_TIM2_TRIG (126) /* DMAMUX TIM2 Trigger request */ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_DMAMUX_H */ diff --git a/arch/arm/src/at32/hardware/at32f43xxx_gpio.h b/arch/arm/src/at32/hardware/at32f43xxx_gpio.h new file mode 100644 index 0000000000..c72a641059 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32f43xxx_gpio.h @@ -0,0 +1,356 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32f43xxx_gpio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_GPIO_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_GPIO_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define AT32_NGPIO_PORTS ((AT32_NGPIO + 15) >> 4) + +/* Register Offsets *********************************************************/ + +#define AT32_GPIO_CFGR_OFFSET (0x00) /* GPIO config register */ +#define AT32_GPIO_OMODER_OFFSET (0x04) /* GPIO output mode register */ +#define AT32_GPIO_ODRVR_OFFSET (0x08) /* GPIO drive capability */ +#define AT32_GPIO_PULL_OFFSET (0x0C) /* GPIO pull config register */ +#define AT32_GPIO_IDT_OFFSET (0x10) /* GPIO input data register */ +#define AT32_GPIO_ODT_OFFSET (0x14) /* GPIO output data register */ +#define AT32_GPIO_SCR_OFFSET (0x18) /* GPIO clear/set bit register */ +#define AT32_GPIO_WPR_OFFSET (0x1C) /* GPIO write protect register */ +#define AT32_GPIO_MUXL_OFFSET (0x20) /* GPIO muxing register (pin0~7) */ +#define AT32_GPIO_MUXH_OFFSET (0x24) /* GPIO muxing register (pin8~15)*/ +#define AT32_GPIO_CLR_OFFSET (0x28) /* GPIO clear bit */ +#define AT32_GPIO_HDRV_OFFSET (0x3C) /* GPIO high driver */ + +/* Register Addresses *******************************************************/ + +#if AT32_NGPIO_PORTS > 0 +# define AT32_GPIOA_CFGR (AT32_GPIOA_BASE+AT32_GPIO_CFGR_OFFSET) +# define AT32_GPIOA_OMODER (AT32_GPIOA_BASE+AT32_GPIO_OMODER_OFFSET) +# define AT32_GPIOA_ODRVR (AT32_GPIOA_BASE+AT32_GPIO_ODRVR_OFFSET) +# define AT32_GPIOA_PULL (AT32_GPIOA_BASE+AT32_GPIO_PULL_OFFSET) +# define AT32_GPIOA_IDT (AT32_GPIOA_BASE+AT32_GPIO_IDT_OFFSET) +# define AT32_GPIOA_ODT (AT32_GPIOA_BASE+AT32_GPIO_ODT_OFFSET) +# define AT32_GPIOA_SCR (AT32_GPIOA_BASE+AT32_GPIO_SCR_OFFSET) +# define AT32_GPIOA_WPR (AT32_GPIOA_BASE+AT32_GPIO_WPR_OFFSET) +# define AT32_GPIOA_MUXL (AT32_GPIOA_BASE+AT32_GPIO_MUXL_OFFSET) +# define AT32_GPIOA_MUXH (AT32_GPIOA_BASE+AT32_GPIO_MUXH_OFFSET) +# define AT32_GPIOA_CLR (AT32_GPIOA_BASE+AT32_GPIO_CLR_OFFSET) +# define AT32_GPIOA_HDRV (AT32_GPIOA_BASE+AT32_GPIO_HDRV_OFFSET) +#endif + +#if AT32_NGPIO_PORTS > 1 +# define AT32_GPIOB_CFGR (AT32_GPIOB_BASE+AT32_GPIO_CFGR_OFFSET) +# define AT32_GPIOB_OMODER (AT32_GPIOB_BASE+AT32_GPIO_OMODER_OFFSET) +# define AT32_GPIOB_ODRVR (AT32_GPIOB_BASE+AT32_GPIO_ODRVR_OFFSET) +# define AT32_GPIOB_PULL (AT32_GPIOB_BASE+AT32_GPIO_PULL_OFFSET) +# define AT32_GPIOB_IDT (AT32_GPIOB_BASE+AT32_GPIO_IDT_OFFSET) +# define AT32_GPIOB_ODT (AT32_GPIOB_BASE+AT32_GPIO_ODT_OFFSET) +# define AT32_GPIOB_SCR (AT32_GPIOB_BASE+AT32_GPIO_SCR_OFFSET) +# define AT32_GPIOB_WPR (AT32_GPIOB_BASE+AT32_GPIO_WPR_OFFSET) +# define AT32_GPIOB_MUXL (AT32_GPIOB_BASE+AT32_GPIO_MUXL_OFFSET) +# define AT32_GPIOB_MUXH (AT32_GPIOB_BASE+AT32_GPIO_MUXH_OFFSET) +# define AT32_GPIOB_CLR (AT32_GPIOB_BASE+AT32_GPIO_CLR_OFFSET) +# define AT32_GPIOB_HDRV (AT32_GPIOB_BASE+AT32_GPIO_HDRV_OFFSET) +#endif + +#if AT32_NGPIO_PORTS > 2 +# define AT32_GPIOC_CFGR (AT32_GPIOC_BASE+AT32_GPIO_CFGR_OFFSET) +# define AT32_GPIOC_OMODER (AT32_GPIOC_BASE+AT32_GPIO_OMODER_OFFSET) +# define AT32_GPIOC_ODRVR (AT32_GPIOC_BASE+AT32_GPIO_ODRVR_OFFSET) +# define AT32_GPIOC_PULL (AT32_GPIOC_BASE+AT32_GPIO_PULL_OFFSET) +# define AT32_GPIOC_IDT (AT32_GPIOC_BASE+AT32_GPIO_IDT_OFFSET) +# define AT32_GPIOC_ODT (AT32_GPIOC_BASE+AT32_GPIO_ODT_OFFSET) +# define AT32_GPIOC_SCR (AT32_GPIOC_BASE+AT32_GPIO_SCR_OFFSET) +# define AT32_GPIOC_WPR (AT32_GPIOC_BASE+AT32_GPIO_WPR_OFFSET) +# define AT32_GPIOC_MUXL (AT32_GPIOC_BASE+AT32_GPIO_MUXL_OFFSET) +# define AT32_GPIOC_MUXH (AT32_GPIOC_BASE+AT32_GPIO_MUXH_OFFSET) +# define AT32_GPIOC_CLR (AT32_GPIOC_BASE+AT32_GPIO_CLR_OFFSET) +# define AT32_GPIOC_HDRV (AT32_GPIOC_BASE+AT32_GPIO_HDRV_OFFSET) +#endif + +#if AT32_NGPIO_PORTS > 3 +# define AT32_GPIOD_CFGR (AT32_GPIOD_BASE+AT32_GPIO_CFGR_OFFSET) +# define AT32_GPIOD_OMODER (AT32_GPIOD_BASE+AT32_GPIO_OMODER_OFFSET) +# define AT32_GPIOD_ODRVR (AT32_GPIOD_BASE+AT32_GPIO_ODRVR_OFFSET) +# define AT32_GPIOD_PULL (AT32_GPIOD_BASE+AT32_GPIO_PULL_OFFSET) +# define AT32_GPIOD_IDT (AT32_GPIOD_BASE+AT32_GPIO_IDT_OFFSET) +# define AT32_GPIOD_ODT (AT32_GPIOD_BASE+AT32_GPIO_ODT_OFFSET) +# define AT32_GPIOD_SCR (AT32_GPIOD_BASE+AT32_GPIO_SCR_OFFSET) +# define AT32_GPIOD_WPR (AT32_GPIOD_BASE+AT32_GPIO_WPR_OFFSET) +# define AT32_GPIOD_MUXL (AT32_GPIOD_BASE+AT32_GPIO_MUXL_OFFSET) +# define AT32_GPIOD_MUXH (AT32_GPIOD_BASE+AT32_GPIO_MUXH_OFFSET) +# define AT32_GPIOD_CLR (AT32_GPIOD_BASE+AT32_GPIO_CLR_OFFSET) +# define AT32_GPIOD_HDRV (AT32_GPIOD_BASE+AT32_GPIO_HDRV_OFFSET) +#endif + +#if AT32_NGPIO_PORTS > 4 +# define AT32_GPIOE_CFGR (AT32_GPIOE_BASE+AT32_GPIO_CFGR_OFFSET) +# define AT32_GPIOE_OMODER (AT32_GPIOE_BASE+AT32_GPIO_OMODER_OFFSET) +# define AT32_GPIOE_ODRVR (AT32_GPIOE_BASE+AT32_GPIO_ODRVR_OFFSET) +# define AT32_GPIOE_PULL (AT32_GPIOE_BASE+AT32_GPIO_PULL_OFFSET) +# define AT32_GPIOE_IDT (AT32_GPIO_BASE+AT32_GPIO_IDT_OFFSET) +# define AT32_GPIOE_ODT (AT32_GPIOE_BASE+AT32_GPIO_ODT_OFFSET) +# define AT32_GPIOE_SCR (AT32_GPIOE_BASE+AT32_GPIO_SCR_OFFSET) +# define AT32_GPIOE_WPR (AT32_GPIOE_BASE+AT32_GPIO_WPR_OFFSET) +# define AT32_GPIOE_MUXL (AT32_GPIOE_BASE+AT32_GPIO_MUXL_OFFSET) +# define AT32_GPIOE_MUXH (AT32_GPIOE_BASE+AT32_GPIO_MUXH_OFFSET) +# define AT32_GPIOE_CLR (AT32_GPIOE_BASE+AT32_GPIO_CLR_OFFSET) +# define AT32_GPIOE_HDRV (AT32_GPIOE_BASE+AT32_GPIO_HDRV_OFFSET) +#endif + +#if AT32_NGPIO_PORTS > 5 +# define AT32_GPIOF_CFGR (AT32_GPIOF_BASE+AT32_GPIO_CFGR_OFFSET) +# define AT32_GPIOF_OMODER (AT32_GPIOF_BASE+AT32_GPIO_OMODER_OFFSET) +# define AT32_GPIOF_ODRVR (AT32_GPIOF_BASE+AT32_GPIO_ODRVR_OFFSET) +# define AT32_GPIOF_PULL (AT32_GPIOF_BASE+AT32_GPIO_PULL_OFFSET) +# define AT32_GPIOF_IDT (AT32_GPIOF_BASE+AT32_GPIO_IDT_OFFSET) +# define AT32_GPIOF_ODT (AT32_GPIOF_BASE+AT32_GPIO_ODT_OFFSET) +# define AT32_GPIOF_SCR (AT32_GPIOF_BASE+AT32_GPIO_SCR_OFFSET) +# define AT32_GPIOF_WPR (AT32_GPIOF_BASE+AT32_GPIO_WPR_OFFSET) +# define AT32_GPIOF_MUXL (AT32_GPIOF_BASE+AT32_GPIO_MUXL_OFFSET) +# define AT32_GPIOF_MUXH (AT32_GPIOF_BASE+AT32_GPIO_MUXH_OFFSET) +# define AT32_GPIOF_CLR (AT32_GPIOF_BASE+AT32_GPIO_CLR_OFFSET) +# define AT32_GPIOF_HDRV (AT32_GPIOF_BASE+AT32_GPIO_HDRV_OFFSET) +#endif + +#if AT32_NGPIO_PORTS > 6 +# define AT32_GPIOG_CFGR (AT32_GPIOG_BASE+AT32_GPIO_CFGR_OFFSET) +# define AT32_GPIOG_OMODER (AT32_GPIOG_BASE+AT32_GPIO_OMODER_OFFSET) +# define AT32_GPIOG_ODRVR (AT32_GPIOG_BASE+AT32_GPIO_ODRVR_OFFSET) +# define AT32_GPIOG_PULL (AT32_GPIOG_BASE+AT32_GPIO_PULL_OFFSET) +# define AT32_GPIOG_IDT (AT32_GPIOG_BASE+AT32_GPIO_IDT_OFFSET) +# define AT32_GPIOG_ODT (AT32_GPIOG_BASE+AT32_GPIO_ODT_OFFSET) +# define AT32_GPIOG_SCR (AT32_GPIOG_BASE+AT32_GPIO_SCR_OFFSET) +# define AT32_GPIOG_WPR (AT32_GPIOG_BASE+AT32_GPIO_WPR_OFFSET) +# define AT32_GPIOG_MUXL (AT32_GPIOG_BASE+AT32_GPIO_MUXL_OFFSET) +# define AT32_GPIOG_MUXH (AT32_GPIOG_BASE+AT32_GPIO_MUXH_OFFSET) +# define AT32_GPIOG_CLR (AT32_GPIOG_BASE+AT32_GPIO_CLR_OFFSET) +# define AT32_GPIOG_HDRV (AT32_GPIOG_BASE+AT32_GPIO_HDRV_OFFSET) +#endif + +#if AT32_NGPIO_PORTS > 7 +# define AT32_GPIOH_CFGR (AT32_GPIOH_BASE+AT32_GPIO_CFGR_OFFSET) +# define AT32_GPIOH_OMODER (AT32_GPIOH_BASE+AT32_GPIO_OMODER_OFFSET) +# define AT32_GPIOH_ODRVR (AT32_GPIOH_BASE+AT32_GPIO_ODRVR_OFFSET) +# define AT32_GPIOH_PULL (AT32_GPIOH_BASE+AT32_GPIO_PULL_OFFSET) +# define AT32_GPIOH_IDT (AT32_GPIOH_BASE+AT32_GPIO_IDT_OFFSET) +# define AT32_GPIOH_ODT (AT32_GPIOH_BASE+AT32_GPIO_ODT_OFFSET) +# define AT32_GPIOH_SCR (AT32_GPIOH_BASE+AT32_GPIO_SCR_OFFSET) +# define AT32_GPIOH_WPR (AT32_GPIOH_BASE+AT32_GPIO_WPR_OFFSET) +# define AT32_GPIOH_MUXL (AT32_GPIOH_BASE+AT32_GPIO_MUXL_OFFSET) +# define AT32_GPIOH_MUXH (AT32_GPIOH_BASE+AT32_GPIO_MUXH_OFFSET) +# define AT32_GPIOH_CLR (AT32_GPIOH_BASE+AT32_GPIO_CLR_OFFSET) +# define AT32_GPIOH_HDRV (AT32_GPIOH_BASE+AT32_GPIO_HDRV_OFFSET) +#endif + +/* Register Bitfield Definitions ********************************************/ + +/* GPIO port config register */ + +#define GPIO_CFGR_INPUT (0) /* Input mode */ +#define GPIO_CFGR_OUTPUT (1) /* Output mode */ +#define GPIO_CFGR_AF (2) /* Alternate mode */ +#define GPIO_CFGR_ANALOG (3) /* Analog mode */ + +#define GPIO_CFGR_SHIFT(n) ((n) << 1) +#define GPIO_CFGR_MASK(n) (3 << GPIO_CFGR_SHIFT(n)) + +#define GPIO_CFGR0_SHIFT (0) +#define GPIO_CFGR0_MASK (3 << GPIO_CFGR0_SHIFT) +#define GPIO_CFGR1_SHIFT (2) +#define GPIO_CFGR1_MASK (3 << GPIO_CFGR1_SHIFT) +#define GPIO_CFGR2_SHIFT (4) +#define GPIO_CFGR2_MASK (3 << GPIO_CFGR2_SHIFT) +#define GPIO_CFGR3_SHIFT (6) +#define GPIO_CFGR3_MASK (3 << GPIO_CFGR3_SHIFT) +#define GPIO_CFGR4_SHIFT (8) +#define GPIO_CFGR4_MASK (3 << GPIO_CFGR4_SHIFT) +#define GPIO_CFGR5_SHIFT (10) +#define GPIO_CFGR5_MASK (3 << GPIO_CFGR5_SHIFT) +#define GPIO_CFGR6_SHIFT (12) +#define GPIO_CFGR6_MASK (3 << GPIO_CFGR6_SHIFT) +#define GPIO_CFGR7_SHIFT (14) +#define GPIO_CFGR7_MASK (3 << GPIO_CFGR7_SHIFT) +#define GPIO_CFGR8_SHIFT (16) +#define GPIO_CFGR8_MASK (3 << GPIO_CFGR8_SHIFT) +#define GPIO_CFGR9_SHIFT (18) +#define GPIO_CFGR9_MASK (3 << GPIO_CFGR9_SHIFT) +#define GPIO_CFGR10_SHIFT (20) +#define GPIO_CFGR10_MASK (3 << GPIO_CFGR10_SHIFT) +#define GPIO_CFGR11_SHIFT (22) +#define GPIO_CFGR11_MASK (3 << GPIO_CFGR11_SHIFT) +#define GPIO_CFGR12_SHIFT (24) +#define GPIO_CFGR12_MASK (3 << GPIO_CFGR12_SHIFT) +#define GPIO_CFGR13_SHIFT (26) +#define GPIO_CFGR13_MASK (3 << GPIO_CFGR13_SHIFT) +#define GPIO_CFGR14_SHIFT (28) +#define GPIO_CFGR14_MASK (3 << GPIO_CFGR14_SHIFT) +#define GPIO_CFGR15_SHIFT (30) +#define GPIO_CFGR15_MASK (3 << GPIO_CFGR15_SHIFT) + +/* GPIO port output type register */ + +#define GPIO_OMODER_OD(n) (1 << (n)) /* 1=Output open-drain */ +#define GPIO_OMODER_PP(n) (0) /* 0=Output push-pull */ + +/* GPIO output dirve capability */ + +#define GPIO_ODRVR_MODERATE (0) /* moderate drive */ +#define GPIO_ODRVR_STRONG (1) /* strong drive */ + +#define GPIO_ODRVR_SHIFT(n) ((n) << 1) +#define GPIO_ODRVR_MASK(n) (3 << GPIO_ODRVR_SHIFT(n)) + +#define GPIO_ODRVR0_SHIFT (0) +#define GPIO_ODRVR0_MASK (3 << GPIO_ODRVR0_SHIFT) +#define GPIO_ODRVR1_SHIFT (2) +#define GPIO_ODRVR1_MASK (3 << GPIO_ODRVR1_SHIFT) +#define GPIO_ODRVR2_SHIFT (4) +#define GPIO_ODRVR2_MASK (3 << GPIO_ODRVR2_SHIFT) +#define GPIO_ODRVR3_SHIFT (6) +#define GPIO_ODRVR3_MASK (3 << GPIO_ODRVR3_SHIFT) +#define GPIO_ODRVR4_SHIFT (8) +#define GPIO_ODRVR4_MASK (3 << GPIO_ODRVR4_SHIFT) +#define GPIO_ODRVR5_SHIFT (10) +#define GPIO_ODRVR5_MASK (3 << GPIO_ODRVR5_SHIFT) +#define GPIO_ODRVR6_SHIFT (12) +#define GPIO_ODRVR6_MASK (3 << GPIO_ODRVR6_SHIFT) +#define GPIO_ODRVR7_SHIFT (14) +#define GPIO_ODRVR7_MASK (3 << GPIO_ODRVR7_SHIFT) +#define GPIO_ODRVR8_SHIFT (16) +#define GPIO_ODRVR8_MASK (3 << GPIO_ODRVR8_SHIFT) +#define GPIO_ODRVR9_SHIFT (18) +#define GPIO_ODRVR9_MASK (3 << GPIO_ODRVR9_SHIFT) +#define GPIO_ODRVR10_SHIFT (20) +#define GPIO_ODRVR10_MASK (3 << GPIO_ODRVR10_SHIFT) +#define GPIO_ODRVR11_SHIFT (22) +#define GPIO_ODRVR11_MASK (3 << GPIO_ODRVR11_SHIFT) +#define GPIO_ODRVR12_SHIFT (24) +#define GPIO_ODRVR12_MASK (3 << GPIO_ODRVR12_SHIFT) +#define GPIO_ODRVR13_SHIFT (26) +#define GPIO_ODRVR13_MASK (3 << GPIO_ODRVR13_SHIFT) +#define GPIO_ODRVR14_SHIFT (28) +#define GPIO_ODRVR14_MASK (3 << GPIO_ODRVR14_SHIFT) +#define GPIO_ODRVR15_SHIFT (30) +#define GPIO_ODRVR15_MASK (3 << GPIO_ODRVR15_SHIFT) + +/* GPIO port pull-up/pull-down register */ + +#define GPIO_PULL_NONE (0) /* No pull-up, pull-down */ +#define GPIO_PULL_PULLUP (1) /* Pull-up */ +#define GPIO_PULL_PULLDOWN (2) /* Pull-down */ + +#define GPIO_PULL_SHIFT(n) ((n) << 1) +#define GPIO_PULL_MASK(n) (3 << GPIO_PULL_SHIFT(n)) + +#define GPIO_PULL0_SHIFT (0) +#define GPIO_PULL0_MASK (3 << GPIO_PULL0_SHIFT) +#define GPIO_PULL1_SHIFT (2) +#define GPIO_PULL1_MASK (3 << GPIO_PULL1_SHIFT) +#define GPIO_PULL2_SHIFT (4) +#define GPIO_PULL2_MASK (3 << GPIO_PULL2_SHIFT) +#define GPIO_PULL3_SHIFT (6) +#define GPIO_PULL3_MASK (3 << GPIO_PULL3_SHIFT) +#define GPIO_PULL4_SHIFT (8) +#define GPIO_PULL4_MASK (3 << GPIO_PULL4_SHIFT) +#define GPIO_PULL5_SHIFT (10) +#define GPIO_PULL5_MASK (3 << GPIO_PULL5_SHIFT) +#define GPIO_PULL6_SHIFT (12) +#define GPIO_PULL6_MASK (3 << GPIO_PULL6_SHIFT) +#define GPIO_PULL7_SHIFT (14) +#define GPIO_PULL7_MASK (3 << GPIO_PULL7_SHIFT) +#define GPIO_PULL8_SHIFT (16) +#define GPIO_PULL8_MASK (3 << GPIO_PULL8_SHIFT) +#define GPIO_PULL9_SHIFT (18) +#define GPIO_PULL9_MASK (3 << GPIO_PULL9_SHIFT) +#define GPIO_PULL10_SHIFT (20) +#define GPIO_PULL10_MASK (3 << GPIO_PULL10_SHIFT) +#define GPIO_PULL11_SHIFT (22) +#define GPIO_PULL11_MASK (3 << GPIO_PULL11_SHIFT) +#define GPIO_PULL12_SHIFT (24) +#define GPIO_PULL12_MASK (3 << GPIO_PULL12_SHIFT) +#define GPIO_PULL13_SHIFT (26) +#define GPIO_PULL13_MASK (3 << GPIO_PULL13_SHIFT) +#define GPIO_PULL14_SHIFT (28) +#define GPIO_PULL14_MASK (3 << GPIO_PULL14_SHIFT) +#define GPIO_PULL15_SHIFT (30) +#define GPIO_PULL15_MASK (3 << GPIO_PULL15_SHIFT) + +/* GPIO port input data register */ + +#define GPIO_IDT(n) (1 << (n)) + +/* GPIO port output data register */ + +#define GPIO_ODT(n) (1 << (n)) + +/* GPIO port bit set/reset register */ + +#define GPIO_SCR_SET(n) (1 << (n)) +#define GPIO_SCR_RESET(n) (1 << ((n)+16)) + +/* GPIO port configuration protect register */ + +#define GPIO_PWR_WPEN(n) (1 << (n)) +#define GPIO_PWR_WPSEQ (1 << 16) /* Lock key */ + +/* GPIO alternate function low/high register */ + +#define GPIO_MUX_SHIFT(n) ((n) << 2) +#define GPIO_MUX_MASK(n) (15 << GPIO_MUX_SHIFT(n)) + +#define GPIO_MUXL0_SHIFT (0) +#define GPIO_MUXL0_MASK (15 << GPIO_MUXL0_SHIFT) +#define GPIO_MUXL1_SHIFT (4) +#define GPIO_MUXL1_MASK (15 << GPIO_MUXL1_SHIFT) +#define GPIO_MUXL2_SHIFT (8) +#define GPIO_MUXL2_MASK (15 << GPIO_MUXL2_SHIFT) +#define GPIO_MUXL3_SHIFT (12) +#define GPIO_MUXL3_MASK (15 << GPIO_MUXL3_SHIFT) +#define GPIO_MUXL4_SHIFT (16) +#define GPIO_MUXL4_MASK (15 << GPIO_MUXL4_SHIFT) +#define GPIO_MUXL5_SHIFT (20) +#define GPIO_MUXL5_MASK (15 << GPIO_MUXL5_SHIFT) +#define GPIO_MUXL6_SHIFT (24) +#define GPIO_MUXL6_MASK (15 << GPIO_MUXL6_SHIFT) +#define GPIO_MUXL7_SHIFT (28) +#define GPIO_MUXL7_MASK (15 << GPIO_MUXL7_SHIFT) +#define GPIO_MUXH8_SHIFT (0) +#define GPIO_MUXH8_MASK (15 << GPIO_MUXH8_SHIFT) +#define GPIO_MUXH9_SHIFT (4) +#define GPIO_MUXH9_MASK (15 << GPIO_MUXH9_SHIFT) +#define GPIO_MUXH10_SHIFT (8) +#define GPIO_MUXH10_MASK (15 << GPIO_MUXH10_SHIFT) +#define GPIO_MUXH11_SHIFT (12) +#define GPIO_MUXH11_MASK (15 << GPIO_MUXH11_SHIFT) +#define GPIO_MUXH12_SHIFT (16) +#define GPIO_MUXH12_MASK (15 << GPIO_MUXH12_SHIFT) +#define GPIO_MUXH13_SHIFT (20) +#define GPIO_MUXH13_MASK (15 << GPIO_MUXH13_SHIFT) +#define GPIO_MUXH14_SHIFT (24) +#define GPIO_MUXH14_MASK (15 << GPIO_MUXH14_SHIFT) +#define GPIO_MUXH15_SHIFT (28) +#define GPIO_MUXH15_MASK (15 << GPIO_MUXH15_SHIFT) + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_GPIO_H */ \ No newline at end of file diff --git a/arch/arm/src/at32/hardware/at32f43xxx_memorymap.h b/arch/arm/src/at32/hardware/at32f43xxx_memorymap.h new file mode 100644 index 0000000000..05947335ae --- /dev/null +++ b/arch/arm/src/at32/hardware/at32f43xxx_memorymap.h @@ -0,0 +1,217 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32f43xxx_memorymap.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_MEMORYMAP_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_MEMORYMAP_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* AT32F43XXX Address Blocks ************************************************/ + +#define AT32_CODE_BASE 0x00000000 /* 0x00000000-0x1fffffff: 512Mb code block */ +#define AT32_SRAM_BASE 0x20000000 /* 0x20000000-0x3fffffff: 512Mb sram block */ +#define AT32_PERIPH_BASE 0x40000000 /* 0x40000000-0x5fffffff: 512Mb peripheral block */ +#define AT32_FSMC_BANK1 0x60000000 /* 0x60000000-0x6fffffff: 256Mb NOR/PSRMA/SRAM */ + /* 0x70000000-0x7fffffff: Reserved */ +#define AT32_FSMC_BANK3 0x80000000 /* 0x80000000-0x8fffffff: 256Mb NAND FLASH */ +#define AT32_QSPI_BANK1 0x90000000 /* 0x90000000-0x9fffffff: 256Mb QUADSPI */ + +#define AT32_FMC_QSPI_BASE 0xa0000000 /* 0xa0000000-0xa0002fff: FMC and QUADSPI registers */ + /* 0xa0003000-0xa7ffffff: Reserved */ + +#define AT32_FMC_PC_CARD 0xa8000000 /* 0xa8000000-0xafffffff: 128Mb PC card */ + +#define AT32_FMC_QSPI2 0xb0000000 /* 0xb0000000-0xbfffffff: 128Mb FMC QSPI2 */ + +#define AT32_FMX_SDRAM 0xc0000000 /* 0xc0000000-0xdfffffff: 256Mb SDRAM */ + +#define AT32_CORTEX_BASE 0xe0000000 /* 0xe0000000-0xffffffff: 512Mb Cortex-M4 block */ + +#define AT32_REGION_MASK 0xf0000000 +#define AT32_IS_SRAM(a) ((((uint32_t)(a)) & AT32_REGION_MASK) == AT32_SRAM_BASE) + +/* Code Base Addresses ******************************************************/ + +#define AT32_BOOT_BASE 0x00000000 /* 0x00000000-0x000fffff: Aliased boot memory */ + /* 0x00100000-0x07ffffff: Reserved */ +#define AT32_FLASH_BASE 0x08000000 /* 0x08000000-0x080fffff: FLASH memory */ + /* 0x08100000-0x0fffffff: Reserved */ +#define AT32_CCMRAM_BASE 0x10000000 /* 0x10000000-0x1000ffff: 64Kb CCM data RAM */ + /* 0x10010000-0x1ffeffff: Reserved */ +#define AT32_SYSMEM_BASE 0x1fff0000 /* 0x1fff0000-0x1fff7a0f: System memory */ + /* 0x1fff7a10-0x1fff7fff: Reserved */ +#define AT32_OPTION_BASE 0x1fffc000 /* 0x1fffc000-0x1fffc007: Option bytes */ + /* 0x1fffc008-0x1fffffff: Reserved */ + +/* System Memory Addresses **************************************************/ + +#define AT32_SYSMEM_UID 0x1ffff7e8 /* The 96-bit unique device identifier */ +#define AT32_SYSMEM_FSIZE 0x1ffff7e0 /* This bitfield indicates the size of + * the device Flash memory expressed in + * Kbytes. Example: 0x0400 corresponds + * to 1024 Kbytes. + */ + +/* SRAM Base Addresses ******************************************************/ + +/* 0x20000000-0x2001bfff: + * 112Kb aliased by bit-banding + */ + +/* 0x2001c000-0x2001ffff: + * 16Kb aliased by bit-banding + */ + +#define AT32_SRAMBB_BASE 0x22000000 /* 0x22000000- : SRAM bit-band region */ + +/* Peripheral Base Addresses ************************************************/ + +#define AT32_APB1_BASE 0x40000000 /* 0x40000000-0x400023ff: APB1 */ + /* 0x40002400-0x400027ff: Reserved */ + /* 0x40002800-0x400077ff: APB1 */ + /* 0x40007800-0x4000ffff: Reserved */ +#define AT32_APB2_BASE 0x40010000 /* 0x40010000-0x400023ff: APB2 */ + /* 0x40013400-0x400137ff: Reserved */ + /* 0x40013800-0x40013bff: SYSCFG */ +#define AT32_EXINT_BASE 0x40013c00 /* 0x40013c00-0x40013fff: EXINT */ + /* 0x40014000-0x40014bff: APB2 */ + /* 0x40014c00-0x4001ffff: Reserved */ +#define AT32_AHB1_BASE 0x40020000 /* 0x40020000-0x400223ff: APB1 */ + /* 0x40022400-0x40022fff: Reserved */ + /* 0x40023000-0x400233ff: CRC */ + /* 0x40023400-0x400237ff: Reserved */ + /* 0x40023800-0x40023bff: Reset and Clock control RCC */ + /* 0x40023c00-0x400293ff: AHB1 (?) */ + /* 0x40029400-0x4fffffff: Reserved (?) */ +#define AT32_AHB2_BASE 0x50000000 /* 0x50000000-0x5003ffff: AHB2 */ + /* 0x50040000-0x5004ffff: Reserved */ + /* 0x50050000-0x500503ff: AHB2 */ + /* 0x50050400-0x500607ff: Reserved */ + /* 0x50060800-0x50060bff: AHB2 */ + /* 0x50060c00-0x5fffffff: Reserved */ + +/* FSMC Base Addresses ******************************************************/ + +#define AT32_AHB3_BASE 0x60000000 /* 0x60000000-0xa0000fff: AHB3 */ + +/* APB1 Base Addresses ******************************************************/ + +#define AT32_TMR2_BASE 0x40000000 /* 0x40000000-0x400003ff: TMR2 timer */ +#define AT32_TMR3_BASE 0x40000400 /* 0x40000400-0x400007ff: TMR3 timer */ +#define AT32_TMR4_BASE 0x40000800 /* 0x40000800-0x40000bff: TMR4 timer */ +#define AT32_TMR5_BASE 0x40000c00 /* 0x40000c00-0x40000fff: TMR5 timer */ +#define AT32_TMR6_BASE 0x40001000 /* 0x40001000-0x400013ff: TMR6 timer */ +#define AT32_TMR7_BASE 0x40001400 /* 0x40001400-0x400017ff: TMR7 timer */ +#define AT32_TMR12_BASE 0x40001800 /* 0x40001800-0x40001bff: TMR12 timer */ +#define AT32_TMR13_BASE 0x40001c00 /* 0x40001c00-0x40001fff: TMR13 timer */ +#define AT32_TMR14_BASE 0x40002000 /* 0x40002000-0x400023ff: TMR14 timer */ +#define AT32_ERTC_BASE 0x40002800 /* 0x40002800-0x40002bff: ERTC & BKP registers */ +#define AT32_WWDT_BASE 0x40002c00 /* 0x40002c00-0x40002fff: Window watchdog (WWDG) */ +#define AT32_WDT_BASE 0x40003000 /* 0x40003000-0x400033ff: Independent watchdog (IWDG) */ +#define AT32_SPI2_BASE 0x40003800 /* 0x40003800-0x40003bff: SPI2/I2S2 */ +#define AT32_I2S2_BASE 0x40003800 +#define AT32_SPI3_BASE 0x40003c00 /* 0x40003c00-0x40003fff: SPI3/I2S3 */ +#define AT32_I2S3_BASE 0x40003c00 +#define AT32_USART2_BASE 0x40004400 /* 0x40004400-0x400047ff: USART2 */ +#define AT32_USART3_BASE 0x40004800 /* 0x40004800-0x40004bff: USART3 */ +#define AT32_UART4_BASE 0x40004c00 /* 0x40004c00-0x40004fff: UART4 */ +#define AT32_UART5_BASE 0x40005000 /* 0x40005000-0x400053ff: UART5 */ +#define AT32_I2C1_BASE 0x40005400 /* 0x40005400-0x400057ff: I2C1 */ +#define AT32_I2C2_BASE 0x40005800 /* 0x40005800-0x40005Bff: I2C2 */ +#define AT32_I2C3_BASE 0x40005c00 /* 0x40005c00-0x40005fff: I2C3 */ +#define AT32_CAN1_BASE 0x40006400 /* 0x40006400-0x400067ff: bxCAN1 */ +#define AT32_CAN2_BASE 0x40006800 /* 0x40006800-0x40006bff: bxCAN2 */ +#define AT32_PWC_BASE 0x40007000 /* 0x40007000-0x400073ff: Power control PWR */ +#define AT32_DAC_BASE 0x40007400 /* 0x40007400-0x400077ff: DAC */ +#define AT32_UART7_BASE 0x40007800 /* 0x40007800-0x40007bff: UART7 */ +#define AT32_UART8_BASE 0x40007c00 /* 0x40007c00-0x40007fff: UART8 */ + +/* APB2 Base Addresses ******************************************************/ + +#define AT32_TMR1_BASE 0x40010000 /* 0x40010000-0x400103ff: TMR1 timer */ +#define AT32_TMR8_BASE 0x40010400 /* 0x40010400-0x400107ff: TMR8 timer */ +#define AT32_USART1_BASE 0x40011000 /* 0x40011000-0x400113ff: USART1 */ +#define AT32_USART6_BASE 0x40011400 /* 0x40011400-0x400117ff: USART6 */ +#define AT32_ADC_BASE 0x40012000 /* 0x40012000-0x400123ff: ADC1-3 */ +#define AT32_SPI1_BASE 0x40013000 /* 0x40013000-0x400133ff: SPI1 */ +#define AT32_I2S1_BASE 0x40013000 +#define AT32_SPI4_BASE 0x40013400 /* 0x40013000-0x400137ff: SPI4 */ +#define AT32_I2S4_BASE 0x40013400 +#define AT32_SCFG_BASE 0x40013800 /* 0x40013800-0x40013bff: SCFG */ +#define AT32_EXINT_BASE 0x40013c00 /* 0x40013c00-0x40013fff: EXINT */ +#define AT32_TMR9_BASE 0x40014000 /* 0x40014000-0x400143ff: TMR9 timer */ +#define AT32_TMR10_BASE 0x40014400 /* 0x40014400-0x400147ff: TMR10 timer */ +#define AT32_TMR11_BASE 0x40014800 /* 0x40014800-0x40014bff: TMR11 timer */ +#define AT32_TMR20_BASE 0x40014C00 /* 0x40014C00-0x400173ff: TMR20 timer */ +#define AT32_ACC_BASE 0x40017400 /* 0x40017400-0x400177ff: ACC */ +#define AT32_I2S2EXT_BASE 0x40017800 /* 0x40017800-0x40017bff: I2S2EXT */ +#define AT32_I2S3EXT_BASE 0x40017C00 /* 0x40017C00-0x40017fff: I2S3EXT */ + +/* AHB1 Base Addresses ******************************************************/ + +#define AT32_GPIOA_BASE 0x40020000 /* 0x40020000-0x400203ff: GPIO Port A */ +#define AT32_GPIOB_BASE 0x40020400 /* 0x40020400-0x400207ff: GPIO Port B */ +#define AT32_GPIOC_BASE 0x40020800 /* 0x40020800-0x40020bff: GPIO Port C */ +#define AT32_GPIOD_BASE 0X40020C00 /* 0x40020c00-0x40020fff: GPIO Port D */ +#define AT32_GPIOE_BASE 0x40021000 /* 0x40021000-0x400213ff: GPIO Port E */ +#define AT32_GPIOF_BASE 0x40021400 /* 0x40021400-0x400217ff: GPIO Port F */ +#define AT32_GPIOG_BASE 0x40021800 /* 0x40021800-0x40021bff: GPIO Port G */ +#define AT32_GPIOH_BASE 0x40021C00 /* 0x40021C00-0x40021fff: GPIO Port H */ + +#define AT32_CRC_BASE 0x40023000 /* 0x40023000-0x400233ff: CRC */ +#define AT32_CRM_BASE 0x40023800 /* 0x40023800-0x40023bff: Reset and Clock control RCC */ +#define AT32_FLASHIF_BASE 0x40023c00 /* 0x40023c00-0x40023fff: Flash memory interface */ + +#define AT32_EDMA_BASE 0x40026000 /* 0x40026000-0x400263ff: EDMA */ +#define AT32_DMA1_BASE 0x40026400 /* 0x40026400-0x400265ff: DMA1 */ +#define AT32_DMA2_BASE 0x40026600 /* 0x40026600-0x400267ff: DMA2 */ + +#define AT32_DMAMUX1_BASE 0x40026500 /* 0x40026500-0x400265ff: DMA1 MUX */ +#define AT32_DMAMUX2_BASE 0x40026700 /* 0x40026700-0x400267ff: DMA2 MUX */ + +#define AT32_EMAC_BASE 0x40028000 /* 0x40028000-0x400283ff: Ethernet MAC */ + /* 0x40028400-0x400287ff: Ethernet MAC */ + /* 0x40028800-0x40028bff: Ethernet MAC */ + /* 0x40028c00-0x40028fff: Ethernet MAC */ + /* 0x40029000-0x400293ff: Ethernet MAC */ + +#define AT32_OTGFS2_BASE 0x40040000 /* 0x40040000-0x4007ffff: USB OTG FS2 */ +#define AT32_SDIO1_BASE 0x4002C400 /* 0x4002c400-0x4002c7ff: SDIO1 */ + +#define AT32_PERIPHBB_BASE 0x42000000 /* Peripheral bit-band region */ + +/* AHB2 Base Addresses ******************************************************/ + +#define AT32_OTGFS1_BASE 0x50000000 /* 0x50000000-0x5003ffff: USB OTG FS1 */ +#define AT32_DVP_BASE 0x50050000 /* 0x50050000-0x500503ff: DVP */ +#define AT32_SDIO2_BASE 0x50061000 /* 0x50061000-0x500613ff: SDIO2 */ + +/* Cortex-M4 Base Addresses *************************************************/ + +/* Other registers -- see armv7-m/nvic.h for standard Cortex-M3 registers in + * this address range + */ + +#define AT32_SCS_BASE 0xe000e000 +#define AT32_DEBUGMCU_BASE 0xe0042000 + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_MEMORYMAP_H */ diff --git a/arch/arm/src/at32/hardware/at32f43xxx_pinmap.h b/arch/arm/src/at32/hardware/at32f43xxx_pinmap.h new file mode 100644 index 0000000000..ad085027ae --- /dev/null +++ b/arch/arm/src/at32/hardware/at32f43xxx_pinmap.h @@ -0,0 +1,897 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32f43xxx_pinmap.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_PINMAP_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_PINMAP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "at32_gpio.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Alternate Pin Functions. + * All members of the AT32F43xxx family share the same pin multiplexing + * (although they may differ in the pins physically available). + * + * Alternative pin selections are provided with a numeric suffix like _1, _2, + * etc. Drivers, however, will use the pin selection without the numeric + * suffix. Additional definitions are required in the board.h file. For + * example, if CAN1_RX connects via PA11 on some board, then the following + * definitions should appear in the board.h header file for that board: + * + * #define GPIO_CAN1_RX GPIO_CAN1_RX_1 + * + * The driver will then automatically configure PA11 as the CAN1 RX pin. + */ + +/* WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! + * Additional effort is required to select specific GPIO options such as + * frequency, open-drain/push-pull, and pull-up/down! + * Just the basics are defined for most pins in this file. + */ + +/* ADC */ + +#define GPIO_ADC1_IN0 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN0) +#define GPIO_ADC1_IN1 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN1) +#define GPIO_ADC1_IN2 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN2) +#define GPIO_ADC1_IN3 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN3) +#define GPIO_ADC1_IN4 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN4) +#define GPIO_ADC1_IN5 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN5) +#define GPIO_ADC1_IN6 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN6) +#define GPIO_ADC1_IN7 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN7) +#define GPIO_ADC1_IN8 (GPIO_ANALOG|GPIO_PORTB|GPIO_PIN0) +#define GPIO_ADC1_IN9 (GPIO_ANALOG|GPIO_PORTB|GPIO_PIN1) +#define GPIO_ADC1_IN10 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN0) +#define GPIO_ADC1_IN11 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN1) +#define GPIO_ADC1_IN12 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN2) +#define GPIO_ADC1_IN13 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN3) +#define GPIO_ADC1_IN14 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN4) +#define GPIO_ADC1_IN15 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN5) + +#define GPIO_ADC2_IN0 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN0) +#define GPIO_ADC2_IN1 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN1) +#define GPIO_ADC2_IN2 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN2) +#define GPIO_ADC2_IN3 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN3) +#define GPIO_ADC2_IN4 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN4) +#define GPIO_ADC2_IN5 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN5) +#define GPIO_ADC2_IN6 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN6) +#define GPIO_ADC2_IN7 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN7) +#define GPIO_ADC2_IN8 (GPIO_ANALOG|GPIO_PORTB|GPIO_PIN0) +#define GPIO_ADC2_IN9 (GPIO_ANALOG|GPIO_PORTB|GPIO_PIN1) +#define GPIO_ADC2_IN10 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN0) +#define GPIO_ADC2_IN11 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN1) +#define GPIO_ADC2_IN12 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN2) +#define GPIO_ADC2_IN13 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN3) +#define GPIO_ADC2_IN14 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN4) +#define GPIO_ADC2_IN15 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN5) + +#define GPIO_ADC3_IN0 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN0) +#define GPIO_ADC3_IN1 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN1) +#define GPIO_ADC3_IN2 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN2) +#define GPIO_ADC3_IN3 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN3) +#define GPIO_ADC3_IN4 (GPIO_ANALOG|GPIO_PORTF|GPIO_PIN6) +#define GPIO_ADC3_IN5 (GPIO_ANALOG|GPIO_PORTF|GPIO_PIN7) +#define GPIO_ADC3_IN6 (GPIO_ANALOG|GPIO_PORTF|GPIO_PIN8) +#define GPIO_ADC3_IN7 (GPIO_ANALOG|GPIO_PORTF|GPIO_PIN9) +#define GPIO_ADC3_IN8 (GPIO_ANALOG|GPIO_PORTF|GPIO_PIN10) +#define GPIO_ADC3_IN9 (GPIO_ANALOG|GPIO_PORTF|GPIO_PIN3) +#define GPIO_ADC3_IN10 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN0) +#define GPIO_ADC3_IN11 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN1) +#define GPIO_ADC3_IN12 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN2) +#define GPIO_ADC3_IN13 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN3) +#define GPIO_ADC3_IN14 (GPIO_ANALOG|GPIO_PORTF|GPIO_PIN4) +#define GPIO_ADC3_IN15 (GPIO_ANALOG|GPIO_PORTF|GPIO_PIN5) + +/* CAN */ + +#define GPIO_CAN1_RX_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN11) +#define GPIO_CAN1_RX_2 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN8) +#define GPIO_CAN1_RX_3 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN0) +#define GPIO_CAN1_RX_4 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN0) +#define GPIO_CAN1_TX_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN12) +#define GPIO_CAN1_TX_2 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN9) +#define GPIO_CAN1_TX_3 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN1) +#define GPIO_CAN1_TX_4 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN1) + +#define GPIO_CAN2_RX_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN12) +#define GPIO_CAN2_RX_2 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN5) +#define GPIO_CAN2_RX_3 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN11) +#define GPIO_CAN2_TX_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN13) +#define GPIO_CAN2_TX_2 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN6) +#define GPIO_CAN2_TX_3 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN12) + +/* DAC - "Once the DAC channelx is enabled, the corresponding GPIO pin + * (PA4 or PA5) is automatically connected to the analog converter output + * (DAC_OUTx). In order to avoid parasitic consumption, the PA4 or PA5 pin + * should first be configured to analog (AIN)". + */ + +#define GPIO_DAC1_OUT1 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN4) +#define GPIO_DAC1_OUT2 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN5) + +/* Digital Camera Interface (DCMI) */ + +#define GPIO_DCMI_D0_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTA|GPIO_PIN9) +#define GPIO_DCMI_D0_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTC|GPIO_PIN6) +#define GPIO_DCMI_D1_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTA|GPIO_PIN10) +#define GPIO_DCMI_D1_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTC|GPIO_PIN7) +#define GPIO_DCMI_D2_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTC|GPIO_PIN8) +#define GPIO_DCMI_D2_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTE|GPIO_PIN0) +#define GPIO_DCMI_D2_3 (GPIO_ALT|GPIO_AF13|GPIO_PORTA|GPIO_PIN11) +#define GPIO_DCMI_D2_4 (GPIO_ALT|GPIO_AF13|GPIO_PORTG|GPIO_PIN10) +#define GPIO_DCMI_D3_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTC|GPIO_PIN9) +#define GPIO_DCMI_D3_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTE|GPIO_PIN1) +#define GPIO_DCMI_D3_3 (GPIO_ALT|GPIO_AF13|GPIO_PORTA|GPIO_PIN12) +#define GPIO_DCMI_D3_4 (GPIO_ALT|GPIO_AF13|GPIO_PORTG|GPIO_PIN11) +#define GPIO_DCMI_D4_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTC|GPIO_PIN11) +#define GPIO_DCMI_D4_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTE|GPIO_PIN4) +#define GPIO_DCMI_D4_3 (GPIO_ALT|GPIO_AF13|GPIO_PORTB|GPIO_PIN3) +#define GPIO_DCMI_D5_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTB|GPIO_PIN6) +#define GPIO_DCMI_D5_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTB|GPIO_PIN4) +#define GPIO_DCMI_D5_3 (GPIO_ALT|GPIO_AF13|GPIO_PORTD|GPIO_PIN3) +#define GPIO_DCMI_D6_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTB|GPIO_PIN8) +#define GPIO_DCMI_D6_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTE|GPIO_PIN5) +#define GPIO_DCMI_D7_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTB|GPIO_PIN9) +#define GPIO_DCMI_D7_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTE|GPIO_PIN6) +#define GPIO_DCMI_D8_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTC|GPIO_PIN10) +#define GPIO_DCMI_D9_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTC|GPIO_PIN12) +#define GPIO_DCMI_D9_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTE|GPIO_PIN3) +#define GPIO_DCMI_D10_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTB|GPIO_PIN5) +#define GPIO_DCMI_D10_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTD|GPIO_PIN6) +#define GPIO_DCMI_D11_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTD|GPIO_PIN2) +#define GPIO_DCMI_D11_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTF|GPIO_PIN10) +#define GPIO_DCMI_D12_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTF|GPIO_PIN11) +#define GPIO_DCMI_D12_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTG|GPIO_PIN6) +#define GPIO_DCMI_D13_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTG|GPIO_PIN15) +#define GPIO_DCMI_D13_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTG|GPIO_PIN7) +#define GPIO_DCMI_HSYNC_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTA|GPIO_PIN4) +#define GPIO_DCMI_PIXCLK (GPIO_ALT|GPIO_AF13|GPIO_PORTA|GPIO_PIN6) +#define GPIO_DCMI_VSYNC_1 (GPIO_ALT|GPIO_AF13|GPIO_PORTB|GPIO_PIN7) +#define GPIO_DCMI_VSYNC_2 (GPIO_ALT|GPIO_AF13|GPIO_PORTG|GPIO_PIN9) + +/* Clocks outputs */ + +#define GPIO_MCO1 (GPIO_ALT|GPIO_AF0|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN8) +#define GPIO_MCO2 (GPIO_ALT|GPIO_AF0|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN9) + +/* Ethernet MAC */ + +#if defined(CONFIG_AT32_AT32F437) +# define GPIO_ETH_MDC (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN1) +# define GPIO_ETH_MDIO (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN2) +# define GPIO_ETH_MII_COL_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN3) +# define GPIO_ETH_MII_COL_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTH|GPIO_PIN3) +# define GPIO_ETH_MII_CRS_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN0) +# define GPIO_ETH_MII_CRS_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTH|GPIO_PIN2) +# define GPIO_ETH_MII_RXD0 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN4) +# define GPIO_ETH_MII_RXD1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN5) +# define GPIO_ETH_MII_RXD2_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN0) +# define GPIO_ETH_MII_RXD2_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTH|GPIO_PIN6) +# define GPIO_ETH_MII_RXD3_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN1) +# define GPIO_ETH_MII_RXD3_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTH|GPIO_PIN7) +# define GPIO_ETH_MII_RX_CLK (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN1) +# define GPIO_ETH_MII_RX_DV (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN7) +# define GPIO_ETH_MII_RX_ER_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN10) +# define GPIO_ETH_MII_RX_ER_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTI|GPIO_PIN10) +# define GPIO_ETH_MII_TXD0_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN12) +# define GPIO_ETH_MII_TXD0_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN13) +# define GPIO_ETH_MII_TXD1_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN13) +# define GPIO_ETH_MII_TXD1_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN14) +# define GPIO_ETH_MII_TXD2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN2) +# define GPIO_ETH_MII_TXD3_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN8) +# define GPIO_ETH_MII_TXD3_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN2) +# define GPIO_ETH_MII_TX_CLK (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN3) +# define GPIO_ETH_MII_TX_EN_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN11) +# define GPIO_ETH_MII_TX_EN_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN11) +# define GPIO_ETH_PPS_OUT_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN5) +# define GPIO_ETH_PPS_OUT_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN8) +# define GPIO_ETH_RMII_CRS_DV (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN7) +# define GPIO_ETH_RMII_REF_CLK (GPIO_ALT|GPIO_AF11|GPIO_PORTA|GPIO_PIN1) +# define GPIO_ETH_RMII_RXD0 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN4) +# define GPIO_ETH_RMII_RXD1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN5) +# define GPIO_ETH_RMII_TXD0_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN12) +# define GPIO_ETH_RMII_TXD0_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN13) +# define GPIO_ETH_RMII_TXD1_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN13) +# define GPIO_ETH_RMII_TXD1_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN14) +# define GPIO_ETH_RMII_TX_EN_1 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN11) +# define GPIO_ETH_RMII_TX_EN_2 (GPIO_ALT|GPIO_AF11|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN11) +#endif + +/* Flexible Memory Controller (FMC) */ +#if 0 +#define GPIO_FMC_A0 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN0) +#define GPIO_FMC_A1 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN1) +#define GPIO_FMC_A2 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN2) +#define GPIO_FMC_A3 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN3) +#define GPIO_FMC_A4 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN4) +#define GPIO_FMC_A5 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN5) +#define GPIO_FMC_A6 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN12) +#define GPIO_FMC_A7 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN13) +#define GPIO_FMC_A8 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN14) +#define GPIO_FMC_A9 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN15) +#define GPIO_FMC_A10 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN0) +#define GPIO_FMC_A11 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN1) +#define GPIO_FMC_A12 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN2) +#define GPIO_FMC_A13 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN3) +#define GPIO_FMC_A14 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN4) +#define GPIO_FMC_A15 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN5) +#define GPIO_FMC_A16 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN11) +#define GPIO_FMC_A17 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN12) +#define GPIO_FMC_A18 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN13) +#define GPIO_FMC_A19 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN3) +#define GPIO_FMC_A20 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN4) +#define GPIO_FMC_A21 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN5) +#define GPIO_FMC_A22 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN6) +#define GPIO_FMC_A23 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN2) +#define GPIO_FMC_A24 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN13) +#define GPIO_FMC_A25 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN14) +#define GPIO_FMC_NBL1 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN1) +#define GPIO_FMC_CLK (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN3) +#define GPIO_FMC_D0 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN14) +#define GPIO_FMC_D1 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN15) +#define GPIO_FMC_D2 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN0) +#define GPIO_FMC_D3 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN1) +#define GPIO_FMC_D4 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN7) +#define GPIO_FMC_D5 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN8) +#define GPIO_FMC_D6 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN9) +#define GPIO_FMC_D7 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN10) +#define GPIO_FMC_D8 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN11) +#define GPIO_FMC_D9 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN12) +#define GPIO_FMC_D10 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN13) +#define GPIO_FMC_D11 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN14) +#define GPIO_FMC_D12 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN15) +#define GPIO_FMC_D13 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN8) +#define GPIO_FMC_D14 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN9) +#define GPIO_FMC_D15 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN10) +#define GPIO_FMC_NBL0 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN0) +#define GPIO_FMC_NE1 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN7) +#define GPIO_FMC_NE2 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN9) +#define GPIO_FMC_NE3 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN10) +#define GPIO_FMC_NE4 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN12) +#define GPIO_FMC_NL (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTB|GPIO_PIN7) +#define GPIO_FMC_NOE (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN4) +#define GPIO_FMC_NWAIT (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN6) +#define GPIO_FMC_NWE (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN5) + +#define GPIO_FMC_INT3 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN7) +#define GPIO_FMC_NCE3 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN9) + +/* Flexible Static Memory Controller (FSMC) */ + +#define GPIO_FSMC_A0 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN0) +#define GPIO_FSMC_A1 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN1) +#define GPIO_FSMC_A2 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN2) +#define GPIO_FSMC_A3 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN3) +#define GPIO_FSMC_A4 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN4) +#define GPIO_FSMC_A5 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN5) +#define GPIO_FSMC_A6 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN12) +#define GPIO_FSMC_A7 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN13) +#define GPIO_FSMC_A8 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN14) +#define GPIO_FSMC_A9 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTF|GPIO_PIN15) +#define GPIO_FSMC_A10 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN0) +#define GPIO_FSMC_A11 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN1) +#define GPIO_FSMC_A12 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN2) +#define GPIO_FSMC_A13 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN3) +#define GPIO_FSMC_A14 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN4) +#define GPIO_FSMC_A15 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN5) +#define GPIO_FSMC_A16 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN11) +#define GPIO_FSMC_A17 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN12) +#define GPIO_FSMC_A18 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN13) +#define GPIO_FSMC_A19 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN3) +#define GPIO_FSMC_A20 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN4) +#define GPIO_FSMC_A21 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN5) +#define GPIO_FSMC_A22 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN6) +#define GPIO_FSMC_A23 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN2) +#define GPIO_FSMC_A24 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN13) +#define GPIO_FSMC_A25 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN14) +#define GPIO_FSMC_NBL1 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN1) +#define GPIO_FSMC_CLK (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN3) +#define GPIO_FSMC_D0 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN14) +#define GPIO_FSMC_D1 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN15) +#define GPIO_FSMC_D2 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN0) +#define GPIO_FSMC_D3 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN1) +#define GPIO_FSMC_D4 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN7) +#define GPIO_FSMC_D5 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN8) +#define GPIO_FSMC_D6 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN9) +#define GPIO_FSMC_D7 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN10) +#define GPIO_FSMC_D8 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN11) +#define GPIO_FSMC_D9 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN12) +#define GPIO_FSMC_D10 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN13) +#define GPIO_FSMC_D11 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN14) +#define GPIO_FSMC_D12 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN15) +#define GPIO_FSMC_D13 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN8) +#define GPIO_FSMC_D14 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN9) +#define GPIO_FSMC_D15 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN10) +#define GPIO_FSMC_NBL0 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTE|GPIO_PIN0) +#define GPIO_FSMC_NE1 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN7) +#define GPIO_FSMC_NE2 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN9) +#define GPIO_FSMC_NE3 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN10) +#define GPIO_FSMC_NE4 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN12) +#define GPIO_FSMC_NL (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTB|GPIO_PIN7) +#define GPIO_FSMC_NOE (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN4) +#define GPIO_FSMC_NWAIT (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN6) +#define GPIO_FSMC_NWE (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTD|GPIO_PIN5) + +#define GPIO_FSMC_INT3 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN7) +#define GPIO_FSMC_NCE3 (GPIO_ALT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PORTG|GPIO_PIN9) +#endif + +/* I2C */ + +#define GPIO_I2C1_SCL_1 (GPIO_ALT|GPIO_AF8|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTA|GPIO_PIN9) +#define GPIO_I2C1_SCL_2 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN6) +#define GPIO_I2C1_SCL_3 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN8) +#define GPIO_I2C1_SCL_4 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTC|GPIO_PIN6) +#define GPIO_I2C1_SCL_5 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTH|GPIO_PIN1) +#define GPIO_I2C1_SDA_1 (GPIO_ALT|GPIO_AF8|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTA|GPIO_PIN10) +#define GPIO_I2C1_SDA_2 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN7) +#define GPIO_I2C1_SDA_3 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN9) +#define GPIO_I2C1_SDA_4 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTC|GPIO_PIN7) +#define GPIO_I2C1_SDA_5 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTH|GPIO_PIN0) +#define GPIO_I2C1_SMBA_1 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN5) +#define GPIO_I2C1_SMBA_2 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN5) + +#define GPIO_I2C2_SCL_1 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN10) +#define GPIO_I2C2_SCL_2 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTF|GPIO_PIN1) +#define GPIO_I2C2_SCL_3 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTH|GPIO_PIN2) +#define GPIO_I2C2_SCL_4 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTA|GPIO_PIN0) +#define GPIO_I2C2_SCL_5 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTA|GPIO_PIN11) +#define GPIO_I2C2_SCL_6 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTD|GPIO_PIN12) +#define GPIO_I2C2_SDA_1 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTA|GPIO_PIN1) +#define GPIO_I2C2_SDA_2 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTA|GPIO_PIN12) +#define GPIO_I2C2_SDA_3 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN3) +#define GPIO_I2C2_SDA_4 (GPIO_ALT|GPIO_AF7|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN9) +#define GPIO_I2C2_SDA_5 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN11) +#define GPIO_I2C2_SDA_6 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTC|GPIO_PIN12) +#define GPIO_I2C2_SDA_7 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTD|GPIO_PIN13) +#define GPIO_I2C2_SDA_8 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTF|GPIO_PIN0) +#define GPIO_I2C2_SDA_9 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTH|GPIO_PIN3) +#define GPIO_I2C2_SMBA_1 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN12) +#define GPIO_I2C2_SMBA_2 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN2) +#define GPIO_I2C2_SMBA_3 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN11) + +#define GPIO_I2C3_SCL_1 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTA|GPIO_PIN8) +#define GPIO_I2C3_SCL_2 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN15) +#define GPIO_I2C3_SCL_3 (GPIO_ALT|GPIO_AF7|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN13) +#define GPIO_I2C3_SCL_4 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTC|GPIO_PIN0) +#define GPIO_I2C3_SCL_5 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTD|GPIO_PIN14) +#define GPIO_I2C3_SCL_6 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTF|GPIO_PIN14) +#define GPIO_I2C3_SDA_1 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN4) +#define GPIO_I2C3_SDA_2 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN14) +#define GPIO_I2C3_SDA_3 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTC|GPIO_PIN1) +#define GPIO_I2C3_SDA_4 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTC|GPIO_PIN9) +#define GPIO_I2C3_SDA_5 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTD|GPIO_PIN15) +#define GPIO_I2C3_SDA_6 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_OPENDRAIN|GPIO_PORTF|GPIO_PIN15) +#define GPIO_I2C3_SMBA_1 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN9) +#define GPIO_I2C3_SMBA_2 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN2) +#define GPIO_I2C3_SMBA_3 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN13) +#define GPIO_I2C3_SMBA_4 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN13) + +/* JTAG */ + +#define GPIO_JTCK_SWCLK (GPIO_ALT|GPIO_AF0|GPIO_PORTA|GPIO_PIN14) +#define GPIO_JTDI (GPIO_ALT|GPIO_AF0|GPIO_PORTA|GPIO_PIN15) +#define GPIO_JTDO (GPIO_ALT|GPIO_AF0|GPIO_PORTB|GPIO_PIN3) +#define GPIO_JTMS_SWDIO (GPIO_ALT|GPIO_AF0|GPIO_PORTA|GPIO_PIN13) +#define GPIO_JTRST (GPIO_ALT|GPIO_AF0|GPIO_PORTB|GPIO_PIN4) + +/* OTG FS/HS (VBUS PA9 is not an alternate configuration) */ + +#define GPIO_OTGFS_DM (GPIO_ALT|GPIO_FLOAT|GPIO_AF10|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN11) +#define GPIO_OTGFS_DP (GPIO_ALT|GPIO_FLOAT|GPIO_AF10|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN12) +#define GPIO_OTGFS_ID (GPIO_ALT|GPIO_PULLUP|GPIO_AF10|GPIO_DRV_STRONG|GPIO_OPENDRAIN|GPIO_PORTA|GPIO_PIN10) +#define GPIO_OTGFS_SOF (GPIO_ALT|GPIO_FLOAT|GPIO_AF10|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN8) +#define GPIO_OTGFS_VBUS (GPIO_ALT|GPIO_FLOAT|GPIO_AF10|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN9) + +#define GPIO_OTGFS2_DM (GPIO_ALT|GPIO_FLOAT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN14) +#define GPIO_OTGFS2_DP (GPIO_ALT|GPIO_FLOAT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN15) +#define GPIO_OTGFS2_ID (GPIO_ALT|GPIO_PULLUP|GPIO_AF12|GPIO_DRV_STRONG|GPIO_OPENDRAIN|GPIO_PORTB|GPIO_PIN12) +#define GPIO_OTGFS2_SOF (GPIO_ALT|GPIO_FLOAT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN4) +#define GPIO_OTGFS2_VBUS (GPIO_ALT|GPIO_FLOAT|GPIO_AF12|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN13) + +/* RTC */ + +#define GPIO_RTC_50HZ (GPIO_ALT|GPIO_AF0|GPIO_PORTC|GPIO_PIN15) + +/* SDIO + * + * Note that the below configures GPIO_DRV_MODETATE I/O, that means for using + * the SDIO that you must enable I/O Compensation via the configuration + * option CONFIG_AT32_SYSCFG_IOCOMPENSATION=y. + */ + +#define GPIO_SDIO_CMD_1 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN2) +#define GPIO_SDIO_CMD_2 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN6) +#define GPIO_SDIO_CK_1 (GPIO_ALT|GPIO_AF12|GPIO_DRV_MODETATE|GPIO_PORTC|GPIO_PIN12) +#define GPIO_SDIO_CK_2 (GPIO_ALT|GPIO_AF12|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN2) +#define GPIO_SDIO_CK_3 (GPIO_ALT|GPIO_AF13|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN15) +#define GPIO_SDIO_D0_1 (GPIO_ALT|GPIO_AF14|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN6) +#define GPIO_SDIO_D0_2 (GPIO_ALT|GPIO_AF14|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN7) +#define GPIO_SDIO_D0_3 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN8) +#define GPIO_SDIO_D0_4 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN4) +#define GPIO_SDIO_D1_1 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN9) +#define GPIO_SDIO_D1_2 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN0) +#define GPIO_SDIO_D1_3 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN8) +#define GPIO_SDIO_D2_1 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN10) +#define GPIO_SDIO_D2_2 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN9) +#define GPIO_SDIO_D2_3 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN1) +#define GPIO_SDIO_D3_1 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN11) +#define GPIO_SDIO_D3_2 (GPIO_ALT|GPIO_AF14|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN5) +#define GPIO_SDIO_D4_1 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN8) +#define GPIO_SDIO_D5_1 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN9) +#define GPIO_SDIO_D6_1 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN6) +#define GPIO_SDIO_D6_2 (GPIO_ALT|GPIO_AF13|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN14) +#define GPIO_SDIO_D7_1 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN7) +#define GPIO_SDIO_D7_2 (GPIO_ALT|GPIO_AF12|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN10) +#define GPIO_SDIO2_CMD_1 (GPIO_ALT|GPIO_AF13|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN5) +#define GPIO_SDIO2_CMD_2 (GPIO_ALT|GPIO_AF10|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN3) +#define GPIO_SDIO2_CK_1 (GPIO_ALT|GPIO_AF13|GPIO_DRV_MODETATE|GPIO_PORTC|GPIO_PIN4) +#define GPIO_SDIO2_CK_2 (GPIO_ALT|GPIO_AF10|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN2) +#define GPIO_SDIO2_D0_1 (GPIO_ALT|GPIO_AF10|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN0) +#define GPIO_SDIO2_D0_2 (GPIO_ALT|GPIO_AF11|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN4) +#define GPIO_SDIO2_D1_1 (GPIO_ALT|GPIO_AF10|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN1) +#define GPIO_SDIO2_D1_2 (GPIO_ALT|GPIO_AF11|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN5) +#define GPIO_SDIO2_D2_1 (GPIO_ALT|GPIO_AF10|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN2) +#define GPIO_SDIO2_D2_2 (GPIO_ALT|GPIO_AF11|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN6) +#define GPIO_SDIO2_D3_1 (GPIO_ALT|GPIO_AF10|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN3) +#define GPIO_SDIO2_D3_2 (GPIO_ALT|GPIO_AF13|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN7) +#define GPIO_SDIO2_D4_1 (GPIO_ALT|GPIO_AF10|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN4) +#define GPIO_SDIO2_D5_1 (GPIO_ALT|GPIO_AF10|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN5) +#define GPIO_SDIO2_D6_1 (GPIO_ALT|GPIO_AF14|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN6) +#define GPIO_SDIO2_D7_1 (GPIO_ALT|GPIO_AF14|GPIO_PULLUP|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN7) + +/* SPI */ + +#define GPIO_SPI1_MISO_1 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN6) +#define GPIO_SPI1_MISO_2 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN4) +#define GPIO_SPI1_MISO_3 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN14) +#define GPIO_SPI1_MISO_4 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTG|GPIO_PIN0) +#define GPIO_SPI1_MOSI_1 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN7) +#define GPIO_SPI1_MOSI_2 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN5) +#define GPIO_SPI1_MOSI_3 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN15) +#define GPIO_SPI1_MOSI_4 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTG|GPIO_PIN1) +#define GPIO_SPI1_NSS_1 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN15) +#define GPIO_SPI1_NSS_2 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN4) +#define GPIO_SPI1_NSS_3 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN12) +#define GPIO_SPI1_SCK_1 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN5) +#define GPIO_SPI1_SCK_2 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN3) +#define GPIO_SPI1_SCK_3 (GPIO_ALT|GPIO_AF4|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN13) +#define GPIO_SPI2_MISO_1 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN14) +#define GPIO_SPI2_MISO_2 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTC|GPIO_PIN2) +#define GPIO_SPI2_MISO_3 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN12) +#define GPIO_SPI2_MISO_4 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTD|GPIO_PIN3) +#define GPIO_SPI2_MOSI_1 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN15) +#define GPIO_SPI2_MOSI_2 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTC|GPIO_PIN3) +#define GPIO_SPI2_MOSI_3 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN10) +#define GPIO_SPI2_MOSI_4 (GPIO_ALT|GPIO_AF7|GPIO_DRV_MODETATE|GPIO_PORTC|GPIO_PIN1) +#define GPIO_SPI2_MOSI_5 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTD|GPIO_PIN4) +#define GPIO_SPI2_NSS_1 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN12) +#define GPIO_SPI2_NSS_2 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN9) +#define GPIO_SPI2_NSS_3 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN11) +#define GPIO_SPI2_NSS_4 (GPIO_ALT|GPIO_AF7|GPIO_DRV_MODETATE|GPIO_PORTD|GPIO_PIN0) +#define GPIO_SPI2_NSS_5 (GPIO_ALT|GPIO_AF7|GPIO_DRV_MODETATE|GPIO_PORTD|GPIO_PIN1) +#define GPIO_SPI2_SCK_1 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN10) +#define GPIO_SPI2_SCK_2 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN13) +#define GPIO_SPI2_SCK_3 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN9) +#define GPIO_SPI2_SCK_4 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN1) +#define GPIO_SPI2_SCK_5 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTC|GPIO_PIN7) +#define GPIO_SPI2_SCK_6 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTD|GPIO_PIN1) +#define GPIO_SPI2_SCK_7 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTD|GPIO_PIN3) +#define GPIO_SPI3_MISO_1 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN4) +#define GPIO_SPI3_MISO_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTC|GPIO_PIN11) +#define GPIO_SPI3_MISO_3 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN13) +#define GPIO_SPI3_MOSI_1 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN5) +#define GPIO_SPI3_MOSI_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTC|GPIO_PIN12) +#define GPIO_SPI3_MOSI_3 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN14) +#define GPIO_SPI3_MOSI_4 (GPIO_ALT|GPIO_AF7|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN0) +#define GPIO_SPI3_MOSI_5 (GPIO_ALT|GPIO_AF7|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN2) +#define GPIO_SPI3_MOSI_6 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTC|GPIO_PIN1) +#define GPIO_SPI3_MOSI_7 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTD|GPIO_PIN0) +#define GPIO_SPI3_MOSI_8 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTD|GPIO_PIN6) +#define GPIO_SPI3_NSS_1 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN15) +#define GPIO_SPI3_NSS_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN4) +#define GPIO_SPI3_SCK_1 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN3) +#define GPIO_SPI3_SCK_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTC|GPIO_PIN10) +#define GPIO_SPI3_SCK_3 (GPIO_ALT|GPIO_AF7|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN12) +#define GPIO_SPI4_MISO_1 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN11) +#define GPIO_SPI4_MISO_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN8) +#define GPIO_SPI4_MISO_3 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTD|GPIO_PIN0) +#define GPIO_SPI4_MISO_4 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN5) +#define GPIO_SPI4_MISO_5 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN13) +#define GPIO_SPI4_MISO_6 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTG|GPIO_PIN12) +#define GPIO_SPI4_MOSI_1 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTA|GPIO_PIN1) +#define GPIO_SPI4_MOSI_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN9) +#define GPIO_SPI4_MOSI_3 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN6) +#define GPIO_SPI4_MOSI_4 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN14) +#define GPIO_SPI4_MOSI_5 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTG|GPIO_PIN13) +#define GPIO_SPI4_SCK_1 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN7) +#define GPIO_SPI4_SCK_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN13) +#define GPIO_SPI4_SCK_3 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN2) +#define GPIO_SPI4_SCK_4 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN12) +#define GPIO_SPI4_SCK_5 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTG|GPIO_PIN11) +#define GPIO_SPI4_NSS_1 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN6) +#define GPIO_SPI4_NSS_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTB|GPIO_PIN12) +#define GPIO_SPI4_NSS_3 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN4) +#define GPIO_SPI4_NSS_4 (GPIO_ALT|GPIO_AF5|GPIO_DRV_MODETATE|GPIO_PORTE|GPIO_PIN11) +#define GPIO_SPI4_NSS_5 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PORTG|GPIO_PIN14) + +/* Timers */ + +#define GPIO_TIM1_BKIN_1 (GPIO_ALT|GPIO_AF1|GPIO_PORTA|GPIO_PIN6) +#define GPIO_TIM1_BKIN_2 (GPIO_ALT|GPIO_AF1|GPIO_PORTB|GPIO_PIN12) +#define GPIO_TIM1_BKIN_3 (GPIO_ALT|GPIO_AF1|GPIO_PORTE|GPIO_PIN15) +#define GPIO_TIM1_CH1N_1 (GPIO_ALT|GPIO_AF1|GPIO_PORTA|GPIO_PIN7) +#define GPIO_TIM1_CH1N_2 (GPIO_ALT|GPIO_AF1|GPIO_PORTB|GPIO_PIN13) +#define GPIO_TIM1_CH1N_3 (GPIO_ALT|GPIO_AF1|GPIO_PORTE|GPIO_PIN8) +#define GPIO_TIM1_CH1IN_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN8) +#define GPIO_TIM1_CH1IN_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN9) +#define GPIO_TIM1_CH1OUT_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN8) +#define GPIO_TIM1_CH1OUT_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN9) +#define GPIO_TIM1_CH2N_1 (GPIO_ALT|GPIO_AF1|GPIO_PORTB|GPIO_PIN0) +#define GPIO_TIM1_CH2N_2 (GPIO_ALT|GPIO_AF1|GPIO_PORTB|GPIO_PIN14) +#define GPIO_TIM1_CH2N_3 (GPIO_ALT|GPIO_AF1|GPIO_PORTE|GPIO_PIN10) +#define GPIO_TIM1_CH2N_4 (GPIO_ALT|GPIO_AF1|GPIO_PORTE|GPIO_PIN1) +#define GPIO_TIM1_CH2IN_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN9) +#define GPIO_TIM1_CH2IN_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN11) +#define GPIO_TIM1_CH2OUT_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN9) +#define GPIO_TIM1_CH2OUT_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN11) +#define GPIO_TIM1_CH3N_1 (GPIO_ALT|GPIO_AF1|GPIO_PORTB|GPIO_PIN1) +#define GPIO_TIM1_CH3N_2 (GPIO_ALT|GPIO_AF1|GPIO_PORTB|GPIO_PIN15) +#define GPIO_TIM1_CH3N_3 (GPIO_ALT|GPIO_AF1|GPIO_PORTE|GPIO_PIN12) +#define GPIO_TIM1_CH3IN_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN10) +#define GPIO_TIM1_CH3IN_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN13) +#define GPIO_TIM1_CH3OUT_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN10) +#define GPIO_TIM1_CH3OUT_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN13) +#define GPIO_TIM1_CH4IN_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN11) +#define GPIO_TIM1_CH4IN_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN14) +#define GPIO_TIM1_CH4OUT_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN11) +#define GPIO_TIM1_CH4OUT_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN14) +#define GPIO_TIM1_ETR_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN12) +#define GPIO_TIM1_ETR_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN7) +#define GPIO_TIM1_ETR_3 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN10) + +#define GPIO_TIM2_CH1IN_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN0) +#define GPIO_TIM2_CH1IN_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN15) +#define GPIO_TIM2_CH1IN_3 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN5) +#define GPIO_TIM2_CH1IN_4 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN8) +#define GPIO_TIM2_CH1OUT_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN0) +#define GPIO_TIM2_CH1OUT_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN15) +#define GPIO_TIM2_CH1OUT_3 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN5) +#define GPIO_TIM2_CH1OUT_4 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN8) +#define GPIO_TIM2_CH2IN_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN1) +#define GPIO_TIM2_CH2IN_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN3) +#define GPIO_TIM2_CH2IN_3 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN9) +#define GPIO_TIM2_CH2OUT_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN1) +#define GPIO_TIM2_CH2OUT_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN3) +#define GPIO_TIM2_CH2OUT_3 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN9) +#define GPIO_TIM2_CH3IN_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN2) +#define GPIO_TIM2_CH3IN_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN10) +#define GPIO_TIM2_CH3OUT_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN2) +#define GPIO_TIM2_CH3OUT_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN10) +#define GPIO_TIM2_CH4IN_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN3) +#define GPIO_TIM2_CH4IN_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN11) +#define GPIO_TIM2_CH4IN_3 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN2) +#define GPIO_TIM2_CH4OUT_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN3) +#define GPIO_TIM2_CH4OUT_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN11) +#define GPIO_TIM2_CH4OUT_3 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN2) +#define GPIO_TIM2_ETR_1 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN0) +#define GPIO_TIM2_ETR_2 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN15) +#define GPIO_TIM2_ETR_3 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN5) +#define GPIO_TIM2_ETR_4 (GPIO_ALT|GPIO_AF1|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN8) + +#define GPIO_TIM3_CH1IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN6) +#define GPIO_TIM3_CH1IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN4) +#define GPIO_TIM3_CH1IN_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN6) +#define GPIO_TIM3_CH1IN_4 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN3) +#define GPIO_TIM3_CH1OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN6) +#define GPIO_TIM3_CH1OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN4) +#define GPIO_TIM3_CH1OUT_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN6) +#define GPIO_TIM3_CH1OUT_4 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN3) +#define GPIO_TIM3_CH2IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN7) +#define GPIO_TIM3_CH2IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN5) +#define GPIO_TIM3_CH2IN_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN7) +#define GPIO_TIM3_CH2IN_4 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN4) +#define GPIO_TIM3_CH2OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN7) +#define GPIO_TIM3_CH2OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN5) +#define GPIO_TIM3_CH2OUT_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN7) +#define GPIO_TIM3_CH2OUT_4 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN4) +#define GPIO_TIM3_CH3IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN0) +#define GPIO_TIM3_CH3IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN8) +#define GPIO_TIM3_CH3IN_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN5) +#define GPIO_TIM3_CH3OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN0) +#define GPIO_TIM3_CH3OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN8) +#define GPIO_TIM3_CH3OUT_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN5) +#define GPIO_TIM3_CH4IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN1) +#define GPIO_TIM3_CH4IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN9) +#define GPIO_TIM3_CH4IN_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN6) +#define GPIO_TIM3_CH4OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN1) +#define GPIO_TIM3_CH4OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN9) +#define GPIO_TIM3_CH4OUT_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN6) +#define GPIO_TIM3_ETR_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTD|GPIO_PIN2) +#define GPIO_TIM3_ETR_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN2) + +#define GPIO_TIM4_CH1IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN6) +#define GPIO_TIM4_CH1IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTD|GPIO_PIN12) +#define GPIO_TIM4_CH1OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN6) +#define GPIO_TIM4_CH1OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN12) +#define GPIO_TIM4_CH2IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN7) +#define GPIO_TIM4_CH2IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTD|GPIO_PIN13) +#define GPIO_TIM4_CH2OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN7) +#define GPIO_TIM4_CH2OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN13) +#define GPIO_TIM4_CH3IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN8) +#define GPIO_TIM4_CH3IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTD|GPIO_PIN14) +#define GPIO_TIM4_CH3OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN8) +#define GPIO_TIM4_CH3OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN14) +#define GPIO_TIM4_CH4IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN9) +#define GPIO_TIM4_CH4IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTD|GPIO_PIN15) +#define GPIO_TIM4_CH4OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN9) +#define GPIO_TIM4_CH4OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN15) +#define GPIO_TIM4_ETR (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN0) + +#define GPIO_TIM5_CH1IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN0) +#define GPIO_TIM5_CH1IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTH|GPIO_PIN2) +#define GPIO_TIM5_CH1IN_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN12) +#define GPIO_TIM5_CH1OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN0) +#define GPIO_TIM5_CH1OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTH|GPIO_PIN2) +#define GPIO_TIM5_CH1OUT_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN12) +#define GPIO_TIM5_CH2IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN1) +#define GPIO_TIM5_CH2IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTH|GPIO_PIN3) +#define GPIO_TIM5_CH2IN_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN10) +#define GPIO_TIM5_CH2OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN1) +#define GPIO_TIM5_CH2OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTH|GPIO_PIN2) +#define GPIO_TIM5_CH2OUT_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN10) +#define GPIO_TIM5_CH3IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN2) +#define GPIO_TIM5_CH3IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN11) +#define GPIO_TIM5_CH3OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN2) +#define GPIO_TIM5_CH3OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN11) +#define GPIO_TIM5_CH4IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN3) +#define GPIO_TIM5_CH4IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN11) +#define GPIO_TIM5_CH4IN_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN10) +#define GPIO_TIM5_CH4OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN3) +#define GPIO_TIM5_CH4OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN11) +#define GPIO_TIM5_CH4OUT_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN10) + +#define GPIO_TIM8_BKIN_1 (GPIO_ALT|GPIO_AF3|GPIO_PORTA|GPIO_PIN6) +#define GPIO_TIM8_BKIN_2 (GPIO_ALT|GPIO_AF3|GPIO_PORTB|GPIO_PIN7) +#define GPIO_TIM8_BKIN_3 (GPIO_ALT|GPIO_AF3|GPIO_PORTF|GPIO_PIN12) +#define GPIO_TIM8_CH1N_1 (GPIO_ALT|GPIO_AF3|GPIO_PORTA|GPIO_PIN5) +#define GPIO_TIM8_CH1N_2 (GPIO_ALT|GPIO_AF3|GPIO_PORTA|GPIO_PIN7) +#define GPIO_TIM8_CH1IN_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN6) +#define GPIO_TIM8_CH1OUT_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN6) +#define GPIO_TIM8_CH2N_1 (GPIO_ALT|GPIO_AF3|GPIO_PORTB|GPIO_PIN0) +#define GPIO_TIM8_CH2N_2 (GPIO_ALT|GPIO_AF3|GPIO_PORTB|GPIO_PIN14) +#define GPIO_TIM8_CH2IN_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN7) +#define GPIO_TIM8_CH2OUT_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN7) +#define GPIO_TIM8_CH3N_1 (GPIO_ALT|GPIO_AF3|GPIO_PORTB|GPIO_PIN1) +#define GPIO_TIM8_CH3N_2 (GPIO_ALT|GPIO_AF3|GPIO_PORTB|GPIO_PIN15) +#define GPIO_TIM8_CH3IN_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN8) +#define GPIO_TIM8_CH3OUT_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN8) +#define GPIO_TIM8_CH4IN_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN9) +#define GPIO_TIM8_CH4OUT_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN9) +#define GPIO_TIM8_ETR_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN0) +#define GPIO_TIM8_ETR_2 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN11) + +#define GPIO_TIM9_CH1IN_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN2) +#define GPIO_TIM9_CH1IN_2 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN5) +#define GPIO_TIM9_CH1OUT_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN2) +#define GPIO_TIM9_CH1OUT_2 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN5) +#define GPIO_TIM9_CH2IN_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN3) +#define GPIO_TIM9_CH2IN_2 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN6) +#define GPIO_TIM9_CH2OUT_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN3) +#define GPIO_TIM9_CH2OUT_2 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN6) + +#define GPIO_TIM10_CH1IN_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN8) +#define GPIO_TIM10_CH1IN_2 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN6) +#define GPIO_TIM10_CH1OUT_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN8) +#define GPIO_TIM10_CH1OUT_2 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN6) + +#define GPIO_TIM11_CH1IN_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN9) +#define GPIO_TIM11_CH1IN_2 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN7) +#define GPIO_TIM11_CH1OUT_1 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN9) +#define GPIO_TIM11_CH1OUT_2 (GPIO_ALT|GPIO_AF3|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN7) + +#define GPIO_TIM12_CH1IN_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN14) +#define GPIO_TIM12_CH1OUT_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN14) +#define GPIO_TIM12_CH2IN_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN15) +#define GPIO_TIM12_CH2OUT_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN15) + +#define GPIO_TIM13_CH1IN_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN6) +#define GPIO_TIM13_CH1IN_2 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN8) +#define GPIO_TIM13_CH1OUT_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN6) +#define GPIO_TIM13_CH1OUT_2 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN8) + +#define GPIO_TIM14_CH1IN_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN7) +#define GPIO_TIM14_CH1IN_2 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN9) +#define GPIO_TIM14_CH1OUT_1 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN7) +#define GPIO_TIM14_CH1OUT_2 (GPIO_ALT|GPIO_AF9|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN9) + +#define GPIO_TIM20_BKIN_1 (GPIO_ALT|GPIO_AF2|GPIO_PORTF|GPIO_PIN7) +#define GPIO_TIM20_BKIN_2 (GPIO_ALT|GPIO_AF2|GPIO_PORTF|GPIO_PIN9) +#define GPIO_TIM20_BKIN_3 (GPIO_ALT|GPIO_AF2|GPIO_PORTG|GPIO_PIN3) +#define GPIO_TIM20_CH1N_1 (GPIO_ALT|GPIO_AF6|GPIO_PORTE|GPIO_PIN4) +#define GPIO_TIM20_CH1N_2 (GPIO_ALT|GPIO_AF2|GPIO_PORTF|GPIO_PIN4) +#define GPIO_TIM20_CH1N_3 (GPIO_ALT|GPIO_AF2|GPIO_PORTG|GPIO_PIN0) +#define GPIO_TIM20_CH1IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTB|GPIO_PIN2) +#define GPIO_TIM20_CH1IN_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN2) +#define GPIO_TIM20_CH1IN_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN12) +#define GPIO_TIM20_CH1OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN2) +#define GPIO_TIM20_CH1OUT_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN2) +#define GPIO_TIM20_CH1OUT_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN12) +#define GPIO_TIM20_CH2N_1 (GPIO_ALT|GPIO_AF2|GPIO_PORTF|GPIO_PIN5) +#define GPIO_TIM20_CH2N_2 (GPIO_ALT|GPIO_AF2|GPIO_PORTG|GPIO_PIN1) +#define GPIO_TIM20_CH2N_3 (GPIO_ALT|GPIO_AF6|GPIO_PORTE|GPIO_PIN5) +#define GPIO_TIM20_CH2IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN2) +#define GPIO_TIM20_CH2IN_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN3) +#define GPIO_TIM20_CH2IN_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN13) +#define GPIO_TIM20_CH2OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN2) +#define GPIO_TIM20_CH2OUT_2 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN3) +#define GPIO_TIM20_CH2OUT_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN13) +#define GPIO_TIM20_CH3N_1 (GPIO_ALT|GPIO_AF2|GPIO_PORTG|GPIO_PIN2) +#define GPIO_TIM20_CH3N_2 (GPIO_ALT|GPIO_AF6|GPIO_PORTE|GPIO_PIN6) +#define GPIO_TIM20_CH3IN_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN2) +#define GPIO_TIM20_CH3IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN14) +#define GPIO_TIM20_CH3IN_3 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN8) +#define GPIO_TIM20_CH3OUT_1 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN2) +#define GPIO_TIM20_CH3OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN14) +#define GPIO_TIM20_CH3OUT_3 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN8) +#define GPIO_TIM20_CH4IN_1 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN1) +#define GPIO_TIM20_CH4IN_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN3) +#define GPIO_TIM20_CH4IN_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN6) +#define GPIO_TIM20_CH4IN_4 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN15) +#define GPIO_TIM20_CH4OUT_1 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN1) +#define GPIO_TIM20_CH4OUT_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN3) +#define GPIO_TIM20_CH4OUT_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN6) +#define GPIO_TIM20_CH4OUT_4 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN15) +#define GPIO_TIM20_ETR_1 (GPIO_ALT|GPIO_AF6|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTE|GPIO_PIN0) +#define GPIO_TIM20_ETR_2 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTF|GPIO_PIN11) +#define GPIO_TIM20_ETR_3 (GPIO_ALT|GPIO_AF2|GPIO_DRV_MODETATE|GPIO_FLOAT|GPIO_PORTG|GPIO_PIN5) + +/* Trace */ + +#define GPIO_TRACECLK (GPIO_ALT|GPIO_AF0|GPIO_PORTE|GPIO_PIN2) +#define GPIO_TRACESWO (GPIO_ALT|GPIO_AF0|GPIO_PORTB|GPIO_PIN3) + +#define GPIO_TRACED0 (GPIO_ALT|GPIO_AF0|GPIO_PORTE|GPIO_PIN3) +#define GPIO_TRACED1 (GPIO_ALT|GPIO_AF0|GPIO_PORTE|GPIO_PIN4) + +#define GPIO_TRACED2 (GPIO_ALT|GPIO_AF0|GPIO_PORTE|GPIO_PIN5) +#define GPIO_TRACED3 (GPIO_ALT|GPIO_AF0|GPIO_PORTE|GPIO_PIN6) + +/* UARTs/USARTs */ + +#define GPIO_USART1_CK_1 (GPIO_ALT|GPIO_AF7|GPIO_PORTA|GPIO_PIN8) +#define GPIO_USART1_CK_2 (GPIO_ALT|GPIO_AF7|GPIO_PORTB|GPIO_PIN5) +#define GPIO_USART1_CTS (GPIO_ALT|GPIO_AF7|GPIO_PORTA|GPIO_PIN11) +#define GPIO_USART1_RTS (GPIO_ALT|GPIO_AF7|GPIO_PORTA|GPIO_PIN12) +#define GPIO_USART1_RX_1 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN10) +#define GPIO_USART1_RX_2 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN7) +#define GPIO_USART1_RX_3 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN3) +#define GPIO_USART1_TX_1 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN9) +#define GPIO_USART1_TX_2 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN6) +#define GPIO_USART1_TX_3 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN15) + +#define GPIO_USART2_CK_1 (GPIO_ALT|GPIO_AF7|GPIO_PORTA|GPIO_PIN4) +#define GPIO_USART2_CK_2 (GPIO_ALT|GPIO_AF7|GPIO_PORTD|GPIO_PIN7) +#define GPIO_USART2_CTS_1 (GPIO_ALT|GPIO_AF7|GPIO_PORTA|GPIO_PIN0) +#define GPIO_USART2_CTS_2 (GPIO_ALT|GPIO_AF7|GPIO_PORTD|GPIO_PIN3) +#define GPIO_USART2_RTS_1 (GPIO_ALT|GPIO_AF7|GPIO_PORTA|GPIO_PIN1) +#define GPIO_USART2_RTS_2 (GPIO_ALT|GPIO_AF7|GPIO_PORTD|GPIO_PIN4) +#define GPIO_USART2_RX_1 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN3) +#define GPIO_USART2_RX_2 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN6) +#define GPIO_USART2_RX_3 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN15) +#define GPIO_USART2_RX_4 (GPIO_ALT|GPIO_AF6|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN0) +#define GPIO_USART2_TX_1 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN2) +#define GPIO_USART2_TX_2 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN5) +#define GPIO_USART2_TX_3 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN8) +#define GPIO_USART2_TX_4 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN14) + +#define GPIO_USART3_CK_1 (GPIO_ALT|GPIO_AF8|GPIO_PORTB|GPIO_PIN12) +#define GPIO_USART3_CK_2 (GPIO_ALT|GPIO_AF7|GPIO_PORTC|GPIO_PIN12) +#define GPIO_USART3_CK_3 (GPIO_ALT|GPIO_AF7|GPIO_PORTD|GPIO_PIN10) +#define GPIO_USART3_CK_4 (GPIO_ALT|GPIO_AF8|GPIO_PORTB|GPIO_PIN0) +#define GPIO_USART3_CTS_1 (GPIO_ALT|GPIO_AF7|GPIO_PORTD|GPIO_PIN11) +#define GPIO_USART3_CTS_2 (GPIO_ALT|GPIO_AF7|GPIO_PORTA|GPIO_PIN6) +#define GPIO_USART3_RTS_1 (GPIO_ALT|GPIO_AF7|GPIO_PORTB|GPIO_PIN14) +#define GPIO_USART3_RTS_2 (GPIO_ALT|GPIO_AF7|GPIO_PORTD|GPIO_PIN12) +#define GPIO_USART3_RTS_3 (GPIO_ALT|GPIO_AF7|GPIO_PORTD|GPIO_PIN2) +#define GPIO_USART3_RX_1 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN11) +#define GPIO_USART3_RX_2 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN11) +#define GPIO_USART3_RX_3 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN9) +#define GPIO_USART3_RX_4 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN5) +#define GPIO_USART3_TX_1 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN10) +#define GPIO_USART3_TX_2 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN10) +#define GPIO_USART3_TX_3 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN8) +#define GPIO_USART3_TX_4 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN4) + +#define GPIO_UART4_RX_1 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN1) +#define GPIO_UART4_RX_2 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN11) +#define GPIO_UART4_RX_3 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN9) +#define GPIO_UART4_TX_1 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN0) +#define GPIO_UART4_TX_2 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN10) +#define GPIO_UART4_TX_3 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN8) + +#define GPIO_UART5_RX_1 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN5) +#define GPIO_UART5_RX_2 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN8) +#define GPIO_UART5_RX_3 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN2) +#define GPIO_UART5_RX_4 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN11) +#define GPIO_UART5_TX_1 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN6) +#define GPIO_UART5_TX_2 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN9) +#define GPIO_UART5_TX_3 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN12) +#define GPIO_UART5_TX_4 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN10) + +#define GPIO_USART6_CK_1 (GPIO_ALT|GPIO_AF8|GPIO_PORTC|GPIO_PIN8) +#define GPIO_USART6_CK_2 (GPIO_ALT|GPIO_AF8|GPIO_PORTG|GPIO_PIN7) +#define GPIO_USART6_CTS_1 (GPIO_ALT|GPIO_AF8|GPIO_PORTG|GPIO_PIN13) +#define GPIO_USART6_CTS_2 (GPIO_ALT|GPIO_AF8|GPIO_PORTG|GPIO_PIN15) +#define GPIO_USART6_RTS_1 (GPIO_ALT|GPIO_AF8|GPIO_PORTG|GPIO_PIN12) +#define GPIO_USART6_RTS_2 (GPIO_ALT|GPIO_AF8|GPIO_PORTG|GPIO_PIN8) +#define GPIO_USART6_RX_1 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN7) +#define GPIO_USART6_RX_2 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN9) +#define GPIO_USART6_RX_3 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN5) +#define GPIO_USART6_RX_4 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN12) +#define GPIO_USART6_TX_1 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN6) +#define GPIO_USART6_TX_2 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTG|GPIO_PIN14) +#define GPIO_USART6_TX_3 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN4) +#define GPIO_USART6_TX_4 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTA|GPIO_PIN11) + +#define GPIO_UART7_RX_1 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN3) +#define GPIO_UART7_RX_2 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN1) +#define GPIO_UART7_RX_3 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN7) +#define GPIO_UART7_RX_4 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN6) +#define GPIO_UART7_TX_1 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTB|GPIO_PIN4) +#define GPIO_UART7_TX_2 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN0) +#define GPIO_UART7_TX_3 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN8) +#define GPIO_UART7_TX_4 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTF|GPIO_PIN7) + +#define GPIO_UART8_RX_1 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN9) +#define GPIO_UART8_RX_2 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN3) +#define GPIO_UART8_RX_3 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN14) +#define GPIO_UART8_RX_4 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN0) +#define GPIO_UART8_TX_1 (GPIO_ALT|GPIO_AF7|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN8) +#define GPIO_UART8_TX_2 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTC|GPIO_PIN2) +#define GPIO_UART8_TX_3 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTD|GPIO_PIN13) +#define GPIO_UART8_TX_4 (GPIO_ALT|GPIO_AF8|GPIO_PULLUP|GPIO_DRV_STRONG|GPIO_PUSHPULL|GPIO_PORTE|GPIO_PIN1) + +/* Quad SPI */ + +#if defined(CONFIG_AT32_AT32F435) || defined(CONFIG_AT32_AT32F437) +# define GPIO_QUADSPI_BK1_IO0_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTF|GPIO_PIN8) +# define GPIO_QUADSPI_BK1_IO0_2 (GPIO_ALT|GPIO_AF9 |GPIO_PORTC|GPIO_PIN9) +# define GPIO_QUADSPI_BK1_IO0_3 (GPIO_ALT|GPIO_AF9 |GPIO_PORTD|GPIO_PIN11) +# define GPIO_QUADSPI_BK1_IO1_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTF|GPIO_PIN9) +# define GPIO_QUADSPI_BK1_IO1_2 (GPIO_ALT|GPIO_AF9 |GPIO_PORTC|GPIO_PIN10) +# define GPIO_QUADSPI_BK1_IO1_3 (GPIO_ALT|GPIO_AF9 |GPIO_PORTD|GPIO_PIN12) +# define GPIO_QUADSPI_BK1_IO2_1 (GPIO_ALT|GPIO_AF9 |GPIO_PORTE|GPIO_PIN2) +# define GPIO_QUADSPI_BK1_IO2_2 (GPIO_ALT|GPIO_AF9 |GPIO_PORTF|GPIO_PIN7) +# define GPIO_QUADSPI_BK1_IO3_1 (GPIO_ALT|GPIO_AF9 |GPIO_PORTA|GPIO_PIN1) +# define GPIO_QUADSPI_BK1_IO3_2 (GPIO_ALT|GPIO_AF9 |GPIO_PORTD|GPIO_PIN13) +# define GPIO_QUADSPI_BK1_IO3_3 (GPIO_ALT|GPIO_AF9 |GPIO_PORTF|GPIO_PIN6) +# define GPIO_QUADSPI_BK1_NCS_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTB|GPIO_PIN6) +#endif + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_PINMAP_H */ diff --git a/arch/arm/src/at32/hardware/at32f43xxx_rcc.h b/arch/arm/src/at32/hardware/at32f43xxx_rcc.h new file mode 100644 index 0000000000..ad32801fb9 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32f43xxx_rcc.h @@ -0,0 +1,568 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32f43xxx_rcc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_RCC_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_RCC_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define AT32_CRM_CTRL_OFFSET 0x000 /* Clock control register */ +#define AT32_CRM_PLL_CFG_OFFSET 0x004 /* PLL configuration register */ +#define AT32_CRM_CFG_OFFSET 0x008 /* Clock configuration register */ +#define AT32_CRM_CLKINT_OFFSET 0x00C /* Clock interrupt register */ +#define AT32_CRM_AHBRST1_OFFSET 0x010 /* AHB1 peripheral reset register */ +#define AT32_CRM_AHBRST2_OFFSET 0x014 /* AHB2 peripheral reset register */ +#define AT32_CRM_AHBRST3_OFFSET 0x018 /* AHB3 peripheral reset register */ +#define AT32_CRM_APB1RST_OFFSET 0x020 /* APB1 Peripheral reset register */ +#define AT32_CRM_APB2RST_OFFSET 0x024 /* APB2 Peripheral reset register */ +#define AT32_CRM_AHBEN1_OFFSET 0x030 /* AHB1 Peripheral Clock enable register */ +#define AT32_CRM_AHBEN2_OFFSET 0x034 /* AHB2 Peripheral Clock enable register */ +#define AT32_CRM_AHBEN3_OFFSET 0x038 /* AHB3 Peripheral Clock enable register */ +#define AT32_CRM_APB1EN_OFFSET 0x040 /* APB1 Peripheral Clock enable register */ +#define AT32_CRM_APB2EN_OFFSET 0x044 /* APB2 Peripheral Clock enable register */ +#define AT32_CRM_AHBLPEN1_OFFSET 0x050 /* RCC AHB1 low power mode peripheral clock enable register */ +#define AT32_CRM_AHBLPEN2_OFFSET 0x054 /* RCC AHB2 low power mode peripheral clock enable register */ +#define AT32_CRM_AHBLPEN3_OFFSET 0x058 /* RCC AHB3 low power mode peripheral clock enable register */ +#define AT32_CRM_APB1LPEN_OFFSET 0x060 /* RCC APB1 low power mode peripheral clock enable register */ +#define AT32_CRM_APB2LPEN_OFFSET 0x064 /* RCC APB2 low power mode peripheral clock enable register */ +#define AT32_CRM_BPDC_OFFSET 0x070 /* Backup domain control register */ +#define AT32_CRM_CTRLSTS_OFFSET 0x074 /* Control/status register */ +#define AT32_CRM_MISC1_OFFSET 0x0A0 /* Misc1 register */ +#define AT32_CRM_MISC2_OFFSET 0x0A4 /* Misc2 register */ + +/* Register Addresses *******************************************************/ + +#define AT32_CRM_CTRL (AT32_CRM_BASE+AT32_CRM_CTRL_OFFSET) +#define AT32_CRM_PLL_CFG (AT32_CRM_BASE+AT32_CRM_PLL_CFG_OFFSET) +#define AT32_CRM_CFG (AT32_CRM_BASE+AT32_CRM_CFG_OFFSET) +#define AT32_CRM_CLKINT (AT32_CRM_BASE+AT32_CRM_CLKINT_OFFSET) +#define AT32_CRM_AHBRST1 (AT32_CRM_BASE+AT32_CRM_AHBRST1_OFFSET) +#define AT32_CRM_AHBRST2 (AT32_CRM_BASE+AT32_CRM_AHBRST2_OFFSET) +#define AT32_CRM_AHBRST3 (AT32_CRM_BASE+AT32_CRM_AHBRST3_OFFSET) +#define AT32_CRM_APB1RST (AT32_CRM_BASE+AT32_CRM_APB1RST_OFFSET) +#define AT32_CRM_APB2RST (AT32_CRM_BASE+AT32_CRM_APB2RST_OFFSET) +#define AT32_CRM_AHBEN1 (AT32_CRM_BASE+AT32_CRM_AHBEN1_OFFSET) +#define AT32_CRM_AHBEN2 (AT32_CRM_BASE+AT32_CRM_AHBEN2_OFFSET) +#define AT32_CRM_AHBEN3 (AT32_CRM_BASE+AT32_CRM_AHBEN3_OFFSET) +#define AT32_CRM_APB1EN (AT32_CRM_BASE+AT32_CRM_APB1EN_OFFSET) +#define AT32_CRM_APB2EN (AT32_CRM_BASE+AT32_CRM_APB2EN_OFFSET) +#define AT32_CRM_AHBLPEN1 (AT32_CRM_BASE+AT32_CRM_AHBLPEN1_OFFSET) +#define AT32_CRM_AHBLPEN2 (AT32_CRM_BASE+AT32_CRM_AHBLPEN2_OFFSET) +#define AT32_CRM_AHBLPEN3 (AT32_CRM_BASE+AT32_CRM_AHBLPEN3_OFFSET) +#define AT32_CRM_APB1LPEN (AT32_CRM_BASE+AT32_CRM_APB1LPEN_OFFSET) +#define AT32_CRM_APB2LPEN (AT32_CRM_BASE+AT32_CRM_APB2LPEN_OFFSET) +#define AT32_CRM_BPDC (AT32_CRM_BASE+AT32_CRM_BPDC_OFFSET) +#define AT32_CRM_CTRLSTS (AT32_CRM_BASE+AT32_CRM_CTRLSTS_OFFSET) +#define AT32_CRM_MISC1 (AT32_CRM_BASE+AT32_CRM_MISC1_OFFSET) +#define AT32_CRM_MISC2 (AT32_CRM_BASE+AT32_CRM_MISC2_OFFSET) + +/* Register Bitfield Definitions ********************************************/ + +/* Clock control register */ + +#define CRM_CTRL_HICKEN (1 << 0) /* High speed internal clock enable */ +#define CRM_CTRL_HICKSTBL (1 << 1) /* High speed internal clock stable */ +#define CRM_CTRL_HICKTRIM (0x3F << 2) /* High speed internal clock trimming */ +#define CRM_CTRL_HICKCAL (0xFF << 8) /* High speed internal clock calibration */ +#define CRM_CTRL_HEXTEN (1 << 16) /* High speed external crystal enable */ +#define CRM_CTRL_HEXTSTBL (1 << 17) /* High speed external crystal stable */ +#define CRM_CTRL_HEXTBYPS (1 << 18) /* High speed external crystal bypass */ +#define CRM_CTRL_CFDEN (1 << 19) /* Clock Failure Detection enable */ +#define CRM_CTRL_PLLEN (1 << 24) /* PLL enable */ +#define CRM_CTRL_PLLSTBL (1 << 25) /* PLL clock stable */ + +/* PLL configuration register */ + +#define CRM_PLL_CFG_PLL_MS_SHIFT (0) /* PLL pre-division, range: 1~15 */ +#define CRM_PLL_CFG_PLL_MS_MASK (15 << CRM_PLL_CFG_PLL_MS_SHIFT) +# define CRM_PLL_CFG_PLL_MS(n) ((n) << CRM_PLL_CFG_PLL_MS_SHIFT) /* n = 1..15 */ + +#define CRM_PLL_CFG_PLL_NS_SHIFT (6) /* PLL Multiplication Factor,range: 31~500 */ +#define CRM_PLL_CFG_PLL_NS_MASK (0x1FF << CRM_PLL_CFG_PLL_NS_SHIFT) +# define CRM_PLL_CFG_PLL_NS(n) ((n) << CRM_PLL_CFG_PLL_NS_SHIFT) /* n = 31..500 */ + +#define CRM_PLL_CFG_PLL_FR_SHIFT (16) /* PLL post-division */ +#define CRM_PLL_CFG_PLL_FR_MASK (7 << CRM_PLL_CFG_PLL_FR_SHIFT) +# define CRM_PLL_CFG_PLL_FR_1 (0 << CRM_PLL_CFG_PLL_FR_SHIFT) /* div 1 */ +# define CRM_PLL_CFG_PLL_FR_2 (1 << CRM_PLL_CFG_PLL_FR_SHIFT) /* div 2 */ +# define CRM_PLL_CFG_PLL_FR_4 (2 << CRM_PLL_CFG_PLL_FR_SHIFT) /* div 4 */ +# define CRM_PLL_CFG_PLL_FR_8 (3 << CRM_PLL_CFG_PLL_FR_SHIFT) /* div 8 */ +# define CRM_PLL_CFG_PLL_FR_16 (4 << CRM_PLL_CFG_PLL_FR_SHIFT) /* div 16 */ +# define CRM_PLL_CFG_PLL_FR_32 (5 << CRM_PLL_CFG_PLL_FR_SHIFT) /* div 32 */ + +#define CRM_PLL_CFG_PLLRCS (1 << 22) /* PLL reference clock select */ + +/* Clock configuration register */ + +#define CRM_CFG_SCLKSEL_SHIFT (0) /* System clock select */ +#define CRM_CFG_SCLKSEL_MASK (3 << CRM_CFG_SCLKSEL_SHIFT) +# define CRM_CFG_SEL_HICK (0 << CRM_CFG_SCLKSEL_SHIFT) /* Select HICK */ +# define CRM_CFG_SEL_HEXT (1 << CRM_CFG_SCLKSEL_SHIFT) /* Select HEXT */ +# define CRM_CFG_SEL_PLL (2 << CRM_CFG_SCLKSEL_SHIFT) /* Select PLL */ + +#define CRM_CFG_SCLKSTS_SHIFT (2) /* System clock select status */ +#define CRM_CFG_SCLKSTSL_MASK (3 << CRM_CFG_SCLKSTS_SHIFT) +# define CRM_CFG_STS_HICK (0 << CRM_CFG_SCLKSTS_SHIFT) /* Select HICK */ +# define CRM_CFG_STS_HEXT (1 << CRM_CFG_SCLKSTS_SHIFT) /* Select HEXT */ +# define CRM_CFG_STS_PLL (2 << CRM_CFG_SCLKSTS_SHIFT) /* Select PLL */ + +#define CRM_CFG_AHBDIV_SHIFT (4) /* AHB division */ +#define CRM_CFG_AHBDIV_MASK (7 << CRM_CFG_AHBDIV_SHIFT) +# define CRM_CFG_AHBDIV_NONE (0 << CRM_CFG_AHBDIV_SHIFT) /* AHB division None */ +# define CRM_CFG_AHBDIV_2 (8 << CRM_CFG_AHBDIV_SHIFT) /* AHB division 2 */ +# define CRM_CFG_AHBDIV_4 (9 << CRM_CFG_AHBDIV_SHIFT) /* AHB division 4 */ +# define CRM_CFG_AHBDIV_8 (10 << CRM_CFG_AHBDIV_SHIFT) /* AHB division 8 */ +# define CRM_CFG_AHBDIV_16 (11 << CRM_CFG_AHBDIV_SHIFT) /* AHB division 16 */ +# define CRM_CFG_AHBDIV_64 (12 << CRM_CFG_AHBDIV_SHIFT) /* AHB division 64 */ +# define CRM_CFG_AHBDIV_128 (13 << CRM_CFG_AHBDIV_SHIFT) /* AHB division 128 */ +# define CRM_CFG_AHBDIV_256 (14 << CRM_CFG_AHBDIV_SHIFT) /* AHB division 256 */ +# define CRM_CFG_AHBDIV_512 (15 << CRM_CFG_AHBDIV_SHIFT) /* AHB division 512 */ + +#define CRM_CFG_APB1DIV_SHIFT (10) /* APB1 division */ +#define CRM_CFG_APB1DIV_MASK (7 << CRM_CFG_APB1DIV_SHIFT) +# define CRM_CFG_APB1DIV_NONE (3 << CRM_CFG_APB1DIV_SHIFT) /* APB1 division None */ +# define CRM_CFG_APB1DIV_2 (4 << CRM_CFG_APB1DIV_SHIFT) /* APB1 division 2 */ +# define CRM_CFG_APB1DIV_4 (5 << CRM_CFG_APB1DIV_SHIFT) /* APB1 division 4 */ +# define CRM_CFG_APB1DIV_8 (6 << CRM_CFG_APB1DIV_SHIFT) /* APB1 division 8 */ +# define CRM_CFG_APB1DIV_16 (7 << CRM_CFG_APB1DIV_SHIFT) /* APB1 division 16 */ + +#define CRM_CFG_APB2DIV_SHIFT (13) /* APB2 division */ +#define CRM_CFG_APB2DIV_MASK (7 << CRM_CFG_APB2DIV_SHIFT) +# define CRM_CFG_APB2DIV_NONE (3 << CRM_CFG_APB2DIV_SHIFT) /* APB2 division None */ +# define CRM_CFG_APB2DIV_2 (4 << CRM_CFG_APB2DIV_SHIFT) /* APB2 division 2 */ +# define CRM_CFG_APB2DIV_4 (5 << CRM_CFG_APB2DIV_SHIFT) /* APB2 division 4 */ +# define CRM_CFG_APB2DIV_8 (6 << CRM_CFG_APB2DIV_SHIFT) /* APB2 division 8 */ +# define CRM_CFG_APB2DIV_16 (7 << CRM_CFG_APB2DIV_SHIFT) /* APB2 division 16 */ + +#define CRM_CFG_ERTCDIV_SHIFT (16) /* HEXT division for ERTC clock */ +#define CRM_CFG_ERTCDIV_MASK (31 << CRM_CFG_ERTCDIV_SHIFT) +# define CRM_CFG_ERTCDIV_NONE1 (0 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock None */ +# define CRM_CFG_ERTCDIV_NONE2 (1 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock None */ +# define CRM_CFG_ERTCDIV_2 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 2 */ +# define CRM_CFG_ERTCDIV_3 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 3 */ +# define CRM_CFG_ERTCDIV_4 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 4 */ +# define CRM_CFG_ERTCDIV_5 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 5 */ +# define CRM_CFG_ERTCDIV_6 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 6 */ +# define CRM_CFG_ERTCDIV_7 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 7 */ +# define CRM_CFG_ERTCDIV_8 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 8 */ +# define CRM_CFG_ERTCDIV_9 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 9 */ +# define CRM_CFG_ERTCDIV_10 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 10 */ +# define CRM_CFG_ERTCDIV_11 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 11 */ +# define CRM_CFG_ERTCDIV_12 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 12 */ +# define CRM_CFG_ERTCDIV_13 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 13 */ +# define CRM_CFG_ERTCDIV_14 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 14 */ +# define CRM_CFG_ERTCDIV_15 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 15 */ +# define CRM_CFG_ERTCDIV_16 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 16 */ +# define CRM_CFG_ERTCDIV_17 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 17 */ +# define CRM_CFG_ERTCDIV_18 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 18 */ +# define CRM_CFG_ERTCDIV_19 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 19 */ +# define CRM_CFG_ERTCDIV_20 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 20 */ +# define CRM_CFG_ERTCDIV_21 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 21 */ +# define CRM_CFG_ERTCDIV_22 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 22 */ +# define CRM_CFG_ERTCDIV_23 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 23 */ +# define CRM_CFG_ERTCDIV_24 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 24 */ +# define CRM_CFG_ERTCDIV_25 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 25 */ +# define CRM_CFG_ERTCDIV_26 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 26 */ +# define CRM_CFG_ERTCDIV_27 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 27 */ +# define CRM_CFG_ERTCDIV_28 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 28 */ +# define CRM_CFG_ERTCDIV_29 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 29 */ +# define CRM_CFG_ERTCDIV_30 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 30 */ +# define CRM_CFG_ERTCDIV_31 (2 << CRM_CFG_ERTCDIV_SHIFT) /* HEXT division for ERTC clock 31 */ + +#define CRM_CFG_CLKOUT1_SEL_SHIFT (21) /* Clock output1 selection */ +#define CRM_CFG_CLKOUT1_SEL_MASK (3 << CRM_CFG_APB1DIV_SHIFT) +# define CRM_CFG_CLKOUT1_SEL_HICK (0 << CRM_CFG_APB1DIV_SHIFT) /* HICK output */ +# define CRM_CFG_CLKOUT1_SEL_LEXT (1 << CRM_CFG_APB1DIV_SHIFT) /* LEXT output */ +# define CRM_CFG_CLKOUT1_SEL_HEXT (2 << CRM_CFG_APB1DIV_SHIFT) /* HEXT output */ +# define CRM_CFG_CLKOUT1_SEL_PLL (3 << CRM_CFG_APB1DIV_SHIFT) /* PLL output */ + +#define CRM_CFG_CLKOUT1DIV1_SHIFT (24) /* Clock output1 division1 */ +#define CRM_CFG_CLKOUT1DIV1_MASK (7 << CRM_CFG_CLKOUT1DIV1_SHIFT) +# define CRM_CFG_CLKOUT1DIV1_1 (3 << CRM_CFG_CLKOUT1DIV1_SHIFT) /* CLKOUT1 */ +# define CRM_CFG_CLKOUT1DIV1_1_2 (4 << CRM_CFG_CLKOUT1DIV1_SHIFT) /* CLKOUT1/2 */ +# define CRM_CFG_CLKOUT1DIV1_1_3 (5 << CRM_CFG_CLKOUT1DIV1_SHIFT) /* CLKOUT1/3 */ +# define CRM_CFG_CLKOUT1DIV1_1_4 (6 << CRM_CFG_CLKOUT1DIV1_SHIFT) /* CLKOUT1/4 */ +# define CRM_CFG_CLKOUT1DIV1_1_5 (7 << CRM_CFG_CLKOUT1DIV1_SHIFT) /* CLKOUT1/5 */ + +#define CRM_CFG_CLKOUT2DIV1_SHIFT (27) /* Clock output2 division1 */ +#define CRM_CFG_CLKOUT2DIV1_MASK (7 << CRM_CFG_CLKOUT2DIV1_SHIFT) +# define CRM_CFG_CLKOUT2DIV1_1 (3 << CRM_CFG_CLKOUT2DIV1_SHIFT) /* CLKOUT2 */ +# define CRM_CFG_CLKOUT2DIV1_1_2 (4 << CRM_CFG_CLKOUT2DIV1_SHIFT) /* CLKOUT2/2 */ +# define CRM_CFG_CLKOUT2DIV1_1_3 (5 << CRM_CFG_CLKOUT2DIV1_SHIFT) /* CLKOUT2/3 */ +# define CRM_CFG_CLKOUT2DIV1_1_4 (6 << CRM_CFG_CLKOUT2DIV1_SHIFT) /* CLKOUT2/4 */ +# define CRM_CFG_CLKOUT2DIV1_1_5 (7 << CRM_CFG_CLKOUT2DIV1_SHIFT) /* CLKOUT2/5 */ + +#define CRM_CFG_CLKOUT2_SEL1_SHIFT (30) /* clock output2 selecction 1 */ +#define CRM_CFG_CLKOUT2_SEL1_MASK (3 << CRM_CFG_CLKOUT2_SEL1_SHIFT) +# define CRM_CFG_CLKOUT2_SEL1_SCLK (0 << CRM_CFG_CLKOUT2_SEL1_SHIFT) /* Output from SCLK */ +# define CRM_CFG_CLKOUT2_SEL1_2 (1 << CRM_CFG_CLKOUT2_SEL1_SHIFT) /* Output determine from CRM_MISC1 */ +# define CRM_CFG_CLKOUT2_SEL1_HEXT (2 << CRM_CFG_CLKOUT2_SEL1_SHIFT) /* Output from HEXT */ +# define CRM_CFG_CLKOUT2_SEL1_PLL (3 << CRM_CFG_CLKOUT2_SEL1_SHIFT) /* Output from PLL */ + +/* Clock interrupt register */ + +#define CRM_CLKINT_LICKSTBLF (1 << 0) /* LICK stable flag */ +#define CRM_CLKINT_LEXTSTBLF (1 << 1) /* LEXT stable flag */ +#define CRM_CLKINT_HICKSTBLF (1 << 2) /* HICK stable flag */ +#define CRM_CLKINT_HEXTSTBLF (1 << 3) /* HEXT stable flag */ +#define CRM_CLKINT_PLLSTBLF (1 << 4) /* PLL stable flag */ +#define CRM_CLKINT_CFDF (1 << 7) /* Clock Failure Detection flag */ +#define CRM_CLKINT_LICKSTBLIEN (1 << 8) /* LICK stable interrupt enable */ +#define CRM_CLKINT_LEXTSTBLIEN (1 << 9) /* LEXT stable interrupt enable */ +#define CRM_CLKINT_HICKSTBLIEN (1 << 10) /* HICK stable interrupt enable */ +#define CRM_CLKINT_HEXTSTBLIEN (1 << 11) /* HEXT stable interrupt enable */ +#define CRM_CLKINT_PLLSTBLIEN (1 << 12) /* PLL stable interrupt enable */ +#define CRM_CLKINT_LICKSTBLFC (1 << 16) /* LICK stable flag clear */ +#define CRM_CLKINT_LEXTSTBLFC (1 << 17) /* LEXT stable flag clear */ +#define CRM_CLKINT_HICKSTBLFC (1 << 18) /* HICK stable flag clear */ +#define CRM_CLKINT_HEXTSTBLFC (1 << 19) /* HEXT stable flag clear */ +#define CRM_CLKINT_PLLSTBLFC (1 << 20) /* PLL stable flag clear */ +#define CRM_CLKINT_CFDFC (1 << 23) /* Clock failure detection interrupt clear */ + +/* AHB1 peripheral reset register */ + +#define CRM_AHBRST1_GPIOARST (1 << 0) /* IO port A reset */ +#define CRM_AHBRST1_GPIOBRST (1 << 1) /* IO port B reset */ +#define CRM_AHBRST1_GPIOCRST (1 << 2) /* IO port C reset */ +#define CRM_AHBRST1_GPIODRST (1 << 3) /* IO port D reset */ +#define CRM_AHBRST1_GPIOERST (1 << 4) /* IO port E reset */ +#define CRM_AHBRST1_GPIOFRST (1 << 5) /* IO port F reset */ +#define CRM_AHBRST1_GPIOGRST (1 << 6) /* IO port G reset */ +#define CRM_AHBRST1_GPIOHRST (1 << 7) /* IO port H reset */ +#define CRM_AHBRST1_CRCRST (1 << 12) /* CRC reset */ +#define CRM_AHBRST1_EDMARST (1 << 21) /* EDMA reset */ +#define CRM_AHBRST1_DMA1RST (1 << 22) /* DMA1 reset */ +#define CRM_AHBRST1_DMA2RST (1 << 24) /* DMA2 reset */ +#define CRM_AHBRST1_EMACRST (1 << 25) /* EMAC reset */ +#define CRM_AHBRST1_OTGFS2RST (1 << 29) /* OTGFS2 reset */ + +/* AHB2 peripheral reset register */ + +#define CRM_AHBRST2_DVPRST (1 << 0) /* DVP reset */ +#define CRM_AHBRST2_OTGFS1RST (1 << 7) /* OTGFS1 reset */ +#define CRM_AHBRST2_SDIO1RST (1 << 15) /* SDIO1 reset */ + +/* AHB3 peripheral reset register */ + +#define CRM_AHBRST3_XMCRST (1 << 0) /* XMC reset */ +#define CRM_AHBRST3_QSPI1RST (1 << 0) /* QSPI1 reset */ +#define CRM_AHBRST3_QSPI2RST (1 << 0) /* QSPI2 reset */ +#define CRM_AHBRST3_SDIO2RST (1 << 0) /* SDIO2 reset */ + +/* APB1 Peripheral reset register */ + +#define CRM_APB1RST_TMR2RST (1 << 0) /* Timer2 reset */ +#define CRM_APB1RST_TMR3RST (1 << 1) /* Timer3 reset */ +#define CRM_APB1RST_TMR4RST (1 << 2) /* Timer4 reset */ +#define CRM_APB1RST_TMR5RST (1 << 3) /* Timer5 reset */ +#define CRM_APB1RST_TMR6RST (1 << 4) /* Timer6 reset */ +#define CRM_APB1RST_TMR7RST (1 << 5) /* Timer7 reset */ +#define CRM_APB1RST_TMR12RST (1 << 6) /* Timer12 reset */ +#define CRM_APB1RST_TMR13RST (1 << 7) /* Timer13 reset */ +#define CRM_APB1RST_TMR14RST (1 << 8) /* Timer14 reset */ +#define CRM_APB1RST_WWDTRST (1 << 11) /* Window watchdog reset */ +#define CRM_APB1RST_SPI2RST (1 << 14) /* SPI2 reset */ +#define CRM_APB1RST_SPI3RST (1 << 15) /* SPI3 reset */ +#define CRM_APB1RST_USART2RST (1 << 17) /* USART2 reset */ +#define CRM_APB1RST_USART3RST (1 << 18) /* USART3 reset */ +#define CRM_APB1RST_UART4RST (1 << 19) /* UART4 reset */ +#define CRM_APB1RST_UART5RST (1 << 20) /* UART5 reset */ +#define CRM_APB1RST_I2C1RST (1 << 21) /* I2C1 reset */ +#define CRM_APB1RST_I2C2RST (1 << 22) /* I2C2 reset */ +#define CRM_APB1RST_I2C3RST (1 << 23) /* I2C3 reset */ +#define CRM_APB1RST_CAN1RST (1 << 25) /* CAN1 reset */ +#define CRM_APB1RST_CAN2RST (1 << 26) /* CAN2 reset */ +#define CRM_APB1RST_PWCRST (1 << 28) /* Power interface reset */ +#define CRM_APB1RST_DACRST (1 << 29) /* DAC interface reset */ +#define CRM_APB1RST_UART7RST (1 << 30) /* UART7 reset */ +#define CRM_APB1RST_UART8RST (1 << 31) /* UART8 reset */ + +/* APB2 Peripheral reset register */ + +#define CRM_APB2RST_TMR1RST (1 << 0) /* TMR1 timer reset */ +#define CRM_APB2RST_TMR8RST (1 << 1) /* TMR8 timer reset */ +#define CRM_APB2RST_USART1RST (1 << 4) /* USART1 reset */ +#define CRM_APB2RST_USART6RST (1 << 5) /* USART6 reset */ +#define CRM_APB2RST_ADCRST (1 << 8) /* ADC interface reset */ +#define CRM_APB2RST_SPI1RST (1 << 12) /* SPI1 reset */ +#define CRM_APB2RST_SPI4RST (1 << 13) /* SPI4 reset */ +#define CRM_APB2RST_SCFGRST (1 << 14) /* SCFG reset */ +#define CRM_APB2RST_TMR9RST (1 << 16) /* Timer9 reset */ +#define CRM_APB2RST_TMR10RST (1 << 17) /* Timer10 reset */ +#define CRM_APB2RST_TMR11RST (1 << 18) /* Timer11 reset */ +#define CRM_APB2RST_TMR20RST (1 << 20) /* Timer20 reset */ +#define CRM_APB2RST_ACCRST (1 << 29) /* ACC reset */ + +/* AHB1 Peripheral Clock enable register */ + +#define CRM_AHB1EN1_GPIOEN(n) (1 << (n)) +#define CRM_AHBEN1_GPIOAEN (1 << 0) /* IO port A clock enable */ +#define CRM_AHBEN1_GPIOBEN (1 << 1) /* IO port B clock enable */ +#define CRM_AHBEN1_GPIOCEN (1 << 2) /* IO port C clock enable */ +#define CRM_AHBEN1_GPIODEN (1 << 3) /* IO port D clock enable */ +#define CRM_AHBEN1_GPIOEEN (1 << 4) /* IO port E clock enable */ +#define CRM_AHBEN1_GPIOFEN (1 << 5) /* IO port F clock enable */ +#define CRM_AHBEN1_GPIOGEN (1 << 6) /* IO port G clock enable */ +#define CRM_AHBEN1_GPIOHEN (1 << 7) /* IO port H clock enable */ +#define CRM_AHBEN1_CRCEN (1 << 12) /* CRC clock enable */ +#define CRM_AHBEN1_EDMAEN (1 << 21) /* EDMA clock enable */ +#define CRM_AHBEN1_DMA1EN (1 << 22) /* DMA1 clock enable */ +#define CRM_AHBEN1_DMA2EN (1 << 24) /* DMA2 clock enable */ +#define CRM_AHBEN1_EMACEN (1 << 25) /* EMAC clock enable */ +#define CRM_AHBEN1_EMACTXEN (1 << 26) /* EMAC TX clock enable */ +#define CRM_AHBEN1_EMACRXEN (1 << 27) /* EMAC RX clock enable */ +#define CRM_AHBEN1_EMACPTPEN (1 << 28) /* EMAC PTP clock enable */ +#define CRM_AHBEN1_OTGFS2EN (1 << 29) /* OTGFS2 clock enable */ + +/* AHB2 Peripheral Clock enable register */ + +#define CRM_AHBEN2_DVPEN (1 << 0) /* DVP clock enable */ +#define CRM_AHBEN2_OTGFS1EN (1 << 7) /* OTGFS1 clock enable */ +#define CRM_AHBEN2_SDIO1EN (1 << 15) /* SDIO1 clock enable */ + +/* AHB3 Peripheral Clock enable register */ + +#define CRM_AHBEN3_XMCEN (1 << 0) /* XMC clock enable */ +#define CRM_AHBEN3_QSPI1EN (1 << 1) /* QSPI1 clock enable */ +#define CRM_AHBEN3_QSPI2EN (1 << 14) /* QSPI2 clock enable */ +#define CRM_AHBEN3_SDIO2EN (1 << 15) /* SDIO2 clock enable */ + +/* APB1 Peripheral Clock enable register */ + +#define CRM_APB1EN_TMR2EN (1 << 0) /* Timer2 clock enable */ +#define CRM_APB1EN_TMR3EN (1 << 1) /* Timer3 clock enable */ +#define CRM_APB1EN_TMR4EN (1 << 2) /* Timer4 clock enable */ +#define CRM_APB1EN_TMR5EN (1 << 3) /* Timer5 clock enable */ +#define CRM_APB1EN_TMR6EN (1 << 4) /* Timer6 clock enable */ +#define CRM_APB1EN_TMR7EN (1 << 5) /* Timer7 clock enable */ +#define CRM_APB1EN_TMR12EN (1 << 6) /* Timer12 clock enable */ +#define CRM_APB1EN_TMR13EN (1 << 7) /* Timer13 clock enable */ +#define CRM_APB1EN_TMR14EN (1 << 8) /* Timer14 clock enable */ +#define CRM_APB1EN_WWDTEN (1 << 11) /* Window watchdog clock enable */ +#define CRM_APB1EN_SPI2EN (1 << 14) /* SPI2 clock enable */ +#define CRM_APB1EN_SPI3EN (1 << 15) /* SPI3 clock enable */ +#define CRM_APB1EN_USART2EN (1 << 17) /* USART2 clock enable */ +#define CRM_APB1EN_USART3EN (1 << 18) /* USART3 clock enable */ +#define CRM_APB1EN_UART4EN (1 << 19) /* UART4 clock enable */ +#define CRM_APB1EN_UART5EN (1 << 20) /* UART5 clock enable */ +#define CRM_APB1EN_I2C1EN (1 << 21) /* I2C1 clock enable */ +#define CRM_APB1EN_I2C2EN (1 << 22) /* I2C2 clock enable */ +#define CRM_APB1EN_I2C3EN (1 << 23) /* I2C3 clock enable */ +#define CRM_APB1EN_CAN1EN (1 << 25) /* CAN1 clock enable */ +#define CRM_APB1EN_CAN2EN (1 << 26) /* CAN2 clock enable */ +#define CRM_APB1EN_PWCEN (1 << 28) /* Power interface clock enable */ +#define CRM_APB1EN_DACEN (1 << 29) /* DAC interface clock enable */ +#define CRM_APB1EN_UART7EN (1 << 30) /* UART7 clock enable */ +#define CRM_APB1EN_UART8EN (1 << 31) /* UART8 clock enable */ + +/* APB2 Peripheral Clock enable register */ + +#define CRM_APB2EN_TMR1EN (1 << 0) /* TMR1 timer clock enable */ +#define CRM_APB2EN_TMR8EN (1 << 1) /* TMR8 timer clock enable */ +#define CRM_APB2EN_USART1EN (1 << 4) /* USART1 clock enable */ +#define CRM_APB2EN_USART6EN (1 << 5) /* USART6 clock enable */ +#define CRM_APB2EN_ADC1EN (1 << 8) /* ADC1 interface clock enable */ +#define CRM_APB2EN_ADC2EN (1 << 9) /* ADC2 interface clock enable */ +#define CRM_APB2EN_ADC3EN (1 << 10) /* ADC3 interface clock enable */ +#define CRM_APB2EN_SPI1EN (1 << 12) /* SPI1 clock enable */ +#define CRM_APB2EN_SPI4EN (1 << 13) /* SPI4 clock enable */ +#define CRM_APB2EN_SCFGEN (1 << 14) /* SCFG clock enable */ +#define CRM_APB2EN_TMR9EN (1 << 16) /* Timer9 clock enable */ +#define CRM_APB2EN_TMR10EN (1 << 17) /* Timer10 clock enable */ +#define CRM_APB2EN_TMR11EN (1 << 18) /* Timer11 clock enable */ +#define CRM_APB2EN_TMR20EN (1 << 20) /* Timer20 clock enable */ +#define CRM_APB2EN_ACCEN (1 << 29) /* ACC clock enable */ + +/* RCC AHB1 low power mode peripheral clock enable register */ + +#define CRM_AHBLPEN1_GPIOALPEN (1 << 0) /* IO port A clock enable during sleep mode */ +#define CRM_AHBLPEN1_GPIOBLPEN (1 << 1) /* IO port B clock enable during sleep mode */ +#define CRM_AHBLPEN1_GPIOCLPEN (1 << 2) /* IO port C clock enable during sleep mode */ +#define CRM_AHBLPEN1_GPIODLPEN (1 << 3) /* IO port D clock enable during sleep mode */ +#define CRM_AHBLPEN1_GPIOELPEN (1 << 4) /* IO port E clock enable during sleep mode */ +#define CRM_AHBLPEN1_GPIOFLPEN (1 << 5) /* IO port F clock enable during sleep mode */ +#define CRM_AHBLPEN1_GPIOGLPEN (1 << 6) /* IO port G clock enable during sleep mode */ +#define CRM_AHBLPEN1_GPIOHLPEN (1 << 7) /* IO port H clock enable during sleep mode */ +#define CRM_AHBLPEN1_CRCLPEN (1 << 12) /* CRC clock enable during sleep mode */ +#define CRM_AHBLPEN1_EDMALPEN (1 << 21) /* EDMA clock enable during sleep mode */ +#define CRM_AHBLPEN1_DMA1LPEN (1 << 22) /* DMA1 clock enable during sleep mode */ +#define CRM_AHBLPEN1_DMA2LPEN (1 << 24) /* DMA2 clock enable during sleep mode */ +#define CRM_AHBLPEN1_EMACLPEN (1 << 25) /* EMAC clock enable during sleep mode */ +#define CRM_AHBLPEN1_EMACTXLPEN (1 << 26) /* EMAC TX clock enable during sleep mode */ +#define CRM_AHBLPEN1_EMACRXLPEN (1 << 27) /* EMAC RX clock enable during sleep mode */ +#define CRM_AHBLPEN1_EMACPTPLPEN (1 << 28) /* EMAC PTP clock enable during sleep mode */ +#define CRM_AHBLPEN1_OTGFS2LPEN (1 << 29) /* OTGFS2 clock enable during sleep mode */ + +/* RCC AHB2 low power mode peripheral clock enable register */ + +#define CRM_AHBLPEN2_DVPLPEN (1 << 0) /* DVP clock enable during sleep mode */ +#define CRM_AHBLPEN2_OTGFS1LPEN (1 << 7) /* OTGFS1 clock enable during sleep mode */ +#define CRM_AHBLPEN2_SDIO1LPEN (1 << 15) /* SDIO1 clock enable during sleep mode */ + +/* RCC AHB3 low power mode Peripheral Clock enable register */ + +#define CRM_AHBLPEN3_XMCLPEN (1 << 0) /* XMC clock enable during sleep mode */ +#define CRM_AHBLPEN3_QSPI1LPEN (1 << 1) /* QSPI1 clock enable during sleep mode */ +#define CRM_AHBLPEN3_QSPI2LPEN (1 << 14) /* QSPI2 clock enable during sleep mode */ +#define CRM_AHBLPEN3_SDIO2LPEN (1 << 15) /* SDIO2 clock enable during sleep mode */ + +/* RCC APB1 low power mode peripheral clock enable register */ + +#define CRM_APB1LPEN_TMR2LPEN (1 << 0) /* Timer2 clock enable during sleep mode */ +#define CRM_APB1LPEN_TMR3LPEN (1 << 1) /* Timer3 clock enable during sleep mode */ +#define CRM_APB1LPEN_TMR4LPEN (1 << 2) /* Timer4 clock enable during sleep mode */ +#define CRM_APB1LPEN_TMR5LPEN (1 << 3) /* Timer5 clock enable during sleep mode */ +#define CRM_APB1LPEN_TMR6LPEN (1 << 4) /* Timer6 clock enable during sleep mode */ +#define CRM_APB1LPEN_TMR7LPEN (1 << 5) /* Timer7 clock enable during sleep mode */ +#define CRM_APB1LPEN_TMR12LPEN (1 << 6) /* Timer12 clock enable during sleep mode */ +#define CRM_APB1LPEN_TMR13LPEN (1 << 7) /* Timer13 clock enable during sleep mode */ +#define CRM_APB1LPEN_TMR14LPEN (1 << 8) /* Timer14 clock enable during sleep mode */ +#define CRM_APB1LPEN_WWDTLPEN (1 << 11) /* Window watchdog clock enable during sleep mode */ +#define CRM_APB1LPEN_SPI2LPEN (1 << 14) /* SPI2 clock enable during sleep mode */ +#define CRM_APB1LPEN_SPI3LPEN (1 << 15) /* SPI3 clock enable during sleep mode */ +#define CRM_APB1LPEN_USART2LPEN (1 << 17) /* USART2 clock enable during sleep mode */ +#define CRM_APB1LPEN_USART3LPEN (1 << 18) /* USART3 clock enable during sleep mode */ +#define CRM_APB1LPEN_UART4LPEN (1 << 19) /* UART4 clock enable during sleep mode */ +#define CRM_APB1LPEN_UART5LPEN (1 << 20) /* UART5 clock enable during sleep mode */ +#define CRM_APB1LPEN_I2C1LPEN (1 << 21) /* I2C1 clock enable during sleep mode */ +#define CRM_APB1LPEN_I2C2LPEN (1 << 22) /* I2C2 clock enable during sleep mode */ +#define CRM_APB1LPEN_I2C3LPEN (1 << 23) /* I2C3 clock enable during sleep mode */ +#define CRM_APB1LPEN_CAN1LPEN (1 << 25) /* CAN1 clock enable during sleep mode */ +#define CRM_APB1LPEN_CAN2LPEN (1 << 26) /* CAN2 clock enable during sleep mode */ +#define CRM_APB1LPEN_PWCLPEN (1 << 28) /* Power interface clock enable during sleep mode */ +#define CRM_APB1LPEN_DACLPEN (1 << 29) /* DAC interface clock enable during sleep mode */ +#define CRM_APB1LPEN_UART7LPEN (1 << 30) /* UART7 clock enable during sleep mode */ +#define CRM_APB1LPEN_UART8LPEN (1 << 31) /* UART8 clock enable during sleep mode */ + +/* RCC APB2 low power mode peripheral clock enable register */ + +#define CRM_APB2LPEN_TMR1LPEN (1 << 0) /* TMR1 timer clock enable during sleep mode */ +#define CRM_APB2LPEN_TMR8LPEN (1 << 1) /* TMR8 timer clock enable during sleep mode */ +#define CRM_APB2LPEN_USART1LPEN (1 << 4) /* USART1 clock enable during sleep mode */ +#define CRM_APB2LPEN_USART6LPEN (1 << 5) /* USART6 clock enable during sleep mode */ +#define CRM_APB2LPEN_ADC1LPEN (1 << 8) /* ADC1 interface clock enable during sleep mode */ +#define CRM_APB2LPEN_ADC2LPEN (1 << 9) /* ADC2 interface clock enable during sleep mode */ +#define CRM_APB2LPEN_ADC3LPEN (1 << 10) /* ADC3 interface clock enable during sleep mode */ +#define CRM_APB2LPEN_SPI1LPEN (1 << 12) /* SPI1 clock enable during sleep mode */ +#define CRM_APB2LPEN_SPI4LPEN (1 << 13) /* SPI4 clock enable during sleep mode */ +#define CRM_APB2LPEN_SCFGLPEN (1 << 14) /* SCFG clock enable during sleep mode */ +#define CRM_APB2LPEN_TMR9LPEN (1 << 16) /* Timer9 clock enable during sleep mode */ +#define CRM_APB2LPEN_TMR10LPEN (1 << 17) /* Timer10 clock enable during sleep mode */ +#define CRM_APB2LPEN_TMR11LPEN (1 << 18) /* Timer11 clock enable during sleep mode */ +#define CRM_APB2LPEN_TMR20LPEN (1 << 20) /* Timer20 clock enable during sleep mode */ +#define CRM_APB2LPEN_ACCLPEN (1 << 29) /* ACC clock enable during sleep mode */ + +/* Backup domain control register */ + +#define CRM_BPDC_LEXTEN (1 << 0) /* External low-speed oscillator enable */ +#define CRM_BPDC_LEXTSTBL (1 << 1) /* External low-speed oscillator stable */ +#define CRM_BPDC_LEXTBYPS + +#define CRM_BPDC_ERTCSEL_SHIFT (8) /* ERTC clock source selection */ +#define CRM_BPDC_ERTCSEL_MASK (3 << CRM_BPDC_ERTCSEL_SHIFT) +# define CRM_BPDC_ERTCSEL_LEXT (1 << CRM_BPDC_ERTCSEL_SHIFT) /* Select LEXT */ +# define CRM_BPDC_ERTCSEL_LICK (2 << CRM_BPDC_ERTCSEL_SHIFT) /* Select LICK */ +# define CRM_BPDC_ERTCSEL_HEXT (3 << CRM_BPDC_ERTCSEL_SHIFT) /* Select HEXT */ + +#define CRM_BPDC_ERTCEN (1 << 15) /* ERTC clock enable */ +#define CRM_BPDC_BPDRST (1 << 16) /* Battery powered domain software reset */ + +/* Control/status register */ + +#define CRM_CTRLSTS_LICKEN (1 << 0) /* LICK enable */ +#define CRM_CTRLSTS_LICKSTBL (1 << 1) /* LICK stable */ +#define CRM_CTRLSTS_RSTFC (1 << 24) /* Reset flag clear */ +#define CRM_CTRLSTS_NRSTF (1 << 26) /* NRST reset flag */ +#define CRM_CTRLSTS_PORRSTF (1 << 27) /* POR/LVR reset flag */ +#define CRM_CTRLSTS_SWRSTF (1 << 28) /* Software reset flag */ +#define CRM_CTRLSTS_WDTRSTF (1 << 29) /* WDT reset flag */ +#define CRM_CTRLSTS_WWDTRSTF (1 << 30) /* WWDT reset flag */ +#define CRM_CTRLSTS_LPRSTF (1 << 31) /* Low-power reset flag */ + +/* Misc1 register */ + +#define CRM_MISC1_HICKCAL_KEY (255 << 0)/* HICK calibration key */ +#define CRM_MISC1_HICKDIV (1 << 12) /* HICK 6 divider selection */ +#define CRM_MISC1_HICK_TO_USB (1 << 13) /* USB 48MHz clock source select */ +#define CRM_MISC1_HICK_TO_SCLK (1 << 14) /* HICK as system clock frequency select */ + +#define CRM_MISC1_CLKOUT2_SEL2_SHIFT (16) /* Clock output2 sel2 */ +#define CRM_MISC1_CLKOUT2_SEL2_MASK (15 << CRM_MISC1_CLKOUT2_SEL2_SHIFT) +# define CRM_MISC1_CLKOUT2_SEL2_USB (0 << CRM_MISC1_CLKOUT2_SEL2_SHIFT) /* Select USB output */ +# define CRM_MISC1_CLKOUT2_SEL2_ADC (1 << CRM_MISC1_CLKOUT2_SEL2_SHIFT) /* Select ADC output */ +# define CRM_MISC1_CLKOUT2_SEL2_HICK (2 << CRM_MISC1_CLKOUT2_SEL2_SHIFT) /* Select HICK output */ +# define CRM_MISC1_CLKOUT2_SEL2_LICK (3 << CRM_MISC1_CLKOUT2_SEL2_SHIFT) /* Select LICK output */ +# define CRM_MISC1_CLKOUT2_SEL2_LEXT (4 << CRM_MISC1_CLKOUT2_SEL2_SHIFT) /* Select LEXT output */ + +#define CRM_MISC1_CLKOUT1DIV2_SHIFT (24) /* Clock output1 division2 */ +#define CRM_MISC1_CLKOUT1DIV2_MASK (15 << CRM_MISC1_CLKOUT1DIV2_SHIFT) +# define CRM_MISC1_CLKOUT1DIV2_NONE (7 << CRM_MISC1_CLKOUT1DIV2_SHIFT) /* Clock output1 division2 none */ +# define CRM_MISC1_CLKOUT1DIV2_2 (8 << CRM_MISC1_CLKOUT1DIV2_SHIFT) /* Clock output1 division2 2 */ +# define CRM_MISC1_CLKOUT1DIV2_4 (9 << CRM_MISC1_CLKOUT1DIV2_SHIFT) /* Clock output1 division2 4*/ +# define CRM_MISC1_CLKOUT1DIV2_8 (10 << CRM_MISC1_CLKOUT1DIV2_SHIFT) /* Clock output1 division2 8 */ +# define CRM_MISC1_CLKOUT1DIV2_16 (11 << CRM_MISC1_CLKOUT1DIV2_SHIFT) /* Clock output1 division2 16 */ +# define CRM_MISC1_CLKOUT1DIV2_64 (12 << CRM_MISC1_CLKOUT1DIV2_SHIFT) /* Clock output1 division2 64 */ +# define CRM_MISC1_CLKOUT1DIV2_128 (13 << CRM_MISC1_CLKOUT1DIV2_SHIFT) /* Clock output1 division2 128 */ +# define CRM_MISC1_CLKOUT1DIV2_256 (14 << CRM_MISC1_CLKOUT1DIV2_SHIFT) /* Clock output1 division2 256 */ +# define CRM_MISC1_CLKOUT1DIV2_512 (15 << CRM_MISC1_CLKOUT1DIV2_SHIFT) /* Clock output1 division2 512 */ + +#define CRM_MISC1_CLKOUT2DIV2_SHIFT (28) /* Clock output2 division2 */ +#define CRM_MISC1_CLKOUT2DIV2_MASK (15 << CRM_MISC1_CLKOUT2DIV2_SHIFT) +# define CRM_MISC1_CLKOUT2DIV2_NONE (7 << CRM_MISC1_CLKOUT2DIV2_SHIFT) /* Clock output2 division2 none */ +# define CRM_MISC1_CLKOUT2DIV2_2 (8 << CRM_MISC1_CLKOUT2DIV2_SHIFT) /* Clock output2 division2 2 */ +# define CRM_MISC1_CLKOUT2DIV2_4 (9 << CRM_MISC1_CLKOUT2DIV2_SHIFT) /* Clock output2 division2 4*/ +# define CRM_MISC1_CLKOUT2DIV2_8 (10 << CRM_MISC1_CLKOUT2DIV2_SHIFT) /* Clock output2 division2 8 */ +# define CRM_MISC1_CLKOUT2DIV2_16 (11 << CRM_MISC1_CLKOUT2DIV2_SHIFT) /* Clock output2 division2 16 */ +# define CRM_MISC1_CLKOUT2DIV2_64 (12 << CRM_MISC1_CLKOUT2DIV2_SHIFT) /* Clock output2 division2 64 */ +# define CRM_MISC1_CLKOUT2DIV2_128 (13 << CRM_MISC1_CLKOUT2DIV2_SHIFT) /* Clock output2 division2 128 */ +# define CRM_MISC1_CLKOUT2DIV2_256 (14 << CRM_MISC1_CLKOUT2DIV2_SHIFT) /* Clock output2 division2 256 */ +# define CRM_MISC1_CLKOUT2DIV2_512 (15 << CRM_MISC1_CLKOUT2DIV2_SHIFT) /* Clock output2 division2 512 */ + +/* Misc1 register */ + +#define CRM_MISC2_AUTO_STEP_EN_SHIFT (4) /* auto step system clock switch enable */ +#define CRM_MISC2_AUTO_STEP_EN_MASK (3 << CRM_MISC2_AUTO_STEP_EN_SHIFT) +# define CRM_MISC2_AUTO_STEP_EN_DISABLE (0 << CRM_MISC2_AUTO_STEP_EN_SHIFT) /* disanle */ +# define CRM_MISC2_AUTO_STEP_EN_ENABLE (3 << CRM_MISC2_AUTO_STEP_EN_SHIFT) /* enable */ + +#define CRM_MISC2_CLK1_TO_TMR (1 << 8) /* CLKOUT1 internal connect to timer 10 channel 1 */ +#define CRM_MISC2_EMAC_PPS_SEL (1 << 9) /* Ethernet pulse width select */ + +#define CRM_MISC2_USBDIV_SHIFT (12) /* USB division */ +#define CRM_MISC2_USBDIV_MASK (15 << CRM_MISC2_USBDIV_SHIFT) +# define CRM_MISC2_USBDIV_1P5 (0 << CRM_MISC2_USBDIV_SHIFT) /* Div 1.5 */ +# define CRM_MISC2_USBDIV_1P0 (1 << CRM_MISC2_USBDIV_SHIFT) /* Div 1 */ +# define CRM_MISC2_USBDIV_2P5 (2 << CRM_MISC2_USBDIV_SHIFT) /* Div 2.5 */ +# define CRM_MISC2_USBDIV_2P0 (3 << CRM_MISC2_USBDIV_SHIFT) /* Div 2 */ +# define CRM_MISC2_USBDIV_3P5 (4 << CRM_MISC2_USBDIV_SHIFT) /* Div 3.5 */ +# define CRM_MISC2_USBDIV_3P0 (5 << CRM_MISC2_USBDIV_SHIFT) /* Div 3 */ +# define CRM_MISC2_USBDIV_4P5 (6 << CRM_MISC2_USBDIV_SHIFT) /* Div 4.5 */ +# define CRM_MISC2_USBDIV_4P0 (7 << CRM_MISC2_USBDIV_SHIFT) /* Div 4 */ +# define CRM_MISC2_USBDIV_5P5 (8 << CRM_MISC2_USBDIV_SHIFT) /* Div 5.5 */ +# define CRM_MISC2_USBDIV_5P0 (9 << CRM_MISC2_USBDIV_SHIFT) /* Div 5 */ +# define CRM_MISC2_USBDIV_6P5 (10 << CRM_MISC2_USBDIV_SHIFT) /* Div 6.5 */ +# define CRM_MISC2_USBDIV_6P0 (11 << CRM_MISC2_USBDIV_SHIFT) /* Div 6 */ +# define CRM_MISC2_USBDIV_7P0 (12 << CRM_MISC2_USBDIV_SHIFT) /* Div 7 */ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_RCC_H */ diff --git a/arch/arm/src/at32/hardware/at32f43xxx_syscfg.h b/arch/arm/src/at32/hardware/at32f43xxx_syscfg.h new file mode 100644 index 0000000000..ce97639a95 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32f43xxx_syscfg.h @@ -0,0 +1,288 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32f43xxx_syscfg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_SYSCFG_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_SYSCFG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define AT32_SCFG_CFG1_OFFSET (0x00) +#define AT32_SCFG_CFG2_OFFSET (0x04) +#define AT32_SCFG_EXTICR_OFFSET(p) (0x0008 + ((p) & 0x000c)) /* Registers are displaced by 4! */ +#define AT32_SCFG_EXINTC1_OFFSET (0x08) +#define AT32_SCFG_EXINTC2_OFFSET (0x0C) +#define AT32_SCFG_EXINTC3_OFFSET (0x10) +#define AT32_SCFG_EXINTC4_OFFSET (0x14) +#define AT32_SCFG_UHDRV_OFFSET (0x2C) + +/* Register Addresses *******************************************************/ + +#define AT32_SCFG_CFG1 (AT32_SCFG_BASE+AT32_SCFG_CFG1_OFFSET) +#define AT32_SCFG_CFG2 (AT32_SCFG_BASE+AT32_SCFG_CFG2_OFFSET) +#define AT32_SCFG_EXTICR(p) (AT32_SCFG_BASE+AT32_SCFG_EXTICR_OFFSET(p)) +#define AT32_SCFG_EXINTC1 (AT32_SCFG_BASE+AT32_SCFG_EXINTC1_OFFSET) +#define AT32_SCFG_EXINTC2 (AT32_SCFG_BASE+AT32_SCFG_EXINTC2_OFFSET) +#define AT32_SCFG_EXINTC3 (AT32_SCFG_BASE+AT32_SCFG_EXINTC3_OFFSET) +#define AT32_SCFG_EXINTC4 (AT32_SCFG_BASE+AT32_SCFG_EXINTC4_OFFSET) +#define AT32_SCFG_UHDRV (AT32_SCFG_BASE+AT32_SCFG_UHDRV_OFFSET) + +/* Register Bitfield Definitions ********************************************/ + +/* SCFG config1 register */ + +#define SCFG_CFG1_MEM_MAP_SEL_SHIFT (0) /* memory address mapping selection */ +#define SCFG_CFG1_MEM_MAP_SEL_MASK (3 << SCFG_CFG1_MEM_MAP_SEL_SHIFT) +# define SCFG_CFG1_MEM_MAP_SEL_FLASH (0 << SCFG_CFG1_MEM_MAP_SEL_SHIFT) /* 000: Main Flash memory mapped at 0x0000 0000 */ +# define SCFG_CFG1_MEM_MAP_SEL_SYSTEM (1 << SCFG_CFG1_MEM_MAP_SEL_SHIFT) /* 001: System Flash memory mapped at 0x0000 0000 */ +# define SCFG_CFG1_MEM_MAP_SEL_XMC (2 << SCFG_CFG1_MEM_MAP_SEL_SHIFT) /* 010: XMC Bank1 (NOR/PSRAM 1 and 2) mapped at 0x0000 0000 */ +# define SCFG_CFG1_MEM_MAP_SEL_SRAM (3 << SCFG_CFG1_MEM_MAP_SEL_SHIFT) /* 011: Embedded SRAM (112kB) mapped at 0x0000 0000 */ +# define SCFG_CFG1_MEM_MAP_SEL_SDRAM (4 << SCFG_CFG1_MEM_MAP_SEL_SHIFT) /* 100: XMC SDRAM Bank1 mapped at 0x0000 0000 */ + +#define SCFG_CFG1_IR_POL (1 << 5) /* Infrared output polarity selection */ + +#define SCFG_CFG1_IR_SRC_SEL_SHIFT (6) /* Infrared modulation envelope signal source selection */ +#define SCFG_CFG1_IR_SRC_SEL_MASK (3 << SCFG_CFG1_IR_SRC_SEL_SHIFT) +# define SCFG_CFG1_IR_SRC_SEL_TMR10 (0 << SCFG_CFG1_IR_SRC_SEL_SHIFT) /* Source use TRM10 */ +# define SCFG_CFG1_IR_SRC_SEL_USART1 (1 << SCFG_CFG1_IR_SRC_SEL_SHIFT) /* Source use USART1 */ +# define SCFG_CFG1_IR_SRC_SEL_USART2 (2 << SCFG_CFG1_IR_SRC_SEL_SHIFT) /* Source use USART2 */ + +#define SCFG_CFG1_SWAP_XMC_SHIFT (6) /* Infrared modulation envelope signal source selection */ +#define SCFG_CFG1_SWAP_XMC_MASK (3 << SCFG_CFG1_SWAP_XMC_SHIFT) +# define SCFG_CFG1_SWAP_XMC_NONE (0 << SCFG_CFG1_SWAP_XMC_SHIFT) /* No swap */ +# define SCFG_CFG1_SWAP_XMC_SDRAM1 (1 << SCFG_CFG1_SWAP_XMC_SHIFT) /* SDRAM swap1 */ +# define SCFG_CFG1_SWAP_XMC_QSPI2 (2 << SCFG_CFG1_SWAP_XMC_SHIFT) /* QSPI2 swap */ +# define SCFG_CFG1_SWAP_XMC_SDRAM2 (3 << SCFG_CFG1_SWAP_XMC_SHIFT) /* SDRAM swap2 */ + +/* SCFG config2 register */ + +#define SCFG_CFG2_MII_RMII_SEL (1 << 23) /* MII or RMII selection */ + +#define SCFG_EXINTCR_PORT_MASK (15) +#define SCFG_EXINTCR_EXTI_SHIFT(g) (((g) & 3) << 2) +#define SCFG_EXINTCR_EXTI_MASK(g) (SCFG_EXINTCR_PORT_MASK << (SCFG_EXINTCR_EXTI_SHIFT(g))) + +/* SCFG EXINTC1 register */ + +#define SCFG_EXINTC1_EXINT0_SHIFT (0) /* configure EXINT0 source */ +#define SCFG_EXINTC1_EXINT0_MASK (15 << SCFG_EXINTC1_EXINT0_SHIFT) +# define SCFG_EXINTC1_EXINT0_GPIOA (0 << SCFG_EXINTC1_EXINT0_SHIFT) +# define SCFG_EXINTC1_EXINT0_GPIOB (1 << SCFG_EXINTC1_EXINT0_SHIFT) +# define SCFG_EXINTC1_EXINT0_GPIOC (2 << SCFG_EXINTC1_EXINT0_SHIFT) +# define SCFG_EXINTC1_EXINT0_GPIOD (3 << SCFG_EXINTC1_EXINT0_SHIFT) +# define SCFG_EXINTC1_EXINT0_GPIOE (4 << SCFG_EXINTC1_EXINT0_SHIFT) +# define SCFG_EXINTC1_EXINT0_GPIOF (5 << SCFG_EXINTC1_EXINT0_SHIFT) +# define SCFG_EXINTC1_EXINT0_GPIOG (6 << SCFG_EXINTC1_EXINT0_SHIFT) +# define SCFG_EXINTC1_EXINT0_GPIOH (7 << SCFG_EXINTC1_EXINT0_SHIFT) + +#define SCFG_EXINTC1_EXINT1_SHIFT (4) /* configure EXINT1 source */ +#define SCFG_EXINTC1_EXINT1_MASK (15 << SCFG_EXINTC1_EXINT1_SHIFT) +# define SCFG_EXINTC1_EXINT1_GPIOA (0 << SCFG_EXINTC1_EXINT1_SHIFT) +# define SCFG_EXINTC1_EXINT1_GPIOB (1 << SCFG_EXINTC1_EXINT1_SHIFT) +# define SCFG_EXINTC1_EXINT1_GPIOC (2 << SCFG_EXINTC1_EXINT1_SHIFT) +# define SCFG_EXINTC1_EXINT1_GPIOD (3 << SCFG_EXINTC1_EXINT1_SHIFT) +# define SCFG_EXINTC1_EXINT1_GPIOE (4 << SCFG_EXINTC1_EXINT1_SHIFT) +# define SCFG_EXINTC1_EXINT1_GPIOF (5 << SCFG_EXINTC1_EXINT1_SHIFT) +# define SCFG_EXINTC1_EXINT1_GPIOG (6 << SCFG_EXINTC1_EXINT1_SHIFT) +# define SCFG_EXINTC1_EXINT1_GPIOH (7 << SCFG_EXINTC1_EXINT1_SHIFT) + +#define SCFG_EXINTC1_EXINT2_SHIFT (8) /* configure EXINT2 source */ +#define SCFG_EXINTC1_EXINT2_MASK (15 << SCFG_EXINTC1_EXINT2_SHIFT) +# define SCFG_EXINTC1_EXINT2_GPIOA (0 << SCFG_EXINTC1_EXINT2SHIFT) +# define SCFG_EXINTC1_EXINT2_GPIOB (1 << SCFG_EXINTC1_EXINT2_SHIFT) +# define SCFG_EXINTC1_EXINT2_GPIOC (2 << SCFG_EXINTC1_EXINT2_SHIFT) +# define SCFG_EXINTC1_EXINT2_GPIOD (3 << SCFG_EXINTC1_EXINT2_SHIFT) +# define SCFG_EXINTC1_EXINT2_GPIOE (4 << SCFG_EXINTC1_EXINT2_SHIFT) +# define SCFG_EXINTC1_EXINT2_GPIOF (5 << SCFG_EXINTC1_EXINT2_SHIFT) +# define SCFG_EXINTC1_EXINT2_GPIOG (6 << SCFG_EXINTC1_EXINT2_SHIFT) +# define SCFG_EXINTC1_EXINT2_GPIOH (7 << SCFG_EXINTC1_EXINT2_SHIFT) + +#define SCFG_EXINTC1_EXINT3_SHIFT (12) /* configure EXINT3 source */ +#define SCFG_EXINTC1_EXINT3_MASK (15 << SCFG_EXINTC1_EXINT3_SHIFT) +# define SCFG_EXINTC1_EXINT3_GPIOA (0 << SCFG_EXINTC1_EXINT3_SHIFT) +# define SCFG_EXINTC1_EXINT3_GPIOB (1 << SCFG_EXINTC1_EXINT3_SHIFT) +# define SCFG_EXINTC1_EXINT3_GPIOC (2 << SCFG_EXINTC1_EXINT3_SHIFT) +# define SCFG_EXINTC1_EXINT3_GPIOD (3 << SCFG_EXINTC1_EXINT3_SHIFT) +# define SCFG_EXINTC1_EXINT3_GPIOE (4 << SCFG_EXINTC1_EXINT3_SHIFT) +# define SCFG_EXINTC1_EXINT3_GPIOF (5 << SCFG_EXINTC1_EXINT3_SHIFT) +# define SCFG_EXINTC1_EXINT3_GPIOG (6 << SCFG_EXINTC1_EXINT3_SHIFT) +# define SCFG_EXINTC1_EXINT3_GPIOH (7 << SCFG_EXINTC1_EXINT3_SHIFT) + +/* SCFG EXINTC2 register */ + +#define SCFG_EXINTC2_EXINT4_SHIFT (0) /* configure EXINT4 source */ +#define SCFG_EXINTC2_EXINT4_MASK (15 << SCFG_EXINTC2_EXINT4_SHIFT) +# define SCFG_EXINTC2_EXINT4_GPIOA (0 << SCFG_EXINTC2_EXINT4_SHIFT) +# define SCFG_EXINTC2_EXINT4_GPIOB (1 << SCFG_EXINTC2_EXINT4_SHIFT) +# define SCFG_EXINTC2_EXINT4_GPIOC (2 << SCFG_EXINTC2_EXINT4_SHIFT) +# define SCFG_EXINTC2_EXINT4_GPIOD (3 << SCFG_EXINTC2_EXINT4_SHIFT) +# define SCFG_EXINTC2_EXINT4_GPIOE (4 << SCFG_EXINTC2_EXINT4_SHIFT) +# define SCFG_EXINTC2_EXINT4_GPIOF (5 << SCFG_EXINTC2_EXINT4_SHIFT) +# define SCFG_EXINTC2_EXINT4_GPIOG (6 << SCFG_EXINTC2_EXINT4_SHIFT) +# define SCFG_EXINTC2_EXINT4_GPIOH (7 << SCFG_EXINTC2_EXINT4_SHIFT) + +#define SCFG_EXINTC2_EXINT5_SHIFT (4) /* configure EXINT5 source */ +#define SCFG_EXINTC2_EXINT5_MASK (15 << SCFG_EXINTC2_EXINT5_SHIFT) +# define SCFG_EXINTC2_EXINT5_GPIOA (0 << SCFG_EXINTC2_EXINT5_SHIFT) +# define SCFG_EXINTC2_EXINT5_GPIOB (1 << SCFG_EXINTC2_EXINT5_SHIFT) +# define SCFG_EXINTC2_EXINT5_GPIOC (2 << SCFG_EXINTC2_EXINT5_SHIFT) +# define SCFG_EXINTC2_EXINT5_GPIOD (3 << SCFG_EXINTC2_EXINT5_SHIFT) +# define SCFG_EXINTC2_EXINT5_GPIOE (4 << SCFG_EXINTC2_EXINT5_SHIFT) +# define SCFG_EXINTC2_EXINT5_GPIOF (5 << SCFG_EXINTC2_EXINT5_SHIFT) +# define SCFG_EXINTC2_EXINT5_GPIOG (6 << SCFG_EXINTC2_EXINT5_SHIFT) +# define SCFG_EXINTC2_EXINT5_GPIOH (7 << SCFG_EXINTC2_EXINT5_SHIFT) + +#define SCFG_EXINTC2_EXINT6_SHIFT (8) /* configure EXINT6 source */ +#define SCFG_EXINTC2_EXINT6_MASK (15 << SCFG_EXINTC2_EXINT6_SHIFT) +# define SCFG_EXINTC2_EXINT6_GPIOA (0 << SCFG_EXINTC2_EXINT6SHIFT) +# define SCFG_EXINTC2_EXINT6_GPIOB (1 << SCFG_EXINTC2_EXINT6_SHIFT) +# define SCFG_EXINTC2_EXINT6_GPIOC (2 << SCFG_EXINTC2_EXINT6_SHIFT) +# define SCFG_EXINTC2_EXINT6_GPIOD (3 << SCFG_EXINTC2_EXINT6_SHIFT) +# define SCFG_EXINTC2_EXINT6_GPIOE (4 << SCFG_EXINTC2_EXINT6_SHIFT) +# define SCFG_EXINTC2_EXINT6_GPIOF (5 << SCFG_EXINTC2_EXINT6_SHIFT) +# define SCFG_EXINTC2_EXINT6_GPIOG (6 << SCFG_EXINTC2_EXINT6_SHIFT) +# define SCFG_EXINTC2_EXINT6_GPIOH (7 << SCFG_EXINTC2_EXINT6_SHIFT) + +#define SCFG_EXINTC2_EXINT7_SHIFT (12) /* configure EXINT7 source */ +#define SCFG_EXINTC2_EXINT7_MASK (15 << SCFG_EXINTC2_EXINT7_SHIFT) +# define SCFG_EXINTC2_EXINT7_GPIOA (0 << SCFG_EXINTC2_EXINT7_SHIFT) +# define SCFG_EXINTC2_EXINT7_GPIOB (1 << SCFG_EXINTC2_EXINT7_SHIFT) +# define SCFG_EXINTC2_EXINT7_GPIOC (2 << SCFG_EXINTC2_EXINT7_SHIFT) +# define SCFG_EXINTC2_EXINT7_GPIOD (3 << SCFG_EXINTC2_EXINT7_SHIFT) +# define SCFG_EXINTC2_EXINT7_GPIOE (4 << SCFG_EXINTC2_EXINT7_SHIFT) +# define SCFG_EXINTC2_EXINT7_GPIOF (5 << SCFG_EXINTC2_EXINT7_SHIFT) +# define SCFG_EXINTC2_EXINT7_GPIOG (6 << SCFG_EXINTC2_EXINT7_SHIFT) +# define SCFG_EXINTC2_EXINT7_GPIOH (7 << SCFG_EXINTC2_EXINT7_SHIFT) + +/* SCFG EXINTC3 register */ + +#define SCFG_EXINTC3_EXINT8_SHIFT (0) /* configure EXINT8 source */ +#define SCFG_EXINTC3_EXINT8_MASK (15 << SCFG_EXINTC3_EXINT8_SHIFT) +# define SCFG_EXINTC3_EXINT8_GPIOA (0 << SCFG_EXINTC3_EXINT8_SHIFT) +# define SCFG_EXINTC3_EXINT8_GPIOB (1 << SCFG_EXINTC3_EXINT8_SHIFT) +# define SCFG_EXINTC3_EXINT8_GPIOC (2 << SCFG_EXINTC3_EXINT8_SHIFT) +# define SCFG_EXINTC3_EXINT8_GPIOD (3 << SCFG_EXINTC3_EXINT8_SHIFT) +# define SCFG_EXINTC3_EXINT8_GPIOE (4 << SCFG_EXINTC3_EXINT8_SHIFT) +# define SCFG_EXINTC3_EXINT8_GPIOF (5 << SCFG_EXINTC3_EXINT8_SHIFT) +# define SCFG_EXINTC3_EXINT8_GPIOG (6 << SCFG_EXINTC3_EXINT8_SHIFT) +# define SCFG_EXINTC3_EXINT8_GPIOH (7 << SCFG_EXINTC3_EXINT8_SHIFT) + +#define SCFG_EXINTC3_EXINT9_SHIFT (4) /* configure EXINT9 source */ +#define SCFG_EXINTC3_EXINT9_MASK (15 << SCFG_EXINTC3_EXINT9_SHIFT) +# define SCFG_EXINTC3_EXINT9_GPIOA (0 << SCFG_EXINTC3_EXINT9_SHIFT) +# define SCFG_EXINTC3_EXINT9_GPIOB (1 << SCFG_EXINTC3_EXINT9_SHIFT) +# define SCFG_EXINTC3_EXINT9_GPIOC (2 << SCFG_EXINTC3_EXINT9_SHIFT) +# define SCFG_EXINTC3_EXINT9_GPIOD (3 << SCFG_EXINTC3_EXINT9_SHIFT) +# define SCFG_EXINTC3_EXINT9_GPIOE (4 << SCFG_EXINTC3_EXINT9_SHIFT) +# define SCFG_EXINTC3_EXINT9_GPIOF (5 << SCFG_EXINTC3_EXINT9_SHIFT) +# define SCFG_EXINTC3_EXINT9_GPIOG (6 << SCFG_EXINTC3_EXINT9_SHIFT) +# define SCFG_EXINTC3_EXINT9_GPIOH (7 << SCFG_EXINTC3_EXINT9_SHIFT) + +#define SCFG_EXINTC3_EXINT10_SHIFT (8) /* configure EXINT10 source */ +#define SCFG_EXINTC3_EXINT10_MASK (15 << SCFG_EXINTC3_EXINT10_SHIFT) +# define SCFG_EXINTC3_EXINT10_GPIOA (0 << SCFG_EXINTC3_EXINT10SHIFT) +# define SCFG_EXINTC3_EXINT10_GPIOB (1 << SCFG_EXINTC3_EXINT10_SHIFT) +# define SCFG_EXINTC3_EXINT10_GPIOC (2 << SCFG_EXINTC3_EXINT10_SHIFT) +# define SCFG_EXINTC3_EXINT10_GPIOD (3 << SCFG_EXINTC3_EXINT10_SHIFT) +# define SCFG_EXINTC3_EXINT10_GPIOE (4 << SCFG_EXINTC3_EXINT10_SHIFT) +# define SCFG_EXINTC3_EXINT10_GPIOF (5 << SCFG_EXINTC3_EXINT10_SHIFT) +# define SCFG_EXINTC3_EXINT10_GPIOG (6 << SCFG_EXINTC3_EXINT10_SHIFT) +# define SCFG_EXINTC3_EXINT10_GPIOH (7 << SCFG_EXINTC3_EXINT10_SHIFT) + +#define SCFG_EXINTC3_EXINT11_SHIFT (12) /* configure EXINT11 source */ +#define SCFG_EXINTC3_EXINT11_MASK (15 << SCFG_EXINTC3_EXINT11_SHIFT) +# define SCFG_EXINTC3_EXINT11_GPIOA (0 << SCFG_EXINTC3_EXINT11_SHIFT) +# define SCFG_EXINTC3_EXINT11_GPIOB (1 << SCFG_EXINTC3_EXINT11_SHIFT) +# define SCFG_EXINTC3_EXINT11_GPIOC (2 << SCFG_EXINTC3_EXINT11_SHIFT) +# define SCFG_EXINTC3_EXINT11_GPIOD (3 << SCFG_EXINTC3_EXINT11_SHIFT) +# define SCFG_EXINTC3_EXINT11_GPIOE (4 << SCFG_EXINTC3_EXINT11_SHIFT) +# define SCFG_EXINTC3_EXINT11_GPIOF (5 << SCFG_EXINTC3_EXINT11_SHIFT) +# define SCFG_EXINTC3_EXINT11_GPIOG (6 << SCFG_EXINTC3_EXINT11_SHIFT) +# define SCFG_EXINTC3_EXINT11_GPIOH (7 << SCFG_EXINTC3_EXINT11_SHIFT) + +/* SCFG EXINTC4 register */ + +#define SCFG_EXINTC4_EXINT12_SHIFT (0) /* configure EXINT12 source */ +#define SCFG_EXINTC4_EXINT12_MASK (15 << SCFG_EXINTC4_EXINT12_SHIFT) +# define SCFG_EXINTC4_EXINT12_GPIOA (0 << SCFG_EXINTC4_EXINT12_SHIFT) +# define SCFG_EXINTC4_EXINT12_GPIOB (1 << SCFG_EXINTC4_EXINT12_SHIFT) +# define SCFG_EXINTC4_EXINT12_GPIOC (2 << SCFG_EXINTC4_EXINT12_SHIFT) +# define SCFG_EXINTC4_EXINT12_GPIOD (3 << SCFG_EXINTC4_EXINT12_SHIFT) +# define SCFG_EXINTC4_EXINT12_GPIOE (4 << SCFG_EXINTC4_EXINT12_SHIFT) +# define SCFG_EXINTC4_EXINT12_GPIOF (5 << SCFG_EXINTC4_EXINT12_SHIFT) +# define SCFG_EXINTC4_EXINT12_GPIOG (6 << SCFG_EXINTC4_EXINT12_SHIFT) +# define SCFG_EXINTC4_EXINT12_GPIOH (7 << SCFG_EXINTC4_EXINT12_SHIFT) + +#define SCFG_EXINTC4_EXINT13_SHIFT (4) /* configure EXINT13 source */ +#define SCFG_EXINTC4_EXINT13_MASK (15 << SCFG_EXINTC4_EXINT13_SHIFT) +# define SCFG_EXINTC4_EXINT13_GPIOA (0 << SCFG_EXINTC4_EXINT13_SHIFT) +# define SCFG_EXINTC4_EXINT13_GPIOB (1 << SCFG_EXINTC4_EXINT13_SHIFT) +# define SCFG_EXINTC4_EXINT13_GPIOC (2 << SCFG_EXINTC4_EXINT13_SHIFT) +# define SCFG_EXINTC4_EXINT13_GPIOD (3 << SCFG_EXINTC4_EXINT13_SHIFT) +# define SCFG_EXINTC4_EXINT13_GPIOE (4 << SCFG_EXINTC4_EXINT13_SHIFT) +# define SCFG_EXINTC4_EXINT13_GPIOF (5 << SCFG_EXINTC4_EXINT13_SHIFT) +# define SCFG_EXINTC4_EXINT13_GPIOG (6 << SCFG_EXINTC4_EXINT13_SHIFT) +# define SCFG_EXINTC4_EXINT13_GPIOH (7 << SCFG_EXINTC4_EXINT13_SHIFT) + +#define SCFG_EXINTC4_EXINT14_SHIFT (8) /* configure EXINT14 source */ +#define SCFG_EXINTC4_EXINT14_MASK (15 << SCFG_EXINTC4_EXINT14_SHIFT) +# define SCFG_EXINTC4_EXINT14_GPIOA (0 << SCFG_EXINTC4_EXINT14SHIFT) +# define SCFG_EXINTC4_EXINT14_GPIOB (1 << SCFG_EXINTC4_EXINT14_SHIFT) +# define SCFG_EXINTC4_EXINT14_GPIOC (2 << SCFG_EXINTC4_EXINT14_SHIFT) +# define SCFG_EXINTC4_EXINT14_GPIOD (3 << SCFG_EXINTC4_EXINT14_SHIFT) +# define SCFG_EXINTC4_EXINT14_GPIOE (4 << SCFG_EXINTC4_EXINT14_SHIFT) +# define SCFG_EXINTC4_EXINT14_GPIOF (5 << SCFG_EXINTC4_EXINT14_SHIFT) +# define SCFG_EXINTC4_EXINT14_GPIOG (6 << SCFG_EXINTC4_EXINT14_SHIFT) +# define SCFG_EXINTC4_EXINT14_GPIOH (7 << SCFG_EXINTC4_EXINT14_SHIFT) + +#define SCFG_EXINTC4_EXINT15_SHIFT (12) /* configure EXINT15 source */ +#define SCFG_EXINTC4_EXINT15_MASK (15 << SCFG_EXINTC4_EXINT15_SHIFT) +# define SCFG_EXINTC4_EXINT15_GPIOA (0 << SCFG_EXINTC4_EXINT15_SHIFT) +# define SCFG_EXINTC4_EXINT15_GPIOB (1 << SCFG_EXINTC4_EXINT15_SHIFT) +# define SCFG_EXINTC4_EXINT15_GPIOC (2 << SCFG_EXINTC4_EXINT15_SHIFT) +# define SCFG_EXINTC4_EXINT15_GPIOD (3 << SCFG_EXINTC4_EXINT15_SHIFT) +# define SCFG_EXINTC4_EXINT15_GPIOE (4 << SCFG_EXINTC4_EXINT15_SHIFT) +# define SCFG_EXINTC4_EXINT15_GPIOF (5 << SCFG_EXINTC4_EXINT15_SHIFT) +# define SCFG_EXINTC4_EXINT15_GPIOG (6 << SCFG_EXINTC4_EXINT15_SHIFT) +# define SCFG_EXINTC4_EXINT15_GPIOH (7 << SCFG_EXINTC4_EXINT15_SHIFT) + +/* SCFG UHDRV register */ + +#define SCFG_UHDRV_PB3_UH (1 << 0) /* PB3 Ultra high sourcing/sinking strength */ +#define SCFG_UHDRV_PB9_UH (1 << 1) /* PB9 Ultra high sourcing/sinking strength */ +#define SCFG_UHDRV_PB10_UH (1 << 2) /* PB10 Ultra high sourcing/sinking strength */ +#define SCFG_UHDRV_PD12_UH (1 << 5) /* PD12 Ultra high sourcing/sinking strength */ +#define SCFG_UHDRV_PD13_UH (1 << 6) /* PD13 Ultra high sourcing/sinking strength */ +#define SCFG_UHDRV_PD14_UH (1 << 7) /* PD14 Ultra high sourcing/sinking strength */ +#define SCFG_UHDRV_PD15_UH (1 << 8) /* PD15 Ultra high sourcing/sinking strength */ +#define SCFG_UHDRV_PF14_UH (1 << 9) /* PF14 Ultra high sourcing/sinking strength */ +#define SCFG_UHDRV_PF15_UH (1 << 10)/* PF15 Ultra high sourcing/sinking strength */ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_SYSCFG_H */ diff --git a/arch/arm/src/at32/hardware/at32f43xxx_uart.h b/arch/arm/src/at32/hardware/at32f43xxx_uart.h new file mode 100644 index 0000000000..4cc9ab4f42 --- /dev/null +++ b/arch/arm/src/at32/hardware/at32f43xxx_uart.h @@ -0,0 +1,250 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32f43xxx_uart.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_UART_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_UART_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define AT32_USART_STS_OFFSET (0x00) /* Status register */ +#define AT32_USART_DT_OFFSET (0x04) /* Data register */ +#define AT32_USART_BAUDR_OFFSET (0x08) /* Baud Rate register */ +#define AT32_USART_CTRL1_OFFSET (0x0c) /* Control register 1 */ +#define AT32_USART_CTRL2_OFFSET (0x10) /* Control register 2 */ +#define AT32_USART_CTRL3_OFFSET (0x14) /* Control register 3 */ +#define AT32_USART_GDIV_OFFSET (0x18) /* Guard time register */ + +/* Register Addresses *******************************************************/ + +#if AT32_NUSART > 0 +# define AT32_USART1_STS (AT32_USART1_BASE+AT32_USART_STS_OFFSET) +# define AT32_USART1_DT (AT32_USART1_BASE+AT32_USART_DT_OFFSET) +# define AT32_USART1_BAUDR (AT32_USART1_BASE+AT32_USART_BAUDR_OFFSET) +# define AT32_USART1_CTRL1 (AT32_USART1_BASE+AT32_USART_CTRL1_OFFSET) +# define AT32_USART1_CTRL2 (AT32_USART1_BASE+AT32_USART_CTRL2_OFFSET) +# define AT32_USART1_CTRL3 (AT32_USART1_BASE+AT32_USART_CTRL3_OFFSET) +# define AT32_USART1_GDIV (AT32_USART1_BASE+AT32_USART_GDIV_OFFSET) +#endif + +#if AT32_NUSART > 1 +# define AT32_USART2_STS (AT32_USART2_BASE+AT32_USART_STS_OFFSET) +# define AT32_USART2_DT (AT32_USART2_BASE+AT32_USART_DT_OFFSET) +# define AT32_USART2_BAUDR (AT32_USART2_BASE+AT32_USART_BAUDR_OFFSET) +# define AT32_USART2_CTRL1 (AT32_USART2_BASE+AT32_USART_CTRL1_OFFSET) +# define AT32_USART2_CTRL2 (AT32_USART2_BASE+AT32_USART_CTRL2_OFFSET) +# define AT32_USART2_CTRL3 (AT32_USART2_BASE+AT32_USART_CTRL3_OFFSET) +# define AT32_USART2_GDIV (AT32_USART2_BASE+AT32_USART_GDIV_OFFSET) +#endif + +#if AT32_NUSART > 2 +# define AT32_USART3_STS (AT32_USART3_BASE+AT32_USART_STS_OFFSET) +# define AT32_USART3_DT (AT32_USART3_BASE+AT32_USART_DT_OFFSET) +# define AT32_USART3_BAUDR (AT32_USART3_BASE+AT32_USART_BAUDR_OFFSET) +# define AT32_USART3_CTRL1 (AT32_USART3_BASE+AT32_USART_CTRL1_OFFSET) +# define AT32_USART3_CTRL2 (AT32_USART3_BASE+AT32_USART_CTRL2_OFFSET) +# define AT32_USART3_CTRL3 (AT32_USART3_BASE+AT32_USART_CTRL3_OFFSET) +# define AT32_USART3_GDIV (AT32_USART3_BASE+AT32_USART_GDIV_OFFSET) +#endif + +#if AT32_NUSART > 3 +# define AT32_UART4_STS (AT32_UART4_BASE+AT32_USART_STS_OFFSET) +# define AT32_UART4_DT (AT32_UART4_BASE+AT32_USART_DT_OFFSET) +# define AT32_UART4_BAUDR (AT32_UART4_BASE+AT32_USART_BAUDR_OFFSET) +# define AT32_UART4_CTRL1 (AT32_UART4_BASE+AT32_USART_CTRL1_OFFSET) +# define AT32_UART4_CTRL2 (AT32_UART4_BASE+AT32_USART_CTRL2_OFFSET) +# define AT32_UART4_CTRL3 (AT32_UART4_BASE+AT32_USART_CTRL3_OFFSET) +# define AT32_UART4_GDIV (AT32_UART4_BASE+AT32_USART_GDIV_OFFSET) +#endif + +#if AT32_NUSART > 4 +# define AT32_UART5_STS (AT32_UART5_BASE+AT32_USART_STS_OFFSET) +# define AT32_UART5_DT (AT32_UART5_BASE+AT32_USART_DT_OFFSET) +# define AT32_UART5_BAUDR (AT32_UART5_BASE+AT32_USART_BAUDR_OFFSET) +# define AT32_UART5_CTRL1 (AT32_UART5_BASE+AT32_USART_CTRL1_OFFSET) +# define AT32_UART5_CTRL2 (AT32_UART5_BASE+AT32_USART_CTRL2_OFFSET) +# define AT32_UART5_CTRL3 (AT32_UART5_BASE+AT32_USART_CTRL3_OFFSET) +# define AT32_UART5_GDIV (AT32_UART5_BASE+AT32_USART_GDIV_OFFSET) +#endif + +#if AT32_NUSART > 5 +# define AT32_USART6_STS (AT32_USART6_BASE+AT32_USART_STS_OFFSET) +# define AT32_USART6_DT (AT32_USART6_BASE+AT32_USART_DT_OFFSET) +# define AT32_USART6_BAUDR (AT32_USART6_BASE+AT32_USART_BAUDR_OFFSET) +# define AT32_USART6_CTRL1 (AT32_USART6_BASE+AT32_USART_CTRL1_OFFSET) +# define AT32_USART6_CTRL2 (AT32_USART6_BASE+AT32_USART_CTRL2_OFFSET) +# define AT32_USART6_CTRL3 (AT32_USART6_BASE+AT32_USART_CTRL3_OFFSET) +# define AT32_USART6_GDIV (AT32_USART6_BASE+AT32_USART_GDIV_OFFSET) +#endif + +#if AT32_NUSART > 6 +# define AT32_UART7_STS (AT32_UART7_BASE+AT32_USART_STS_OFFSET) +# define AT32_UART7_DT (AT32_UART7_BASE+AT32_USART_DT_OFFSET) +# define AT32_UART7_BAUDR (AT32_UART7_BASE+AT32_USART_BAUDR_OFFSET) +# define AT32_UART7_CTRL1 (AT32_UART7_BASE+AT32_USART_CTRL1_OFFSET) +# define AT32_UART7_CTRL2 (AT32_UART7_BASE+AT32_USART_CTRL2_OFFSET) +# define AT32_UART7_CTRL3 (AT32_UART7_BASE+AT32_USART_CTRL3_OFFSET) +# define AT32_UART7_GDIV (AT32_UART7_BASE+AT32_USART_GDIV_OFFSET) +#endif + +#if AT32_NUSART > 7 +# define AT32_UART8_STS (AT32_UART8_BASE+AT32_USART_STS_OFFSET) +# define AT32_UART8_DT (AT32_UART8_BASE+AT32_USART_DT_OFFSET) +# define AT32_UART8_BAUDR (AT32_UART8_BASE+AT32_USART_BAUDR_OFFSET) +# define AT32_UART8_CTRL1 (AT32_UART8_BASE+AT32_USART_CTRL1_OFFSET) +# define AT32_UART8_CTRL2 (AT32_UART8_BASE+AT32_USART_CTRL2_OFFSET) +# define AT32_UART8_CTRL3 (AT32_UART8_BASE+AT32_USART_CTRL3_OFFSET) +# define AT32_UART8_GDIV (AT32_UART8_BASE+AT32_USART_GDIV_OFFSET) +#endif + +/* Register Bitfield Definitions ********************************************/ + +/* Status register */ + +#define USART_STS_PERR (1 << 0) /* Parity error */ +#define USART_STS_FERR (1 << 1) /* Framing error */ +#define USART_STS_NERR (1 << 2) /* Noise error */ +#define USART_STS_ROERR (1 << 3) /* Receiver overflow error */ +#define USART_STS_IDLEF (1 << 4) /* Idle flag */ +#define USART_STS_RDBF (1 << 5) /* Receive data buffer full */ +#define USART_STS_TDC (1 << 6) /* Transmit data complete */ +#define USART_STS_TDBE (1 << 7) /* Transmit data buffer empty */ +#define USART_STS_BFF (1 << 8) /* break frame flag */ +#define USART_STS_CTSCF (1 << 9) /* CTS change flag */ + +#define USART_STS_ALLBITS (0x03ff) +#define USART_STS_CLRBITS (USART_STS_CTSCF | USART_STS_BFF) + +/* Data register */ + +#define USART_DT_SHIFT (0) /* Data value */ +#define USART_DT_MASK (0xff << USART_DT_SHIFT) + +/* Baud Rate Register */ + +#define USART_BAUDR_DIV_SHIFT (0) /* Baud Rate division */ +#define USART_BAUDR_DIV_MASK (0xffff << USART_BAUDR_DIV_SHIFT) + +/* Control register 1 */ + +#define USART_CTRL1_SBF (1 << 0) /* Send break frame */ +#define USART_CTRL1_RM (1 << 1) /* Receiver mute */ +#define USART_CTRL1_REN (1 << 2) /* Receiver enable */ +#define USART_CTRL1_TEN (1 << 3) /* Transmitter enable */ +#define USART_CTRL1_IDLEIEN (1 << 4) /* IDLE interrupt enable */ +#define USART_CTRL1_RDBFIEN (1 << 5) /* RDBF interrupt enable */ +#define USART_CTRL1_TDCIEN (1 << 6) /* TDC interrupt enable */ +#define USART_CTRL1_TDBEIEN (1 << 7) /* TDBE interrupt enable */ +#define USART_CTRL1_PERRIEN (1 << 8) /* PERR interrupt enable */ +#define USART_CTRL1_PSEL (1 << 9) /* Parity selection */ +#define USART_CTRL1_PEN (1 << 10) /* Parity enable */ +#define USART_CTRL1_WUM (1 << 11) /* Wake up mode */ +#define USART_CTRL1_DBN0 (1 << 12) /* Data bit num */ +#define USART_CTRL1_UEN (1 << 13) /* USART enable */ + +#define USART_CTRL1_TCDT_SHIFT (16) /* transmit complete delay time */ +#define USART_CTRL1_TCDT_MASK (31 << USART_CTRL1_TCDT_SHIFT) +#define USART_CTRL1_TCDT(X) ((X) << USART_CTRL1_TCDT_SHIFT) +#define USART_CTRL1_TSDT_SHIFT (21) /* transmit start delay time */ +#define USART_CTRL1_TSDT_MASK (31 << USART_CTRL1_TSDT_SHIFT) +#define USART_CTRL1_TSDT(X) ((X) << USART_CTRL1_TSDT_SHIFT) +#define USART_CTRL1_DBN1 (1 << 28) /* Data bit num */ + +#define USART_CTRL1_ALLINTS (USART_CTRL1_IDLEIEN|USART_CTRL1_RDBFIEN|USART_CTRL1_TDCIEN|USART_CTRL1_PERRIEN) +/* Control register 2 */ + +#define USART_CTRL2_ID_L_SHIFT (0) /* USART identification low */ +#define USART_CTRL2_ID_L_MASK (15 << USART_CTRL2_ID_L_SHIFT) +#define USART_CTRL2_ID_L(X) ((X) << USART_CTRL2_ID_L_SHIFT) +#define USART_CTRL2_IDBN (1 << 4) /* Identification bit num */ +#define USART_CTRL2_BFBN (1 << 5) /* break frame bit num */ +#define USART_CTRL2_BFIEN (1 << 6) /* break frame interrupt enable */ +#define USART_CTRL2_LBCP (1 << 8) /* Last bit clock pulse */ +#define USART_CTRL2_CLKPHA (1 << 9) /* Clock phase */ +#define USART_CTRL2_CLKPOL (1 << 10) /* Clock polarity */ +#define USART_CTRL2_CLKEN (1 << 11) /* Clock enable */ + +#define USART_CTRL2_STOPBN_SHIFT (12) /* STOP bit num */ +#define USART_CTRL2_STOPBN_MASK (3 << USART_CTRL2_STOPBN_SHIFT) +# define USART_CTRL2_STOPBN_10 (0 << USART_CTRL2_STOPBN_SHIFT) /* 1 stop */ +# define USART_CTRL2_STOPBN_05 (1 << USART_CTRL2_STOPBN_SHIFT) /* 0.5 stop */ +# define USART_CTRL2_STOPBN_20 (2 << USART_CTRL2_STOPBN_SHIFT) /* 2 stop */ +# define USART_CTRL2_STOPBN_15 (3 << USART_CTRL2_STOPBN_SHIFT) /* 1.5 stop */ + +#define USART_CTRL2_LINEN (1 << 14) /* LIN mode enable */ +#define USART_CTRL2_TRPSWAP (1 << 15) /* Transmit receive pin swap */ + +#define USART_CTRL2_ID_H_SHIFT (28) /* USART identification high */ +#define USART_CTRL2_ID_H_MASK (31 << USART_CTRL2_ID_H_SHIFT) +#define USART_CTRL2_ID_H(X) ((X) << USART_CTRL2_ID_H_SHIFT) + +/* Control register 3 */ + +#define USART_CTRL3_ERRIEN (1 << 0) /* Error interrupt enable */ +#define USART_CTRL3_IRDAEN (1 << 1) /* IrDA enable */ +#define USART_CTRL3_IRDALP (1 << 2) /* IrDA low-power mode */ +#define USART_CTRL3_SLBEN (1 << 3) /* Single line bidirectional halfduplex enable */ +#define USART_CTRL3_SCNACKEN (1 << 4) /* Smart card NACK enable */ +#define USART_CTRL3_SCMEN (1 << 5) /* Smart card mode enable */ +#define USART_CTRL3_DMAREN (1 << 6) /* DMA receiver enable */ +#define USART_CTRL3_DMATEN (1 << 7) /* DMA transmit enable */ +#define USART_CTRL3_RTSEN (1 << 8) /* RTS enable */ +#define USART_CTRL3_CTSEN (1 << 9) /* CTS enable */ +#define USART_CTRL3_CTSCFIEN (1 << 10) /* CTSCF interrupt enable */ +#define USART_CTRL3_RS485EN (1 << 14) /* RS485 enable */ +#define USART_CTRL3_DEP (1 << 15) /* DE polarity selection */ + +/* Guard time and prescaler register */ + +#define USART_GDIV_ISDIV_SHIFT (0) /* IrDA/smartcard division */ +#define USART_GDIV_ISDIV_MASK (255 << USART_GDIV_ISDIV_SHIFT) +#define USART_GDIV_ISDIV(X) ((X) << USART_GDIV_ISDIV_SHIFT) + +#define USART_GDIV_SCGT_SHIFT (8) /* Smart card guard time */ +#define USART_GDIV_SCGT_MASK (255 << USART_GDIV_SCGT_SHIFT) +#define USART_GDIV_SCGT(X) ((X) << USART_GDIV_SCGT_SHIFT) + +#define AT32_USART_RDR_OFFSET AT32_USART_DT_OFFSET /* Receive data register */ +#define AT32_USART_TDR_OFFSET AT32_USART_DT_OFFSET /* Transmit data register */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32F43XXX_UART_H */ diff --git a/arch/arm/src/at32/hardware/at32fxxxxx_otgfs.h b/arch/arm/src/at32/hardware/at32fxxxxx_otgfs.h new file mode 100644 index 0000000000..ef3569fffc --- /dev/null +++ b/arch/arm/src/at32/hardware/at32fxxxxx_otgfs.h @@ -0,0 +1,1221 @@ +/**************************************************************************** + * arch/arm/src/at32/hardware/at32fxxxxx_otgfs.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_AT32_HARDWARE_AT32FXXXXX_OTGFS_H +#define __ARCH_ARM_SRC_AT32_HARDWARE_AT32FXXXXX_OTGFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* General definitions */ + +#define OTGFS_EPTYPE_CTRL (0) /* Control */ +#define OTGFS_EPTYPE_ISOC (1) /* Isochronous */ +#define OTGFS_EPTYPE_BULK (2) /* Bulk */ +#define OTGFS_EPTYPE_INTR (3) /* Interrupt */ + +#define OTGFS_PID_DATA0 (0) +#define OTGFS_PID_DATA2 (1) +#define OTGFS_PID_DATA1 (2) +#define OTGFS_PID_MDATA (3) /* Non-control */ +#define OTGFS_PID_SETUP (3) /* Control */ + +/* Register Offsets *********************************************************/ + +/* Core global control and status registers */ + +#define AT32_OTGFS_GOTGCTL_OFFSET 0x0000 /* Control and status register */ +#define AT32_OTGFS_GOTGINT_OFFSET 0x0004 /* Interrupt register */ +#define AT32_OTGFS_GAHBCFG_OFFSET 0x0008 /* AHB configuration register */ +#define AT32_OTGFS_GUSBCFG_OFFSET 0x000c /* USB configuration register */ +#define AT32_OTGFS_GRSTCTL_OFFSET 0x0010 /* Reset register */ +#define AT32_OTGFS_GINTSTS_OFFSET 0x0014 /* Core interrupt register */ +#define AT32_OTGFS_GINTMSK_OFFSET 0x0018 /* Interrupt mask register */ +#define AT32_OTGFS_GRXSTSR_OFFSET 0x001c /* Receive status debug read/OTG status read register */ +#define AT32_OTGFS_GRXSTSP_OFFSET 0x0020 /* Receive status debug read/OTG status pop register */ +#define AT32_OTGFS_GRXFSIZ_OFFSET 0x0024 /* Receive FIFO size register */ +#define AT32_OTGFS_HNPTXFSIZ_OFFSET 0x0028 /* Host non-periodic transmit FIFO size register */ +#define AT32_OTGFS_DIEPTXF0_OFFSET 0x0028 /* Endpoint 0 Transmit FIFO size */ +#define AT32_OTGFS_HNPTXSTS_OFFSET 0x002c /* Non-periodic transmit FIFO/queue status register */ +#define AT32_OTGFS_GCCFG_OFFSET 0x0038 /* General core configuration register */ +#define AT32_OTGFS_CID_OFFSET 0x003c /* Core ID register */ +#define AT32_OTGFS_HPTXFSIZ_OFFSET 0x0100 /* Host periodic transmit FIFO size register */ + +#define AT32_OTGFS_DIEPTXF_OFFSET(n) (0x0104+(((n)-1) << 2)) /* n: 1 ~ 7 */ + +#define AT32_OTGFS_DIEPTXF1_OFFSET 0x0104 /* Device IN endpoint transmit FIFO1 size register */ +#define AT32_OTGFS_DIEPTXF2_OFFSET 0x0108 /* Device IN endpoint transmit FIFO2 size register */ +#define AT32_OTGFS_DIEPTXF3_OFFSET 0x010c /* Device IN endpoint transmit FIFO3 size register */ +#define AT32_OTGFS_DIEPTXF4_OFFSET 0x0110 /* Device IN endpoint transmit FIFO4 size register */ +#define AT32_OTGFS_DIEPTXF5_OFFSET 0x0114 /* Device IN endpoint transmit FIFO5 size register */ +#define AT32_OTGFS_DIEPTXF6_OFFSET 0x0118 /* Device IN endpoint transmit FIFO6 size register */ +#define AT32_OTGFS_DIEPTXF7_OFFSET 0x011c /* Device IN endpoint transmit FIFO7 size register */ + +/* Host-mode control and status registers */ + +#define AT32_OTGFS_HCFG_OFFSET 0x0400 /* Host configuration register */ +#define AT32_OTGFS_HFIR_OFFSET 0x0404 /* Host frame interval register */ +#define AT32_OTGFS_HFNUM_OFFSET 0x0408 /* Host frame number/frame time remaining register */ +#define AT32_OTGFS_HPTXSTS_OFFSET 0x0410 /* Host periodic transmit FIFO/queue status register */ +#define AT32_OTGFS_HAINT_OFFSET 0x0414 /* Host all channels interrupt register */ +#define AT32_OTGFS_HAINTMSK_OFFSET 0x0418 /* Host all channels interrupt mask register */ +#define AT32_OTGFS_HPRT_OFFSET 0x0440 /* Host port control and status register */ + +#define AT32_OTGFS_CHAN_OFFSET(n) (0x500 + ((n) << 5) /* n: 0 ~ 15 */ + +#define AT32_OTGFS_HCCHAR_CHOFFSET 0x0000 /* Host channel characteristics register */ +#define AT32_OTGFS_HCINT_CHOFFSET 0x0008 /* Host channel interrupt register */ +#define AT32_OTGFS_HCINTMSK_CHOFFSET 0x000c /* Host channel interrupt mask register */ +#define AT32_OTGFS_HCTSIZ_CHOFFSET 0x0010 /* Host channel interrupt register */ + +#define AT32_OTGFS_HCCHAR_OFFSET(n) (0x500 + ((n) << 5)) /* n: 0 ~ 15 */ + +#define AT32_OTGFS_HCCHAR0_OFFSET 0x0500 /* Host channel-0 characteristics register */ +#define AT32_OTGFS_HCCHAR1_OFFSET 0x0520 /* Host channel-1 characteristics register */ +#define AT32_OTGFS_HCCHAR2_OFFSET 0x0540 /* Host channel-2 characteristics register */ +#define AT32_OTGFS_HCCHAR3_OFFSET 0x0560 /* Host channel-3 characteristics register */ +#define AT32_OTGFS_HCCHAR4_OFFSET 0x0580 /* Host channel-4 characteristics register */ +#define AT32_OTGFS_HCCHAR5_OFFSET 0x05a0 /* Host channel-5 characteristics register */ +#define AT32_OTGFS_HCCHAR6_OFFSET 0x05c0 /* Host channel-6 characteristics register */ +#define AT32_OTGFS_HCCHAR7_OFFSET 0x05e0 /* Host channel-7 characteristics register */ +#define AT32_OTGFS_HCCHAR8_OFFSET 0x0600 /* Host channel-8 characteristics register */ +#define AT32_OTGFS_HCCHAR9_OFFSET 0x0620 /* Host channel-9 characteristics register */ +#define AT32_OTGFS_HCCHAR10_OFFSET 0x060 /* Host channel-10 characteristics register */ +#define AT32_OTGFS_HCCHAR11_OFFSET 0x0660 /* Host channel-11 characteristics register */ +#define AT32_OTGFS_HCCHAR12_OFFSET 0x0680 /* Host channel-12 characteristics register */ +#define AT32_OTGFS_HCCHAR13_OFFSET 0x06a0 /* Host channel-13 characteristics register */ +#define AT32_OTGFS_HCCHAR14_OFFSET 0x06c0 /* Host channel-14 characteristics register */ +#define AT32_OTGFS_HCCHAR15_OFFSET 0x06e0 /* Host channel-15 characteristics register */ + +#define AT32_OTGFS_HCINT_OFFSET(n) (0x508 + ((n) << 5)) /* n: 0 ~ 15 */ + +#define AT32_OTGFS_HCINT0_OFFSET 0x0508 /* Host channel-0 interrupt register */ +#define AT32_OTGFS_HCINT1_OFFSET 0x0528 /* Host channel-1 interrupt register */ +#define AT32_OTGFS_HCINT2_OFFSET 0x0548 /* Host channel-2 interrupt register */ +#define AT32_OTGFS_HCINT3_OFFSET 0x0568 /* Host channel-3 interrupt register */ +#define AT32_OTGFS_HCINT4_OFFSET 0x0588 /* Host channel-4 interrupt register */ +#define AT32_OTGFS_HCINT5_OFFSET 0x05a8 /* Host channel-5 interrupt register */ +#define AT32_OTGFS_HCINT6_OFFSET 0x05c8 /* Host channel-6 interrupt register */ +#define AT32_OTGFS_HCINT7_OFFSET 0x05e8 /* Host channel-7 interrupt register */ +#define AT32_OTGFS_HCINT8_OFFSET 0x0608 /* Host channel-8 interrupt register */ +#define AT32_OTGFS_HCINT9_OFFSET 0x0628 /* Host channel-9 interrupt register */ +#define AT32_OTGFS_HCINT10_OFFSET 0x0648 /* Host channel-10 interrupt register */ +#define AT32_OTGFS_HCINT11_OFFSET 0x0668 /* Host channel-11 interrupt register */ +#define AT32_OTGFS_HCINT12_OFFSET 0x0688 /* Host channel-12 interrupt register */ +#define AT32_OTGFS_HCINT13_OFFSET 0x06a8 /* Host channel-13 interrupt register */ +#define AT32_OTGFS_HCINT14_OFFSET 0x06c8 /* Host channel-14 interrupt register */ +#define AT32_OTGFS_HCINT15_OFFSET 0x06e8 /* Host channel-15 interrupt register */ + +#define AT32_OTGFS_HCINTMSK_OFFSET(n) (0x50c + ((n) << 5)) /* n: 0 ~ 15 */ + +#define AT32_OTGFS_HCINTMSK0_OFFSET 0x050c /* Host channel-0 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK1_OFFSET 0x052c /* Host channel-1 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK2_OFFSET 0x054c /* Host channel-2 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK3_OFFSET 0x056c /* Host channel-3 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK4_OFFSET 0x058c /* Host channel-4 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK5_OFFSET 0x05ac /* Host channel-5 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK6_OFFSET 0x05cc /* Host channel-6 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK7_OFFSET 0x05ec /* Host channel-7 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK8_OFFSET 0x060c /* Host channel-8 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK9_OFFSET 0x062c /* Host channel-9 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK10_OFFSET 0x064c /* Host channel-10 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK11_OFFSET 0x066c /* Host channel-11 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK12_OFFSET 0x068c /* Host channel-12 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK13_OFFSET 0x06ac /* Host channel-13 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK14_OFFSET 0x06cc /* Host channel-14 interrupt mask register */ +#define AT32_OTGFS_HCINTMSK15_OFFSET 0x06ec /* Host channel-15 interrupt mask register */ + +#define AT32_OTGFS_HCTSIZ_OFFSET(n) (0x510 + ((n) << 5)) /* n: 0 ~ 15 */ + +#define AT32_OTGFS_HCTSIZ0_OFFSET 0x0510 /* Host channel-0 interrupt register */ +#define AT32_OTGFS_HCTSIZ1_OFFSET 0x0530 /* Host channel-1 interrupt register */ +#define AT32_OTGFS_HCTSIZ2_OFFSET 0x0550 /* Host channel-2 interrupt register */ +#define AT32_OTGFS_HCTSIZ3_OFFSET 0x0570 /* Host channel-3 interrupt register */ +#define AT32_OTGFS_HCTSIZ4_OFFSET 0x0590 /* Host channel-4 interrupt register */ +#define AT32_OTGFS_HCTSIZ5_OFFSET 0x05b0 /* Host channel-5 interrupt register */ +#define AT32_OTGFS_HCTSIZ6_OFFSET 0x05d0 /* Host channel-6 interrupt register */ +#define AT32_OTGFS_HCTSIZ7_OFFSET 0x05f0 /* Host channel-7 interrupt register */ +#define AT32_OTGFS_HCTSIZ8_OFFSET 0x0610 /* Host channel-8 interrupt register */ +#define AT32_OTGFS_HCTSIZ9_OFFSET 0x0630 /* Host channel-9 interrupt register */ +#define AT32_OTGFS_HCTSIZ10_OFFSET 0x0650 /* Host channel-10 interrupt register */ +#define AT32_OTGFS_HCTSIZ11_OFFSET 0x0670 /* Host channel-11 interrupt register */ +#define AT32_OTGFS_HCTSIZ12_OFFSET 0x0690 /* Host channel-12 interrupt register */ +#define AT32_OTGFS_HCTSIZ13_OFFSET 0x06b0 /* Host channel-13 interrupt register */ +#define AT32_OTGFS_HCTSIZ14_OFFSET 0x06d0 /* Host channel-14 interrupt register */ +#define AT32_OTGFS_HCTSIZ15_OFFSET 0x06f0 /* Host channel-15 interrupt register */ + +/* Device-mode control and status registers */ + +#define AT32_OTGFS_DCFG_OFFSET 0x0800 /* Device configuration register */ +#define AT32_OTGFS_DCTL_OFFSET 0x0804 /* Device control register */ +#define AT32_OTGFS_DSTS_OFFSET 0x0808 /* Device status register */ +#define AT32_OTGFS_DIEPMSK_OFFSET 0x0810 /* Device IN endpoint common interrupt mask register */ +#define AT32_OTGFS_DOEPMSK_OFFSET 0x0814 /* Device OUT endpoint common interrupt mask register */ +#define AT32_OTGFS_DAINT_OFFSET 0x0818 /* Device all endpoints interrupt register */ +#define AT32_OTGFS_DAINTMSK_OFFSET 0x081c /* All endpoints interrupt mask register */ +#define AT32_OTGFS_DIEPEMPMSK_OFFSET 0x0834 /* Device IN endpoint FIFO empty interrupt mask register */ + +#define AT32_OTGFS_DIEP_OFFSET(n) (0x0900 + ((n) << 5)) /* n: 0 ~ 7 */ + +#define AT32_OTGFS_DIEPCTL_EPOFFSET 0x0000 /* Device endpoint control register */ +#define AT32_OTGFS_DIEPINT_EPOFFSET 0x0008 /* Device endpoint interrupt register */ +#define AT32_OTGFS_DIEPTSIZ_EPOFFSET 0x0010 /* Device IN endpoint transfer size register */ +#define AT32_OTGFS_DTXFSTS_EPOFFSET 0x0018 /* Device IN endpoint transmit FIFO status register */ + +#define AT32_OTGFS_DIEPCTL_OFFSET(n) (0x0900 + ((n) << 5)) /* n: 0 ~ 7 */ + +#define AT32_OTGFS_DIEPCTL0_OFFSET 0x0900 /* Device control IN endpoint 0 control register */ +#define AT32_OTGFS_DIEPCTL1_OFFSET 0x0920 /* Device control IN endpoint 1 control register */ +#define AT32_OTGFS_DIEPCTL2_OFFSET 0x0940 /* Device control IN endpoint 2 control register */ +#define AT32_OTGFS_DIEPCTL3_OFFSET 0x0960 /* Device control IN endpoint 3 control register */ +#define AT32_OTGFS_DIEPCTL4_OFFSET 0x0980 /* Device control IN endpoint 4 control register */ +#define AT32_OTGFS_DIEPCTL5_OFFSET 0x09a0 /* Device control IN endpoint 5 control register */ +#define AT32_OTGFS_DIEPCTL6_OFFSET 0x09c0 /* Device control IN endpoint 6 control register */ +#define AT32_OTGFS_DIEPCTL7_OFFSET 0x09e0 /* Device control IN endpoint 7 control register */ + +#define AT32_OTGFS_DIEPINT_OFFSET(n) (0x0908 + ((n) << 5)) /* n: 0 ~ 7 */ + +#define AT32_OTGFS_DIEPINT0_OFFSET 0x0908 /* Device endpoint-0 interrupt register */ +#define AT32_OTGFS_DIEPINT1_OFFSET 0x0928 /* Device endpoint-1 interrupt register */ +#define AT32_OTGFS_DIEPINT2_OFFSET 0x0948 /* Device endpoint-2 interrupt register */ +#define AT32_OTGFS_DIEPINT3_OFFSET 0x0968 /* Device endpoint-3 interrupt register */ +#define AT32_OTGFS_DIEPINT4_OFFSET 0x0988 /* Device endpoint-4 interrupt register */ +#define AT32_OTGFS_DIEPINT5_OFFSET 0x09a8 /* Device endpoint-5 interrupt register */ +#define AT32_OTGFS_DIEPINT6_OFFSET 0x09c8 /* Device endpoint-6 interrupt register */ +#define AT32_OTGFS_DIEPINT7_OFFSET 0x09e8 /* Device endpoint-7 interrupt register */ + +#define AT32_OTGFS_DIEPTSIZ_OFFSET(n) (0x910 + ((n) << 5)) /* n: 0 ~ 7 */ + +#define AT32_OTGFS_DIEPTSIZ0_OFFSET 0x0910 /* Device IN endpoint 0 transfer size register */ +#define AT32_OTGFS_DIEPTSIZ1_OFFSET 0x0930 /* Device IN endpoint 1 transfer size register */ +#define AT32_OTGFS_DIEPTSIZ2_OFFSET 0x0950 /* Device IN endpoint 2 transfer size register */ +#define AT32_OTGFS_DIEPTSIZ3_OFFSET 0x0970 /* Device IN endpoint 3 transfer size register */ +#define AT32_OTGFS_DIEPTSIZ4_OFFSET 0x0990 /* Device IN endpoint 4 transfer size register */ +#define AT32_OTGFS_DIEPTSIZ5_OFFSET 0x09b0 /* Device IN endpoint 5 transfer size register */ +#define AT32_OTGFS_DIEPTSIZ6_OFFSET 0x09d0 /* Device IN endpoint 6 transfer size register */ +#define AT32_OTGFS_DIEPTSIZ7_OFFSET 0x09f0 /* Device IN endpoint 7 transfer size register */ + +#define AT32_OTGFS_DTXFSTS_OFFSET(n) (0x0918 + ((n) << 5)) /* n: 0 ~ 7 */ + +#define AT32_OTGFS_DTXFSTS0_OFFSET 0x0918 /* Device OUT endpoint-0 TxFIFO status register */ +#define AT32_OTGFS_DTXFSTS1_OFFSET 0x0938 /* Device OUT endpoint-1 TxFIFO status register */ +#define AT32_OTGFS_DTXFSTS2_OFFSET 0x0958 /* Device OUT endpoint-2 TxFIFO status register */ +#define AT32_OTGFS_DTXFSTS3_OFFSET 0x0978 /* Device OUT endpoint-3 TxFIFO status register */ +#define AT32_OTGFS_DTXFSTS4_OFFSET 0x0998 /* Device OUT endpoint-4 TxFIFO status register */ +#define AT32_OTGFS_DTXFSTS5_OFFSET 0x09b8 /* Device OUT endpoint-5 TxFIFO status register */ +#define AT32_OTGFS_DTXFSTS6_OFFSET 0x09d8 /* Device OUT endpoint-6 TxFIFO status register */ +#define AT32_OTGFS_DTXFSTS7_OFFSET 0x09f8 /* Device OUT endpoint-7 TxFIFO status register */ + +#define AT32_OTGFS_DOEP_OFFSET(n) (0x0b00 + ((n) << 5)) /* n: 0 ~ 7 */ + +#define AT32_OTGFS_DOEPCTL_EPOFFSET 0x0000 /* Device control OUT endpoint 0 control register */ +#define AT32_OTGFS_DOEPINT_EPOFFSET 0x0008 /* Device endpoint-x interrupt register */ + +#define AT32_OTGFS_DOEPCTL_OFFSET(n) (0x0b00 + ((n) << 5)) /* n: 0 ~ 7 */ + +#define AT32_OTGFS_DOEPCTL0_OFFSET 0x00b00 /* Device OUT endpoint 0 control register */ +#define AT32_OTGFS_DOEPCTL1_OFFSET 0x00b20 /* Device OUT endpoint 1 control register */ +#define AT32_OTGFS_DOEPCTL2_OFFSET 0x00b40 /* Device OUT endpoint 2 control register */ +#define AT32_OTGFS_DOEPCTL3_OFFSET 0x00b60 /* Device OUT endpoint 3 control register */ +#define AT32_OTGFS_DOEPCTL4_OFFSET 0x00b80 /* Device OUT endpoint 4 control register */ +#define AT32_OTGFS_DOEPCTL5_OFFSET 0x00ba0 /* Device OUT endpoint 5 control register */ +#define AT32_OTGFS_DOEPCTL6_OFFSET 0x00bc0 /* Device OUT endpoint 6 control register */ +#define AT32_OTGFS_DOEPCTL7_OFFSET 0x00be0 /* Device OUT endpoint 7 control register */ + +#define AT32_OTGFS_DOEPINT_OFFSET(n) (0x0b08 + ((n) << 5)) /* n: 0 ~ 7 */ + +#define AT32_OTGFS_DOEPINT0_OFFSET 0x00b08 /* Device endpoint-0 interrupt register */ +#define AT32_OTGFS_DOEPINT1_OFFSET 0x00b28 /* Device endpoint-1 interrupt register */ +#define AT32_OTGFS_DOEPINT2_OFFSET 0x00b48 /* Device endpoint-2 interrupt register */ +#define AT32_OTGFS_DOEPINT3_OFFSET 0x00b68 /* Device endpoint-3 interrupt register */ +#define AT32_OTGFS_DOEPINT4_OFFSET 0x00b88 /* Device endpoint-4 interrupt register */ +#define AT32_OTGFS_DOEPINT5_OFFSET 0x00ba8 /* Device endpoint-5 interrupt register */ +#define AT32_OTGFS_DOEPINT6_OFFSET 0x00bc8 /* Device endpoint-6 interrupt register */ +#define AT32_OTGFS_DOEPINT7_OFFSET 0x00be8 /* Device endpoint-7 interrupt register */ + +#define AT32_OTGFS_DOEPTSIZ_OFFSET(n) (0x0b10 + ((n) << 5)) /* n: 0 ~ 7 */ + +#define AT32_OTGFS_DOEPTSIZ0_OFFSET 0x00b10 /* Device OUT endpoint-0 transfer size register */ +#define AT32_OTGFS_DOEPTSIZ1_OFFSET 0x00b30 /* Device OUT endpoint-1 transfer size register */ +#define AT32_OTGFS_DOEPTSIZ2_OFFSET 0x00b50 /* Device OUT endpoint-2 transfer size register */ +#define AT32_OTGFS_DOEPTSIZ3_OFFSET 0x00b70 /* Device OUT endpoint-3 transfer size register */ +#define AT32_OTGFS_DOEPTSIZ4_OFFSET 0x00b90 /* Device OUT endpoint-4 transfer size register */ +#define AT32_OTGFS_DOEPTSIZ5_OFFSET 0x00bb0 /* Device OUT endpoint-5 transfer size register */ +#define AT32_OTGFS_DOEPTSIZ6_OFFSET 0x00bd0 /* Device OUT endpoint-6 transfer size register */ +#define AT32_OTGFS_DOEPTSIZ7_OFFSET 0x00bf0 /* Device OUT endpoint-7 transfer size register */ + +/* Power and clock gating registers */ + +#define AT32_OTGFS_PCGCCTL_OFFSET 0x0e00 /* Power and clock gating control register */ + +/* Data FIFO (DFIFO) access registers */ + +#define AT32_OTGFS_DFIFO_DEP_OFFSET(n) (0x1000 + ((n) << 12)) /* dev: n: 0 ~ 7 host: n: 0 ~ 15 */ +#define AT32_OTGFS_DFIFO_HCH_OFFSET(n) (0x1000 + ((n) << 12)) /* dev: n: 0 ~ 7 host: n: 0 ~ 15 */ + +#define AT32_OTGFS_DFIFO_DEP0_OFFSET 0x1000 /* 0x1000-0x1ffc Device IN/OUT Endpoint 0 DFIFO Write/Read Access */ +#define AT32_OTGFS_DFIFO_HCH0_OFFSET 0x1000 /* 0x1000-0x1ffc Host OUT/IN Channel 0 DFIFO Read/Write Access */ + +#define AT32_OTGFS_DFIFO_DEP1_OFFSET 0x2000 /* 0x2000-0x2ffc Device IN/OUT Endpoint 1 DFIFO Write/Read Access */ +#define AT32_OTGFS_DFIFO_HCH1_OFFSET 0x2000 /* 0x2000-0x2ffc Host OUT/IN Channel 1 DFIFO Read/Write Access */ + +#define AT32_OTGFS_DFIFO_DEP2_OFFSET 0x3000 /* 0x3000-0x3ffc Device IN/OUT Endpoint 2 DFIFO Write/Read Access */ +#define AT32_OTGFS_DFIFO_HCH2_OFFSET 0x3000 /* 0x3000-0x3ffc Host OUT/IN Channel 2 DFIFO Read/Write Access */ + +#define AT32_OTGFS_DFIFO_DEP3_OFFSET 0x4000 /* 0x4000-0x4ffc Device IN/OUT Endpoint 3 DFIFO Write/Read Access */ +#define AT32_OTGFS_DFIFO_HCH3_OFFSET 0x4000 /* 0x4000-0x4ffc Host OUT/IN Channel 3 DFIFO Read/Write Access */ + +#define AT32_OTGFS_DFIFO_DEP4_OFFSET 0x5000 /* 0x1000-0x1ffc Device IN/OUT Endpoint 4 DFIFO Write/Read Access */ +#define AT32_OTGFS_DFIFO_HCH4_OFFSET 0x5000 /* 0x1000-0x1ffc Host OUT/IN Channel 4 DFIFO Read/Write Access */ + +#define AT32_OTGFS_DFIFO_DEP5_OFFSET 0x6000 /* 0x2000-0x2ffc Device IN/OUT Endpoint 5 DFIFO Write/Read Access */ +#define AT32_OTGFS_DFIFO_HCH5_OFFSET 0x6000 /* 0x2000-0x2ffc Host OUT/IN Channel 5 DFIFO Read/Write Access */ + +#define AT32_OTGFS_DFIFO_DEP6_OFFSET 0x7000 /* 0x3000-0x3ffc Device IN/OUT Endpoint 6 DFIFO Write/Read Access */ +#define AT32_OTGFS_DFIFO_HCH6_OFFSET 0x7000 /* 0x3000-0x3ffc Host OUT/IN Channel 6 DFIFO Read/Write Access */ + +#define AT32_OTGFS_DFIFO_DEP7_OFFSET 0x8000 /* 0x4000-0x4ffc Device IN/OUT Endpoint 7 DFIFO Write/Read Access */ +#define AT32_OTGFS_DFIFO_HCH7_OFFSET 0x8000 /* 0x4000-0x4ffc Host OUT/IN Channel 7 DFIFO Read/Write Access */ + +/* Register Addresses *******************************************************/ + +#define AT32_OTGFS_GOTGCTL (AT32_OTGFS1_BASE+AT32_OTGFS_GOTGCTL_OFFSET) +#define AT32_OTGFS_GOTGINT (AT32_OTGFS1_BASE+AT32_OTGFS_GOTGINT_OFFSET) +#define AT32_OTGFS_GAHBCFG (AT32_OTGFS1_BASE+AT32_OTGFS_GAHBCFG_OFFSET) +#define AT32_OTGFS_GUSBCFG (AT32_OTGFS1_BASE+AT32_OTGFS_GUSBCFG_OFFSET) +#define AT32_OTGFS_GRSTCTL (AT32_OTGFS1_BASE+AT32_OTGFS_GRSTCTL_OFFSET) +#define AT32_OTGFS_GINTSTS (AT32_OTGFS1_BASE+AT32_OTGFS_GINTSTS_OFFSET) +#define AT32_OTGFS_GINTMSK (AT32_OTGFS1_BASE+AT32_OTGFS_GINTMSK_OFFSET) +#define AT32_OTGFS_GRXSTSR (AT32_OTGFS1_BASE+AT32_OTGFS_GRXSTSR_OFFSET) +#define AT32_OTGFS_GRXSTSP (AT32_OTGFS1_BASE+AT32_OTGFS_GRXSTSP_OFFSET) +#define AT32_OTGFS_GRXFSIZ (AT32_OTGFS1_BASE+AT32_OTGFS_GRXFSIZ_OFFSET) +#define AT32_OTGFS_HNPTXFSIZ (AT32_OTGFS1_BASE+AT32_OTGFS_HNPTXFSIZ_OFFSET) +#define AT32_OTGFS_DIEPTXF0 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTXF0_OFFSET) +#define AT32_OTGFS_HNPTXSTS (AT32_OTGFS1_BASE+AT32_OTGFS_HNPTXSTS_OFFSET) +#define AT32_OTGFS_GCCFG (AT32_OTGFS1_BASE+AT32_OTGFS_GCCFG_OFFSET) +#define AT32_OTGFS_CID (AT32_OTGFS1_BASE+AT32_OTGFS_CID_OFFSET) +#define AT32_OTGFS_HPTXFSIZ (AT32_OTGFS1_BASE+AT32_OTGFS_HPTXFSIZ_OFFSET) + +#define AT32_OTGFS_DIEPTXF(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTXF_OFFSET(n)) +#define AT32_OTGFS_DIEPTXF1 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTXF1_OFFSET) +#define AT32_OTGFS_DIEPTXF2 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTXF2_OFFSET) +#define AT32_OTGFS_DIEPTXF3 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTXF3_OFFSET) +#define AT32_OTGFS_DIEPTXF4 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTXF4_OFFSET) +#define AT32_OTGFS_DIEPTXF5 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTXF5_OFFSET) +#define AT32_OTGFS_DIEPTXF6 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTXF6_OFFSET) +#define AT32_OTGFS_DIEPTXF7 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTXF7_OFFSET) + +/* Host-mode control and status registers */ + +#define AT32_OTGFS_HCFG (AT32_OTGFS1_BASE+AT32_OTGFS_HCFG_OFFSET) +#define AT32_OTGFS_HFIR (AT32_OTGFS1_BASE+AT32_OTGFS_HFIR_OFFSET) +#define AT32_OTGFS_HFNUM (AT32_OTGFS1_BASE+AT32_OTGFS_HFNUM_OFFSET) +#define AT32_OTGFS_HPTXSTS (AT32_OTGFS1_BASE+AT32_OTGFS_HPTXSTS_OFFSET) +#define AT32_OTGFS_HAINT (AT32_OTGFS1_BASE+AT32_OTGFS_HAINT_OFFSET) +#define AT32_OTGFS_HAINTMSK (AT32_OTGFS1_BASE+AT32_OTGFS_HAINTMSK_OFFSET) +#define AT32_OTGFS_HPRT (AT32_OTGFS1_BASE+AT32_OTGFS_HPRT_OFFSET) + +#define AT32_OTGFS_CHAN(n) (AT32_OTGFS1_BASE+AT32_OTGFS_CHAN_OFFSET(n)) + +#define AT32_OTGFS_HCCHAR(n) (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR_OFFSET(n)) +#define AT32_OTGFS_HCCHAR0 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR0_OFFSET) +#define AT32_OTGFS_HCCHAR1 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR1_OFFSET) +#define AT32_OTGFS_HCCHAR2 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR2_OFFSET) +#define AT32_OTGFS_HCCHAR3 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR3_OFFSET) +#define AT32_OTGFS_HCCHAR4 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR4_OFFSET) +#define AT32_OTGFS_HCCHAR5 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR5_OFFSET) +#define AT32_OTGFS_HCCHAR6 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR6_OFFSET) +#define AT32_OTGFS_HCCHAR7 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR7_OFFSET) +#define AT32_OTGFS_HCCHAR8 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR8_OFFSET) +#define AT32_OTGFS_HCCHAR9 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR9_OFFSET) +#define AT32_OTGFS_HCCHAR10 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR10_OFFSET) +#define AT32_OTGFS_HCCHAR11 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR11_OFFSET) +#define AT32_OTGFS_HCCHAR12 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR12_OFFSET) +#define AT32_OTGFS_HCCHAR13 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR13_OFFSET) +#define AT32_OTGFS_HCCHAR14 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR14_OFFSET) +#define AT32_OTGFS_HCCHAR15 (AT32_OTGFS1_BASE+AT32_OTGFS_HCCHAR15_OFFSET) + +#define AT32_OTGFS_HCINT(n) (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT_OFFSET(n)) +#define AT32_OTGFS_HCINT0 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT0_OFFSET) +#define AT32_OTGFS_HCINT1 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT1_OFFSET) +#define AT32_OTGFS_HCINT2 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT2_OFFSET) +#define AT32_OTGFS_HCINT3 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT3_OFFSET) +#define AT32_OTGFS_HCINT4 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT4_OFFSET) +#define AT32_OTGFS_HCINT5 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT5_OFFSET) +#define AT32_OTGFS_HCINT6 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT6_OFFSET) +#define AT32_OTGFS_HCINT7 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT7_OFFSET) +#define AT32_OTGFS_HCINT8 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT8_OFFSET) +#define AT32_OTGFS_HCINT9 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT9_OFFSET) +#define AT32_OTGFS_HCINT10 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT10_OFFSET) +#define AT32_OTGFS_HCINT11 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT11_OFFSET) +#define AT32_OTGFS_HCINT12 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT12_OFFSET) +#define AT32_OTGFS_HCINT13 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT13_OFFSET) +#define AT32_OTGFS_HCINT14 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT14_OFFSET) +#define AT32_OTGFS_HCINT15 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINT15_OFFSET) + +#define AT32_OTGFS_HCINTMSK(n) (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK_OFFSET(n)) +#define AT32_OTGFS_HCINTMSK0 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK0_OFFSET) +#define AT32_OTGFS_HCINTMSK1 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK1_OFFSET) +#define AT32_OTGFS_HCINTMSK2 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK2_OFFSET) +#define AT32_OTGFS_HCINTMSK3 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK3_OFFSET) +#define AT32_OTGFS_HCINTMSK4 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK4_OFFSET) +#define AT32_OTGFS_HCINTMSK5 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK5_OFFSET) +#define AT32_OTGFS_HCINTMSK6 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK6_OFFSET) +#define AT32_OTGFS_HCINTMSK7 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK7_OFFSET) +#define AT32_OTGFS_HCINTMSK8 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK8_OFFSET) +#define AT32_OTGFS_HCINTMSK9 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK9_OFFSET) +#define AT32_OTGFS_HCINTMSK10 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK10_OFFSET) +#define AT32_OTGFS_HCINTMSK11 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK11_OFFSET) +#define AT32_OTGFS_HCINTMSK12 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK12_OFFSET) +#define AT32_OTGFS_HCINTMSK13 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK13_OFFSET) +#define AT32_OTGFS_HCINTMSK14 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK14_OFFSET) +#define AT32_OTGFS_HCINTMSK15 (AT32_OTGFS1_BASE+AT32_OTGFS_HCINTMSK15_OFFSET) + +#define AT32_OTGFS_HCTSIZ(n) (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ_OFFSET(n)) +#define AT32_OTGFS_HCTSIZ0 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ0_OFFSET) +#define AT32_OTGFS_HCTSIZ1 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ1_OFFSET) +#define AT32_OTGFS_HCTSIZ2 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ2_OFFSET) +#define AT32_OTGFS_HCTSIZ3 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ3_OFFSET) +#define AT32_OTGFS_HCTSIZ4 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ4_OFFSET) +#define AT32_OTGFS_HCTSIZ5 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ5_OFFSET) +#define AT32_OTGFS_HCTSIZ6 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ6_OFFSET) +#define AT32_OTGFS_HCTSIZ7 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ7_OFFSET) +#define AT32_OTGFS_HCTSIZ8 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ8_OFFSET) +#define AT32_OTGFS_HCTSIZ9 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ9_OFFSET) +#define AT32_OTGFS_HCTSIZ10 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ10_OFFSET) +#define AT32_OTGFS_HCTSIZ11 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ11_OFFSET) +#define AT32_OTGFS_HCTSIZ12 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ12_OFFSET) +#define AT32_OTGFS_HCTSIZ13 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ13_OFFSET) +#define AT32_OTGFS_HCTSIZ14 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ14_OFFSET) +#define AT32_OTGFS_HCTSIZ15 (AT32_OTGFS1_BASE+AT32_OTGFS_HCTSIZ15_OFFSET) + +/* Device-mode control and status registers */ + +#define AT32_OTGFS_DCFG (AT32_OTGFS1_BASE+AT32_OTGFS_DCFG_OFFSET) +#define AT32_OTGFS_DCTL (AT32_OTGFS1_BASE+AT32_OTGFS_DCTL_OFFSET) +#define AT32_OTGFS_DSTS (AT32_OTGFS1_BASE+AT32_OTGFS_DSTS_OFFSET) +#define AT32_OTGFS_DIEPMSK (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPMSK_OFFSET) +#define AT32_OTGFS_DOEPMSK (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPMSK_OFFSET) +#define AT32_OTGFS_DAINT (AT32_OTGFS1_BASE+AT32_OTGFS_DAINT_OFFSET) +#define AT32_OTGFS_DAINTMSK (AT32_OTGFS1_BASE+AT32_OTGFS_DAINTMSK_OFFSET) +#define AT32_OTGFS_DIEPEMPMSK (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPEMPMSK_OFFSET) + +#define AT32_OTGFS_DIEP(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DIEP_OFFSET(n)) +#define AT32_OTGFS_DIEPCTL(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPCTL_OFFSET(n)) +#define AT32_OTGFS_DIEPCTL0 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPCTL0_OFFSET) +#define AT32_OTGFS_DIEPCTL1 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPCTL1_OFFSET) +#define AT32_OTGFS_DIEPCTL2 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPCTL2_OFFSET) +#define AT32_OTGFS_DIEPCTL3 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPCTL3_OFFSET) +#define AT32_OTGFS_DIEPCTL4 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPCTL4_OFFSET) +#define AT32_OTGFS_DIEPCTL5 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPCTL5_OFFSET) +#define AT32_OTGFS_DIEPCTL6 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPCTL6_OFFSET) +#define AT32_OTGFS_DIEPCTL7 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPCTL7_OFFSET) + +#define AT32_OTGFS_DIEPINT(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPINT_OFFSET(n)) +#define AT32_OTGFS_DIEPINT0 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPINT0_OFFSET) +#define AT32_OTGFS_DIEPINT1 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPINT1_OFFSET) +#define AT32_OTGFS_DIEPINT2 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPINT2_OFFSET) +#define AT32_OTGFS_DIEPINT3 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPINT3_OFFSET) +#define AT32_OTGFS_DIEPINT4 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPINT4_OFFSET) +#define AT32_OTGFS_DIEPINT5 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPINT5_OFFSET) +#define AT32_OTGFS_DIEPINT6 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPINT6_OFFSET) +#define AT32_OTGFS_DIEPINT7 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPINT7_OFFSET) + +#define AT32_OTGFS_DIEPTSIZ(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTSIZ_OFFSET(n)) +#define AT32_OTGFS_DIEPTSIZ0 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTSIZ0_OFFSET) +#define AT32_OTGFS_DIEPTSIZ1 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTSIZ1_OFFSET) +#define AT32_OTGFS_DIEPTSIZ2 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTSIZ2_OFFSET) +#define AT32_OTGFS_DIEPTSIZ3 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTSIZ3_OFFSET) +#define AT32_OTGFS_DIEPTSIZ4 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTSIZ4_OFFSET) +#define AT32_OTGFS_DIEPTSIZ5 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTSIZ5_OFFSET) +#define AT32_OTGFS_DIEPTSIZ6 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTSIZ6_OFFSET) +#define AT32_OTGFS_DIEPTSIZ7 (AT32_OTGFS1_BASE+AT32_OTGFS_DIEPTSIZ7_OFFSET) + +#define AT32_OTGFS_DTXFSTS(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DTXFSTS_OFFSET(n)) +#define AT32_OTGFS_DTXFSTS0 (AT32_OTGFS1_BASE+AT32_OTGFS_DTXFSTS0_OFFSET) +#define AT32_OTGFS_DTXFSTS1 (AT32_OTGFS1_BASE+AT32_OTGFS_DTXFSTS1_OFFSET) +#define AT32_OTGFS_DTXFSTS2 (AT32_OTGFS1_BASE+AT32_OTGFS_DTXFSTS2_OFFSET) +#define AT32_OTGFS_DTXFSTS3 (AT32_OTGFS1_BASE+AT32_OTGFS_DTXFSTS3_OFFSET) +#define AT32_OTGFS_DTXFSTS4 (AT32_OTGFS1_BASE+AT32_OTGFS_DTXFSTS4_OFFSET) +#define AT32_OTGFS_DTXFSTS5 (AT32_OTGFS1_BASE+AT32_OTGFS_DTXFSTS5_OFFSET) +#define AT32_OTGFS_DTXFSTS6 (AT32_OTGFS1_BASE+AT32_OTGFS_DTXFSTS6_OFFSET) +#define AT32_OTGFS_DTXFSTS7 (AT32_OTGFS1_BASE+AT32_OTGFS_DTXFSTS7_OFFSET) + +#define AT32_OTGFS_DOEP(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DOEP_OFFSET(n)) +#define AT32_OTGFS_DOEPCTL(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPCTL_OFFSET(n)) +#define AT32_OTGFS_DOEPCTL0 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPCTL0_OFFSET) +#define AT32_OTGFS_DOEPCTL1 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPCTL1_OFFSET) +#define AT32_OTGFS_DOEPCTL2 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPCTL2_OFFSET) +#define AT32_OTGFS_DOEPCTL3 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPCTL3_OFFSET) +#define AT32_OTGFS_DOEPCTL4 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPCTL4_OFFSET) +#define AT32_OTGFS_DOEPCTL5 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPCTL5_OFFSET) +#define AT32_OTGFS_DOEPCTL6 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPCTL6_OFFSET) +#define AT32_OTGFS_DOEPCTL7 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPCTL7_OFFSET) + +#define AT32_OTGFS_DOEPINT(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPINT_OFFSET(n)) +#define AT32_OTGFS_DOEPINT0 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPINT0_OFFSET) +#define AT32_OTGFS_DOEPINT1 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPINT1_OFFSET) +#define AT32_OTGFS_DOEPINT2 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPINT2_OFFSET) +#define AT32_OTGFS_DOEPINT3 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPINT3_OFFSET) +#define AT32_OTGFS_DOEPINT4 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPINT4_OFFSET) +#define AT32_OTGFS_DOEPINT5 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPINT5_OFFSET) +#define AT32_OTGFS_DOEPINT6 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPINT6_OFFSET) +#define AT32_OTGFS_DOEPINT7 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPINT7_OFFSET) + +#define AT32_OTGFS_DOEPTSIZ(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPTSIZ_OFFSET(n)) +#define AT32_OTGFS_DOEPTSIZ0 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPTSIZ0_OFFSET) +#define AT32_OTGFS_DOEPTSIZ1 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPTSIZ1_OFFSET) +#define AT32_OTGFS_DOEPTSIZ2 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPTSIZ2_OFFSET) +#define AT32_OTGFS_DOEPTSIZ3 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPTSIZ3_OFFSET) +#define AT32_OTGFS_DOEPTSIZ4 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPTSIZ4_OFFSET) +#define AT32_OTGFS_DOEPTSIZ5 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPTSIZ5_OFFSET) +#define AT32_OTGFS_DOEPTSIZ6 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPTSIZ6_OFFSET) +#define AT32_OTGFS_DOEPTSIZ7 (AT32_OTGFS1_BASE+AT32_OTGFS_DOEPTSIZ7_OFFSET) + +/* Power and clock gating registers */ + +#define AT32_OTGFS_PCGCCTL (AT32_OTGFS1_BASE+AT32_OTGFS_PCGCCTL_OFFSET) + +/* Data FIFO (DFIFO) access registers */ + +#define AT32_OTGFS_DFIFO_DEP(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_DEP_OFFSET(n)) +#define AT32_OTGFS_DFIFO_HCH(n) (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_HCH_OFFSET(n)) + +#define AT32_OTGFS_DFIFO_DEP0 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_DEP0_OFFSET) +#define AT32_OTGFS_DFIFO_HCH0 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_HCH0_OFFSET) + +#define AT32_OTGFS_DFIFO_DEP1 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_DEP1_OFFSET) +#define AT32_OTGFS_DFIFO_HCH1 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_HCH1_OFFSET) + +#define AT32_OTGFS_DFIFO_DEP2 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_DEP2_OFFSET) +#define AT32_OTGFS_DFIFO_HCH2 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_HCH2_OFFSET) + +#define AT32_OTGFS_DFIFO_DEP3 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_DEP3_OFFSET) +#define AT32_OTGFS_DFIFO_HCH3 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_HCH3_OFFSET) + +#define AT32_OTGFS_DFIFO_DEP4 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_DEP4_OFFSET) +#define AT32_OTGFS_DFIFO_HCH4 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_HCH4_OFFSET) + +#define AT32_OTGFS_DFIFO_DEP5 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_DEP5_OFFSET) +#define AT32_OTGFS_DFIFO_HCH5 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_HCH5_OFFSET) + +#define AT32_OTGFS_DFIFO_DEP6 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_DEP6_OFFSET) +#define AT32_OTGFS_DFIFO_HCH6 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_HCH6_OFFSET) + +#define AT32_OTGFS_DFIFO_DEP7 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_DEP7_OFFSET) +#define AT32_OTGFS_DFIFO_HCH7 (AT32_OTGFS1_BASE+AT32_OTGFS_DFIFO_HCH7_OFFSET) + +/* Register Bitfield Definitions ********************************************/ + +/* Core global control and status registers */ + +/* Control and status register */ + +#define OTGFS_GOTGCTL_CIDSTS (1 << 16) /* Bit 16: Connector ID status */ +#define OTGFS_GOTGCTL_CURMOD (1 << 21) /* Bit 21: Current Mode of Operation */ + +/* Interrupt register */ + +#define OTGFS_GOTGINT_SEDET (1 << 2) /* Bit 2: Session end detected */ + +/* AHB configuration register */ + +#define OTGFS_GAHBCFG_GINTMSK (1 << 0) /* Bit 0: Global interrupt mask */ + /* Bits 1-6: Reserved, must be kept at reset value */ +#define OTGFS_GAHBCFG_TXFELVL (1 << 7) /* Bit 7: TxFIFO empty level */ +#define OTGFS_GAHBCFG_PTXFELVL (1 << 8) /* Bit 8: Periodic TxFIFO empty level */ + /* Bits 20-31: Reserved, must be kept at reset value */ + +/* USB configuration register */ + +#define OTGFS_GUSBCFG_TOCAL_SHIFT (0) /* Bits 0-2: FS timeout calibration */ +#define OTGFS_GUSBCFG_TOCAL_MASK (7 << OTGFS_GUSBCFG_TOCAL_SHIFT) + +#define OTGFS_GUSBCFG_TRDT_SHIFT (10) /* Bits 10-13: USB turnaround time */ +#define OTGFS_GUSBCFG_TRDT_MASK (15 << OTGFS_GUSBCFG_TRDT_SHIFT) +# define OTGFS_GUSBCFG_TRDT(n) ((n) << OTGFS_GUSBCFG_TRDT_SHIFT) + +#define OTGFS_GUSBCFG_FHMOD (1 << 29) /* Bit 29: Force host mode */ +#define OTGFS_GUSBCFG_FDMOD (1 << 30) /* Bit 30: Force device mode */ +#define OTGFS_GUSBCFG_CTXPKT (1 << 31) /* Bit 31: Corrupt Tx packet */ + +/* Reset register */ + +#define OTGFS_GRSTCTL_CSRST (1 << 0) /* Bit 0: Core soft reset */ +#define OTGFS_GRSTCTL_HSRST (1 << 1) /* Bit 1: HCLK soft reset */ +#define OTGFS_GRSTCTL_FCRST (1 << 2) /* Bit 2: Host frame counter reset */ + /* Bit 3 Reserved, must be kept at reset value */ +#define OTGFS_GRSTCTL_RXFFLSH (1 << 4) /* Bit 4: RxFIFO flush */ +#define OTGFS_GRSTCTL_TXFFLSH (1 << 5) /* Bit 5: TxFIFO flush */ +#define OTGFS_GRSTCTL_TXFNUM_SHIFT (6) /* Bits 6-10: TxFIFO number */ +#define OTGFS_GRSTCTL_TXFNUM_MASK (31 << OTGFS_GRSTCTL_TXFNUM_SHIFT) +# define OTGFS_GRSTCTL_TXFNUM_HNONPER (0 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Non-periodic TxFIFO flush in host mode */ +# define OTGFS_GRSTCTL_TXFNUM_HPER (1 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Periodic TxFIFO flush in host mode */ +# define OTGFS_GRSTCTL_TXFNUM_HALL (16 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Flush all the transmit FIFOs in host mode.*/ +# define OTGFS_GRSTCTL_TXFNUM_D(n) ((n) << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* TXFIFO n flush in device mode, n=0-15 */ +# define OTGFS_GRSTCTL_TXFNUM_DALL (16 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Flush all the transmit FIFOs in device mode.*/ + +/* Bits 11-31: Reserved, + * must be kept at reset value + */ +#define OTGFS_GRSTCTL_AHBIDL (1 << 31) /* Bit 31: AHB master idle */ + +/* Core interrupt and Interrupt mask registers */ + +#define OTGFS_GINTSTS_CMOD (1 << 0) /* Bit 0: ro Current mode of operation */ +# define OTGFS_GINTSTS_DEVMODE (0) +# define OTGFS_GINTSTS_HOSTMODE (OTGFS_GINTSTS_CMOD) +#define OTGFS_GINT_MMIS (1 << 1) /* Bit 1: rc_w1 Mode mismatch interrupt */ +#define OTGFS_GINT_OTG (1 << 2) /* Bit 2: ro OTG interrupt */ +#define OTGFS_GINT_SOF (1 << 3) /* Bit 3: rc_w1 Start of frame */ +#define OTGFS_GINT_RXFLVL (1 << 4) /* Bit 4: ro RxFIFO non-empty */ +#define OTGFS_GINT_NPTXFE (1 << 5) /* Bit 5: ro Non-periodic TxFIFO empty */ +#define OTGFS_GINT_GINAKEFF (1 << 6) /* Bit 6: ro Global IN non-periodic NAK effective */ +#define OTGFS_GINT_GONAKEFF (1 << 7) /* Bit 7: Global OUT NAK effective */ +#define OTGFS_GINT_RES89 (3 << 8) /* Bits 8-9: Reserved, must be kept at reset value */ +#define OTGFS_GINT_ESUSP (1 << 10) /* Bit 10: rc_w1 Early suspend */ +#define OTGFS_GINT_USBSUSP (1 << 11) /* Bit 11: rc_w1 USB suspend */ +#define OTGFS_GINT_USBRST (1 << 12) /* Bit 12: rc_w1 USB reset */ +#define OTGFS_GINT_ENUMDNE (1 << 13) /* Bit 13: rc_w1 Enumeration done */ +#define OTGFS_GINT_ISOODRP (1 << 14) /* Bit 14: rc_w1 Isochronous OUT packet dropped interrupt */ +#define OTGFS_GINT_EOPF (1 << 15) /* Bit 15: rc_w1 End of periodic frame interrupt */ +#define OTGFS_GINT_RES16 (1 << 16) /* Bit 16 Reserved, must be kept at reset value */ +#define OTGFS_GINTMSK_EPMISM (1 << 17) /* Bit 17: Reserved in GINT rw Endpoint mismatch interrupt mask */ +#define OTGFS_GINT_IEP (1 << 18) /* Bit 18: ro IN endpoint interrupt */ +#define OTGFS_GINT_OEP (1 << 19) /* Bit 19: ro OUT endpoint interrupt */ +#define OTGFS_GINT_IISOIXFR (1 << 20) /* Bit 20: rc_w1 Incomplete isochronous IN transfer */ +#define OTGFS_GINT_IISOOXFR (1 << 21) /* Bit 21: rc_w1 Incomplete isochronous OUT transfer (device) */ +#define OTGFS_GINT_IPXFR (1 << 21) /* Bit 21: Incomplete periodic transfer (host) */ + +#define OTGFS_GINT_RES2223 (3 << 22) /* Bits 22-23: Reserved, must be kept at reset value */ + +#define OTGFS_GINT_HPRT (1 << 24) /* Bit 24: ro Host port interrupt */ +#define OTGFS_GINT_HC (1 << 25) /* Bit 25: ro Host channels interrupt */ +#define OTGFS_GINT_PTXFE (1 << 26) /* Bit 26: ro Periodic TxFIFO empty */ + +#define OTGFS_GINT_RES27 (1 << 27) /* Bit 27 Reserved, must be kept at reset value */ + +#define OTGFS_GINT_CIDSCHG (1 << 28) /* Bit 28: rc_w1 Connector ID status change */ +#define OTGFS_GINT_DISC (1 << 29) /* Bit 29: rc_w1 Disconnect detected interrupt */ + +#define OTGFS_GINT_SRQ (1 << 30) /* Bit 30: rc_w1 Session request/new session detected interrupt */ + +#define OTGFS_GINT_WKUP (1 << 31) /* Bit 31: rc_w1 Resume/remote wakeup detected interrupt */ + +/* Receive status debug read/OTG status read and pop registers + * (host mode) + */ + +#define OTGFS_GRXSTSH_CHNUM_SHIFT (0) /* Bits 0-3: Channel number */ +#define OTGFS_GRXSTSH_CHNUM_MASK (15 << OTGFS_GRXSTSH_CHNUM_SHIFT) +#define OTGFS_GRXSTSH_BCNT_SHIFT (4) /* Bits 4-14: Byte count */ +#define OTGFS_GRXSTSH_BCNT_MASK (0x7ff << OTGFS_GRXSTSH_BCNT_SHIFT) +#define OTGFS_GRXSTSH_DPID_SHIFT (15) /* Bits 15-16: Data PID */ +#define OTGFS_GRXSTSH_DPID_MASK (3 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_DATA0 (0 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_DATA2 (1 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_DATA1 (2 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_MDATA (3 << OTGFS_GRXSTSH_DPID_SHIFT) +#define OTGFS_GRXSTSH_PKTSTS_SHIFT (17) /* Bits 17-20: Packet status */ +#define OTGFS_GRXSTSH_PKTSTS_MASK (15 << OTGFS_GRXSTSH_PKTSTS_SHIFT) +# define OTGFS_GRXSTSH_PKTSTS_INRECVD (2 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* IN data packet received */ +# define OTGFS_GRXSTSH_PKTSTS_INDONE (3 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* IN transfer completed */ +# define OTGFS_GRXSTSH_PKTSTS_DTOGERR (5 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* Data toggle error */ +# define OTGFS_GRXSTSH_PKTSTS_HALTED (7 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* Channel halted */ + +/* Bits 21-31: Reserved, + * must be kept at reset value + */ + +/* Receive status debug read/OTG status read and pop registers + * (device mode) + */ + +#define OTGFS_GRXSTSD_EPNUM_SHIFT (0) /* Bits 0-3: Endpoint number */ +#define OTGFS_GRXSTSD_EPNUM_MASK (15 << OTGFS_GRXSTSD_EPNUM_SHIFT) +#define OTGFS_GRXSTSD_BCNT_SHIFT (4) /* Bits 4-14: Byte count */ +#define OTGFS_GRXSTSD_BCNT_MASK (0x7ff << OTGFS_GRXSTSD_BCNT_SHIFT) +#define OTGFS_GRXSTSD_DPID_SHIFT (15) /* Bits 15-16: Data PID */ +#define OTGFS_GRXSTSD_DPID_MASK (3 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_DATA0 (0 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_DATA2 (1 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_DATA1 (2 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_MDATA (3 << OTGFS_GRXSTSD_DPID_SHIFT) +#define OTGFS_GRXSTSD_PKTSTS_SHIFT (17) /* Bits 17-20: Packet status */ +#define OTGFS_GRXSTSD_PKTSTS_MASK (15 << OTGFS_GRXSTSD_PKTSTS_SHIFT) +# define OTGFS_GRXSTSD_PKTSTS_OUTNAK (1 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* Global OUT NAK */ +# define OTGFS_GRXSTSD_PKTSTS_OUTRECVD (2 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* OUT data packet received */ +# define OTGFS_GRXSTSD_PKTSTS_OUTDONE (3 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* OUT transfer completed */ +# define OTGFS_GRXSTSD_PKTSTS_SETUPDONE (4 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* SETUP transaction completed */ +# define OTGFS_GRXSTSD_PKTSTS_SETUPRECVD (6 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* SETUP data packet received */ + +#define OTGFS_GRXSTSD_FRMNUM_SHIFT (21) /* Bits 21-24: Frame number */ +#define OTGFS_GRXSTSD_FRMNUM_MASK (15 << OTGFS_GRXSTSD_FRMNUM_SHIFT) + /* Bits 25-31: Reserved, must be kept at reset value */ + +/* Receive FIFO size register */ + +#define OTGFS_GRXFSIZ_MASK (0xffff) + +/* Host non-periodic transmit FIFO size register */ + +#define OTGFS_HNPTXFSIZ_NPTXFSA_SHIFT (0) /* Bits 0-15: Non-periodic transmit RAM start address */ +#define OTGFS_HNPTXFSIZ_NPTXFSA_MASK (0xffff << OTGFS_HNPTXFSIZ_NPTXFSA_SHIFT) +#define OTGFS_HNPTXFSIZ_NPTXFD_SHIFT (16) /* Bits 16-31: Non-periodic TxFIFO depth */ +#define OTGFS_HNPTXFSIZ_NPTXFD_MASK (0xffff << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT) +# define OTGFS_HNPTXFSIZ_NPTXFD_MIN (16 << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT) +# define OTGFS_HNPTXFSIZ_NPTXFD_MAX (256 << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT) + +/* Endpoint 0 Transmit FIFO size */ + +#define OTGFS_DIEPTXF0_TX0FD_SHIFT (0) /* Bits 0-15: Endpoint 0 transmit RAM start address */ +#define OTGFS_DIEPTXF0_TX0FD_MASK (0xffff << OTGFS_DIEPTXF0_TX0FD_SHIFT) +#define OTGFS_DIEPTXF0_TX0FSA_SHIFT (16) /* Bits 16-31: Endpoint 0 TxFIFO depth */ +#define OTGFS_DIEPTXF0_TX0FSA_MASK (0xffff << OTGFS_DIEPTXF0_TX0FSA_SHIFT) +# define OTGFS_DIEPTXF0_TX0FSA_MIN (16 << OTGFS_DIEPTXF0_TX0FSA_SHIFT) +# define OTGFS_DIEPTXF0_TX0FSA_MAX (256 << OTGFS_DIEPTXF0_TX0FSA_SHIFT) + +/* Non-periodic transmit FIFO/queue status register */ + +#define OTGFS_HNPTXSTS_NPTXFSAV_SHIFT (0) /* Bits 0-15: Non-periodic TxFIFO space available */ +#define OTGFS_HNPTXSTS_NPTXFSAV_MASK (0xffff << OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) +# define OTGFS_HNPTXSTS_NPTXFSAV_FULL (0 << OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) +#define OTGFS_HNPTXSTS_NPTQXSAV_SHIFT (16) /* Bits 16-23: Non-periodic transmit request queue space available */ +#define OTGFS_HNPTXSTS_NPTQXSAV_MASK (0xff << OTGFS_HNPTXSTS_NPTQXSAV_SHIFT) +# define OTGFS_HNPTXSTS_NPTQXSAV_FULL (0 << OTGFS_HNPTXSTS_NPTQXSAV_SHIFT) +#define OTGFS_HNPTXSTS_NPTXQTOP_SHIFT (24) /* Bits 24-30: Top of the non-periodic transmit request queue */ +#define OTGFS_HNPTXSTS_NPTXQTOP_MASK (0x7f << OTGFS_HNPTXSTS_NPTXQTOP_SHIFT) +# define OTGFS_HNPTXSTS_TERMINATE (1 << 24) /* Bit 24: Terminate (last entry for selected channel/endpoint) */ +# define OTGFS_HNPTXSTS_TYPE_SHIFT (25) /* Bits 25-26: Status */ +# define OTGFS_HNPTXSTS_TYPE_MASK (3 << OTGFS_HNPTXSTS_TYPE_SHIFT) +# define OTGFS_HNPTXSTS_TYPE_INOUT (0 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* IN/OUT token */ +# define OTGFS_HNPTXSTS_TYPE_ZLP (1 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* Zero-length transmit packet (device IN/host OUT) */ +# define OTGFS_HNPTXSTS_TYPE_HALT (3 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* Channel halt command */ + +# define OTGFS_HNPTXSTS_CHNUM_SHIFT (27) /* Bits 27-30: Channel number */ +# define OTGFS_HNPTXSTS_CHNUM_MASK (15 << OTGFS_HNPTXSTS_CHNUM_SHIFT) +# define OTGFS_HNPTXSTS_EPNUM_SHIFT (27) /* Bits 27-30: Endpoint number */ +# define OTGFS_HNPTXSTS_EPNUM_MASK (15 << OTGFS_HNPTXSTS_EPNUM_SHIFT) + /* Bit 31 Reserved, must be kept at reset value */ + +/* General core configuration register */ + +/* Bits 0-15: Reserved, + * must be kept at reset value + */ +#define OTGFS_GCCFG_PWRDWN (1 << 16) /* Bit 16: Power down */ +#define OTGFS_GCCFG_LP_MODE (1 << 17) /* Bit 17: Low power mode */ + +#define OTGFS_GCCFG_VBUSASEN (1 << 18) /* Bit 18: Enable the VBUS sensing A device */ +#define OTGFS_GCCFG_VBUSBSEN (1 << 19) /* Bit 19: Enable the VBUS sensing B device */ + +#define OTGFS_GCCFG_SOFOUTEN (1 << 20) /* Bit 20: SOF output enable */ +#define OTGFS_GCCFG_NOVBUSSENS (1 << 21) /* Bit 21: VBUS sensing disable option */ + /* Bits 22-31: Reserved, must be kept at reset value */ + +/* Core ID register (32-bit product ID) */ + +/* Host periodic transmit FIFO size register */ + +#define OTGFS_HPTXFSIZ_PTXSA_SHIFT (0) /* Bits 0-15: Host periodic TxFIFO start address */ +#define OTGFS_HPTXFSIZ_PTXSA_MASK (0xffff << OTGFS_HPTXFSIZ_PTXSA_SHIFT) +#define OTGFS_HPTXFSIZ_PTXFD_SHIFT (16) /* Bits 16-31: Host periodic TxFIFO depth */ +#define OTGFS_HPTXFSIZ_PTXFD_MASK (0xffff << OTGFS_HPTXFSIZ_PTXFD_SHIFT) + +/* Device IN endpoint transmit FIFOn size register */ + +#define OTGFS_DIEPTXF_INEPTXSA_SHIFT (0) /* Bits 0-15: IN endpoint FIFOx transmit RAM start address */ +#define OTGFS_DIEPTXF_INEPTXSA_MASK (0xffff << OTGFS_DIEPTXF_INEPTXSA_SHIFT) +#define OTGFS_DIEPTXF_INEPTXFD_SHIFT (16) /* Bits 16-31: IN endpoint TxFIFO depth */ +#define OTGFS_DIEPTXF_INEPTXFD_MASK (0xffff << OTGFS_DIEPTXF_INEPTXFD_SHIFT) +# define OTGFS_DIEPTXF_INEPTXFD_MIN (16 << OTGFS_DIEPTXF_INEPTXFD_MASK) + +/* Host-mode control and status registers */ + +/* Host configuration register */ + +#define OTGFS_HCFG_FSLSPCS_SHIFT (0) /* Bits 0-1: FS/LS PHY clock select */ +#define OTGFS_HCFG_FSLSPCS_MASK (3 << OTGFS_HCFG_FSLSPCS_SHIFT) +# define OTGFS_HCFG_FSLSPCS_FS48MHz (1 << OTGFS_HCFG_FSLSPCS_SHIFT) /* FS host mode, PHY clock is running at 48 MHz */ +# define OTGFS_HCFG_FSLSPCS_LS48MHz (1 << OTGFS_HCFG_FSLSPCS_SHIFT) /* LS host mode, Select 48 MHz PHY clock frequency */ +# define OTGFS_HCFG_FSLSPCS_LS6MHz (2 << OTGFS_HCFG_FSLSPCS_SHIFT) /* LS host mode, Select 6 MHz PHY clock frequency */ + +#define OTGFS_HCFG_FSLSS (1 << 2) /* Bit 2: FS- and LS-only support */ + /* Bits 31:3 Reserved, must be kept at reset value */ + +/* Host frame interval register */ + +#define OTGFS_HFIR_MASK (0xffff) +#define OTGFS_HFIR_HFIRRLDCTRL (1 << 16) /* Reload Control */ + +/* Host frame number/frame time remaining register */ + +#define OTGFS_HFNUM_FRNUM_SHIFT (0) /* Bits 0-15: Frame number */ +#define OTGFS_HFNUM_FRNUM_MASK (0xffff << OTGFS_HFNUM_FRNUM_SHIFT) +#define OTGFS_HFNUM_FTREM_SHIFT (16) /* Bits 16-31: Frame time remaining */ +#define OTGFS_HFNUM_FTREM_MASK (0xffff << OTGFS_HFNUM_FTREM_SHIFT) + +/* Host periodic transmit FIFO/queue status register */ + +#define OTGFS_HPTXSTS_PTXFSAVL_SHIFT (0) /* Bits 0-15: Periodic transmit data FIFO space available */ +#define OTGFS_HPTXSTS_PTXFSAVL_MASK (0xffff << OTGFS_HPTXSTS_PTXFSAVL_SHIFT) +# define OTGFS_HPTXSTS_PTXFSAVL_FULL (0 << OTGFS_HPTXSTS_PTXFSAVL_SHIFT) +#define OTGFS_HPTXSTS_PTXQSAV_SHIFT (16) /* Bits 16-23: Periodic transmit request queue space available */ +#define OTGFS_HPTXSTS_PTXQSAV_MASK (0xff << OTGFS_HPTXSTS_PTXQSAV_SHIFT) +# define OTGFS_HPTXSTS_PTXQSAV_FULL (0 << OTGFS_HPTXSTS_PTXQSAV_SHIFT) +#define OTGFS_HPTXSTS_PTXQTOP_SHIFT (24) /* Bits 24-31: Top of the periodic transmit request queue */ +#define OTGFS_HPTXSTS_PTXQTOP_MASK (0x7f << OTGFS_HPTXSTS_PTXQTOP_SHIFT) +# define OTGFS_HPTXSTS_TERMINATE (1 << 24) /* Bit 24: Terminate (last entry for selected channel/endpoint) */ +# define OTGFS_HPTXSTS_TYPE_SHIFT (25) /* Bits 25-26: Type */ +# define OTGFS_HPTXSTS_TYPE_MASK (3 << OTGFS_HPTXSTS_TYPE_SHIFT) +# define OTGFS_HPTXSTS_TYPE_INOUT (0 << OTGFS_HPTXSTS_TYPE_SHIFT) /* IN/OUT token */ +# define OTGFS_HPTXSTS_TYPE_ZLP (1 << OTGFS_HPTXSTS_TYPE_SHIFT) /* Zero-length transmit packet */ +# define OTGFS_HPTXSTS_TYPE_HALT (3 << OTGFS_HPTXSTS_TYPE_SHIFT) /* Disable channel command */ + +# define OTGFS_HPTXSTS_EPNUM_SHIFT (27) /* Bits 27-30: Endpoint number */ +# define OTGFS_HPTXSTS_EPNUM_MASK (15 << OTGFS_HPTXSTS_EPNUM_SHIFT) +# define OTGFS_HPTXSTS_CHNUM_SHIFT (27) /* Bits 27-30: Channel number */ +# define OTGFS_HPTXSTS_CHNUM_MASK (15 << OTGFS_HPTXSTS_CHNUM_SHIFT) +# define OTGFS_HPTXSTS_ODD (1 << 24) /* Bit 31: Send in odd (vs even) frame */ + +/* Host all channels interrupt and all channels interrupt mask registers */ + +#define OTGFS_HAINT(n) (1 << (n)) /* Bits 15:0 HAINTM: Channel interrupt */ + +/* Host port control and status register */ + +#define OTGFS_HPRT_PCSTS (1 << 0) /* Bit 0: Port connect status */ +#define OTGFS_HPRT_PCDET (1 << 1) /* Bit 1: Port connect detected */ +#define OTGFS_HPRT_PENA (1 << 2) /* Bit 2: Port enable */ +#define OTGFS_HPRT_PENCHNG (1 << 3) /* Bit 3: Port enable/disable change */ +#define OTGFS_HPRT_POCA (1 << 4) /* Bit 4: Port overcurrent active */ +#define OTGFS_HPRT_POCCHNG (1 << 5) /* Bit 5: Port overcurrent change */ +#define OTGFS_HPRT_PRES (1 << 6) /* Bit 6: Port resume */ +#define OTGFS_HPRT_PSUSP (1 << 7) /* Bit 7: Port suspend */ +#define OTGFS_HPRT_PRST (1 << 8) /* Bit 8: Port reset */ + /* Bit 9: Reserved, must be kept at reset value */ +#define OTGFS_HPRT_PLSTS_SHIFT (10) /* Bits 10-11: Port line status */ +#define OTGFS_HPRT_PLSTS_MASK (3 << OTGFS_HPRT_PLSTS_SHIFT) +# define OTGFS_HPRT_PLSTS_DP (1 << 10) /* Bit 10: Logic level of OTG_FS_FS_DP */ +# define OTGFS_HPRT_PLSTS_DM (1 << 11) /* Bit 11: Logic level of OTG_FS_FS_DM */ +#define OTGFS_HPRT_PPWR (1 << 12) /* Bit 12: Port power */ +#define OTGFS_HPRT_PTCTL_SHIFT (13) /* Bits 13-16: Port test control */ +#define OTGFS_HPRT_PTCTL_MASK (15 << OTGFS_HPRT_PTCTL_SHIFT) +# define OTGFS_HPRT_PTCTL_DISABLED (0 << OTGFS_HPRT_PTCTL_SHIFT) /* Test mode disabled */ +# define OTGFS_HPRT_PTCTL_J (1 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_J mode */ +# define OTGFS_HPRT_PTCTL_L (2 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_K mode */ +# define OTGFS_HPRT_PTCTL_SE0_NAK (3 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_SE0_NAK mode */ +# define OTGFS_HPRT_PTCTL_PACKET (4 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_Packet mode */ +# define OTGFS_HPRT_PTCTL_FORCE (5 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_Force_Enable */ + +#define OTGFS_HPRT_PSPD_SHIFT (17) /* Bits 17-18: Port speed */ +#define OTGFS_HPRT_PSPD_MASK (3 << OTGFS_HPRT_PSPD_SHIFT) +# define OTGFS_HPRT_PSPD_FS (1 << OTGFS_HPRT_PSPD_SHIFT) /* Full speed */ +# define OTGFS_HPRT_PSPD_LS (2 << OTGFS_HPRT_PSPD_SHIFT) /* Low speed */ + +/* Bits 19-31: Reserved, + * must be kept at reset value + */ + +/* Host channel-n characteristics register */ + +#define OTGFS_HCCHAR_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */ +#define OTGFS_HCCHAR_MPSIZ_MASK (0x7ff << OTGFS_HCCHAR_MPSIZ_SHIFT) +#define OTGFS_HCCHAR_EPNUM_SHIFT (11) /* Bits 11-14: Endpoint number */ +#define OTGFS_HCCHAR_EPNUM_MASK (15 << OTGFS_HCCHAR_EPNUM_SHIFT) +#define OTGFS_HCCHAR_EPDIR (1 << 15) /* Bit 15: Endpoint direction */ +# define OTGFS_HCCHAR_EPDIR_OUT (0) +# define OTGFS_HCCHAR_EPDIR_IN OTGFS_HCCHAR_EPDIR + +/* Bit 16 Reserved, + * must be kept at reset value + */ +#define OTGFS_HCCHAR_LSDEV (1 << 17) /* Bit 17: Low-speed device */ +#define OTGFS_HCCHAR_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_HCCHAR_EPTYP_MASK (3 << OTGFS_HCCHAR_EPTYP_SHIFT) +# define OTGFS_HCCHAR_EPTYP_CTRL (0 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Control */ +# define OTGFS_HCCHAR_EPTYP_ISOC (1 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Isochronous */ +# define OTGFS_HCCHAR_EPTYP_BULK (2 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Bulk */ +# define OTGFS_HCCHAR_EPTYP_INTR (3 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Interrupt */ + +#define OTGFS_HCCHAR_MCNT_SHIFT (20) /* Bits 20-21: Multicount */ +#define OTGFS_HCCHAR_MCNT_MASK (3 << OTGFS_HCCHAR_MCNT_SHIFT) +#define OTGFS_HCCHAR_DAD_SHIFT (22) /* Bits 22-28: Device address */ +#define OTGFS_HCCHAR_DAD_MASK (0x7f << OTGFS_HCCHAR_DAD_SHIFT) +#define OTGFS_HCCHAR_ODDFRM (1 << 29) /* Bit 29: Odd frame */ +#define OTGFS_HCCHAR_CHDIS (1 << 30) /* Bit 30: Channel disable */ +#define OTGFS_HCCHAR_CHENA (1 << 31) /* Bit 31: Channel enable */ + +/* Host channel-n interrupt and Host channel-0 interrupt mask registers */ + +#define OTGFS_HCINT_XFRC (1 << 0) /* Bit 0: Transfer completed */ +#define OTGFS_HCINT_CHH (1 << 1) /* Bit 1: Channel halted */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_HCINT_STALL (1 << 3) /* Bit 3: STALL response received interrupt */ +#define OTGFS_HCINT_NAK (1 << 4) /* Bit 4: NAK response received interrupt */ +#define OTGFS_HCINT_ACK (1 << 5) /* Bit 5: ACK response received/transmitted interrupt */ +#define OTGFS_HCINT_NYET (1 << 6) /* Bit 6: Response received interrupt */ +#define OTGFS_HCINT_TXERR (1 << 7) /* Bit 7: Transaction error */ +#define OTGFS_HCINT_BBERR (1 << 8) /* Bit 8: Babble error */ +#define OTGFS_HCINT_FRMOR (1 << 9) /* Bit 9: Frame overrun */ +#define OTGFS_HCINT_DTERR (1 << 10) /* Bit 10: Data toggle error */ + +/* Bits 11-31 Reserved, + * must be kept at reset value + */ + +/* Host channel-n interrupt register */ + +#define OTGFS_HCTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */ +#define OTGFS_HCTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_HCTSIZ_XFRSIZ_SHIFT) +#define OTGFS_HCTSIZ_PKTCNT_SHIFT (19) /* Bits 19-28: Packet count */ +#define OTGFS_HCTSIZ_PKTCNT_MASK (0x3ff << OTGFS_HCTSIZ_PKTCNT_SHIFT) +#define OTGFS_HCTSIZ_DPID_SHIFT (29) /* Bits 29-30: Data PID */ +#define OTGFS_HCTSIZ_DPID_MASK (3 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_DATA0 (0 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_DATA2 (1 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_DATA1 (2 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_MDATA (3 << OTGFS_HCTSIZ_DPID_SHIFT) /* Non-control */ +# define OTGFS_HCTSIZ_PID_SETUP (3 << OTGFS_HCTSIZ_DPID_SHIFT) /* Control */ + +/* Bit 31 Reserved, + * must be kept at reset value + */ + +/* Device-mode control and status registers */ + +/* Device configuration register */ + +#define OTGFS_DCFG_DSPD_SHIFT (0) /* Bits 0-1: Device speed */ +#define OTGFS_DCFG_DSPD_MASK (3 << OTGFS_DCFG_DSPD_SHIFT) +# define OTGFS_DCFG_DSPD_FS (3 << OTGFS_DCFG_DSPD_SHIFT) /* Full speed */ + +#define OTGFS_DCFG_NZLSOHSK (1 << 2) /* Bit 2: Non-zero-length status OUT handshake */ + /* Bit 3: Reserved, must be kept at reset value */ +#define OTGFS_DCFG_DAD_SHIFT (4) /* Bits 4-10: Device address */ +#define OTGFS_DCFG_DAD_MASK (0x7f << OTGFS_DCFG_DAD_SHIFT) +#define OTGFS_DCFG_PFIVL_SHIFT (11) /* Bits 11-12: Periodic frame interval */ +#define OTGFS_DCFG_PFIVL_MASK (3 << OTGFS_DCFG_PFIVL_SHIFT) +# define OTGFS_DCFG_PFIVL_80PCT (0 << OTGFS_DCFG_PFIVL_SHIFT) /* 80% of the frame interval */ +# define OTGFS_DCFG_PFIVL_85PCT (1 << OTGFS_DCFG_PFIVL_SHIFT) /* 85% of the frame interval */ +# define OTGFS_DCFG_PFIVL_90PCT (2 << OTGFS_DCFG_PFIVL_SHIFT) /* 90% of the frame interval */ +# define OTGFS_DCFG_PFIVL_95PCT (3 << OTGFS_DCFG_PFIVL_SHIFT) /* 95% of the frame interval */ + +/* Bits 13-31 Reserved, + * must be kept at reset value + */ + +/* Device control register */ + +#define OTGFS_TESTMODE_DISABLED (0) /* Test mode disabled */ +#define OTGFS_TESTMODE_J (1) /* Test_J mode */ +#define OTGFS_TESTMODE_K (2) /* Test_K mode */ +#define OTGFS_TESTMODE_SE0_NAK (3) /* Test_SE0_NAK mode */ +#define OTGFS_TESTMODE_PACKET (4) /* Test_Packet mode */ +#define OTGFS_TESTMODE_FORCE (5) /* Test_Force_Enable */ + +#define OTGFS_DCTL_RWUSIG (1 << 0) /* Bit 0: Remote wakeup signaling */ +#define OTGFS_DCTL_SDIS (1 << 1) /* Bit 1: Soft disconnect */ +#define OTGFS_DCTL_GINSTS (1 << 2) /* Bit 2: Global IN NAK status */ +#define OTGFS_DCTL_GONSTS (1 << 3) /* Bit 3: Global OUT NAK status */ +#define OTGFS_DCTL_TCTL_SHIFT (4) /* Bits 4-6: Test control */ +#define OTGFS_DCTL_TCTL_MASK (7 << OTGFS_DCTL_TCTL_SHIFT) +# define OTGFS_DCTL_TCTL_DISABLED (0 << OTGFS_DCTL_TCTL_SHIFT) /* Test mode disabled */ +# define OTGFS_DCTL_TCTL_J (1 << OTGFS_DCTL_TCTL_SHIFT) /* Test_J mode */ +# define OTGFS_DCTL_TCTL_K (2 << OTGFS_DCTL_TCTL_SHIFT) /* Test_K mode */ +# define OTGFS_DCTL_TCTL_SE0_NAK (3 << OTGFS_DCTL_TCTL_SHIFT) /* Test_SE0_NAK mode */ +# define OTGFS_DCTL_TCTL_PACKET (4 << OTGFS_DCTL_TCTL_SHIFT) /* Test_Packet mode */ +# define OTGFS_DCTL_TCTL_FORCE (5 << OTGFS_DCTL_TCTL_SHIFT) /* Test_Force_Enable */ + +#define OTGFS_DCTL_SGINAK (1 << 7) /* Bit 7: Set global IN NAK */ +#define OTGFS_DCTL_CGINAK (1 << 8) /* Bit 8: Clear global IN NAK */ +#define OTGFS_DCTL_SGONAK (1 << 9) /* Bit 9: Set global OUT NAK */ +#define OTGFS_DCTL_CGONAK (1 << 10) /* Bit 10: Clear global OUT NAK */ +#define OTGFS_DCTL_POPRGDNE (1 << 11) /* Bit 11: Power-on programming done */ + /* Bits 12-31: Reserved, must be kept at reset value */ + +/* Device status register */ + +#define OTGFS_DSTS_SUSPSTS (1 << 0) /* Bit 0: Suspend status */ +#define OTGFS_DSTS_ENUMSPD_SHIFT (1) /* Bits 1-2: Enumerated speed */ +#define OTGFS_DSTS_ENUMSPD_MASK (3 << OTGFS_DSTS_ENUMSPD_SHIFT) +# define OTGFS_DSTS_ENUMSPD_FS (3 << OTGFS_DSTS_ENUMSPD_MASK) /* Full speed */ + +/* Bits 4-7: Reserved, + * must be kept at reset value + */ +#define OTGFS_DSTS_EERR (1 << 3) /* Bit 3: Erratic error */ +#define OTGFS_DSTS_SOFFN_SHIFT (8) /* Bits 8-21: Frame number of the received SOF */ +#define OTGFS_DSTS_SOFFN_MASK (0x3fff << OTGFS_DSTS_SOFFN_SHIFT) +#define OTGFS_DSTS_SOFFN0 (1 << 8) /* Bits 8: Frame number even/odd bit */ +#define OTGFS_DSTS_SOFFN_EVEN 0 +#define OTGFS_DSTS_SOFFN_ODD OTGFS_DSTS_SOFFN0 + /* Bits 22-31: Reserved, must be kept at reset value */ + +/* Device IN endpoint common interrupt mask register */ + +#define OTGFS_DIEPMSK_XFRCM (1 << 0) /* Bit 0: Transfer completed interrupt mask */ +#define OTGFS_DIEPMSK_EPDM (1 << 1) /* Bit 1: Endpoint disabled interrupt mask */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DIEPMSK_TOM (1 << 3) /* Bit 3: Timeout condition mask (Non-isochronous endpoints) */ +#define OTGFS_DIEPMSK_ITTXFEMSK (1 << 4) /* Bit 4: IN token received when TxFIFO empty mask */ +#define OTGFS_DIEPMSK_INEPNMM (1 << 5) /* Bit 5: IN token received with EP mismatch mask */ +#define OTGFS_DIEPMSK_INEPNEM (1 << 6) /* Bit 6: IN endpoint NAK effective mask */ +#define OTGFS_DIEPMSK_TXFIFOUDRMSK (1 << 8) /* Bit 8: FIFO underrun mask */ +#define OTGFS_DIEPMSK_BNAINMSK (1 << 9) /* Bit 9: BNA interrupt mask */ + /* Bits 10-31: Reserved, must be kept at reset value */ + +/* Device OUT endpoint common interrupt mask register */ + +#define OTGFS_DOEPMSK_XFRCM (1 << 0) /* Bit 0: Transfer completed interrupt mask */ +#define OTGFS_DOEPMSK_EPDM (1 << 1) /* Bit 1: Endpoint disabled interrupt mask */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DOEPMSK_STUPM (1 << 3) /* Bit 3: SETUP phase done mask */ +#define OTGFS_DOEPMSK_OTEPDM (1 << 4) /* Bit 4: OUT token received when endpoint disabled mask */ + /* Bits 5-31: Reserved, must be kept at reset value */ +#define OTGFS_DOEPMSK_B2BSETUPMSK (1 << 6) /* Bit6: Back-to-back SETUP packets received mask */ +#define OTGFS_DOEPMSK_OUTPERRMSK (1 << 8) /* Bit8: OUTPERRMSK */ +#define OTGFS_DOEPMSK_BNAOUTMSK (1 << 9) /* Bit9: BNA interrupt mask */ + +/* Device all endpoints interrupt and All endpoints interrupt mask + * registers + */ + +#define OTGFS_DAINT_IEP_SHIFT (0) /* Bits 0-7: IN endpoint interrupt bits */ +#define OTGFS_DAINT_IEP_MASK (0xff << OTGFS_DAINT_IEP_SHIFT) +# define OTGFS_DAINT_IEP(n) (1 << (n)) +#define OTGFS_DAINT_OEP_SHIFT (16) /* Bits 16-23: OUT endpoint interrupt bits */ +#define OTGFS_DAINT_OEP_MASK (0xff << OTGFS_DAINT_OEP_SHIFT) +# define OTGFS_DAINT_OEP(n) (1 << ((n)+16)) + +/* Device IN endpoint FIFO empty interrupt mask register */ + +#define OTGFS_DIEPEMPMSK(n) (1 << (n)) /* n: 0 ~ 7 */ + +/* Device control IN endpoint 0 control register */ + +#define OTGFS_DIEPCTL0_MPSIZ_SHIFT (0) /* Bits 0-1: Maximum packet size */ +#define OTGFS_DIEPCTL0_MPSIZ_MASK (3 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) +# define OTGFS_DIEPCTL0_MPSIZ_64 (0 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 64 bytes */ +# define OTGFS_DIEPCTL0_MPSIZ_32 (1 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 32 bytes */ +# define OTGFS_DIEPCTL0_MPSIZ_16 (2 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 16 bytes */ +# define OTGFS_DIEPCTL0_MPSIZ_8 (3 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 8 bytes */ + +/* Bits 2-14: Reserved, + * must be kept at reset value + */ +#define OTGFS_DIEPCTL0_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ + /* Bit 16: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL0_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DIEPCTL0_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DIEPCTL0_EPTYP_MASK (3 << OTGFS_DIEPCTL0_EPTYP_SHIFT) +# define OTGFS_DIEPCTL0_EPTYP_CTRL (0 << OTGFS_DIEPCTL0_EPTYP_SHIFT) /* Control (hard-coded) */ + +/* Bit 20: Reserved, + * must be kept at reset value + */ +#define OTGFS_DIEPCTL0_STALL (1 << 21) /* Bit 21: STALL handshake */ +#define OTGFS_DIEPCTL0_TXFNUM_SHIFT (22) /* Bits 22-25: TxFIFO number */ +#define OTGFS_DIEPCTL0_TXFNUM_MASK (15 << OTGFS_DIEPCTL0_TXFNUM_SHIFT) +#define OTGFS_DIEPCTL0_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DIEPCTL0_SNAK (1 << 27) /* Bit 27: Set NAK */ + /* Bits 28-29: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL0_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DIEPCTL0_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device control IN endpoint n control register */ + +#define OTGFS_DIEPCTL_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */ +#define OTGFS_DIEPCTL_MPSIZ_MASK (0x7ff << OTGFS_DIEPCTL_MPSIZ_SHIFT) + /* Bits 11-14: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ +#define OTGFS_DIEPCTL_EONUM (1 << 16) /* Bit 16: Even/odd frame */ +# define OTGFS_DIEPCTL_EVEN (0) +# define OTGFS_DIEPCTL_ODD OTGFS_DIEPCTL_EONUM +# define OTGFS_DIEPCTL_DATA0 (0) +# define OTGFS_DIEPCTL_DATA1 OTGFS_DIEPCTL_EONUM +#define OTGFS_DIEPCTL_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DIEPCTL_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DIEPCTL_EPTYP_MASK (3 << OTGFS_DIEPCTL_EPTYP_SHIFT) +# define OTGFS_DIEPCTL_EPTYP_CTRL (0 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Control */ +# define OTGFS_DIEPCTL_EPTYP_ISOC (1 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Isochronous */ +# define OTGFS_DIEPCTL_EPTYP_BULK (2 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Bulk */ +# define OTGFS_DIEPCTL_EPTYP_INTR (3 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Interrupt */ + +/* Bit 20: Reserved, + * must be kept at reset value + */ +#define OTGFS_DIEPCTL_STALL (1 << 21) /* Bit 21: STALL handshake */ +#define OTGFS_DIEPCTL_TXFNUM_SHIFT (22) /* Bits 22-25: TxFIFO number */ +#define OTGFS_DIEPCTL_TXFNUM_MASK (15 << OTGFS_DIEPCTL_TXFNUM_SHIFT) +#define OTGFS_DIEPCTL_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DIEPCTL_SNAK (1 << 27) /* Bit 27: Set NAK */ +#define OTGFS_DIEPCTL_SD0PID (1 << 28) /* Bit 28: Set DATA0 PID (interrupt/bulk) */ +#define OTGFS_DIEPCTL_SEVNFRM (1 << 28) /* Bit 28: Set even frame (isochronous)) */ +#define OTGFS_DIEPCTL_SODDFRM (1 << 29) /* Bit 29: Set odd frame (isochronous) */ +#define OTGFS_DIEPCTL_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DIEPCTL_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device endpoint-n interrupt register */ + +#define OTGFS_DIEPINT_XFRC (1 << 0) /* Bit 0: Transfer completed interrupt */ +#define OTGFS_DIEPINT_EPDISD (1 << 1) /* Bit 1: Endpoint disabled interrupt */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DIEPINT_TOC (1 << 3) /* Bit 3: Timeout condition */ +#define OTGFS_DIEPINT_ITTXFE (1 << 4) /* Bit 4: IN token received when TxFIFO is empty */ + /* Bit 5: Reserved, must be kept at reset value */ +#define OTGFS_DIEPINT_INEPNE (1 << 6) /* Bit 6: IN endpoint NAK effective */ +#define OTGFS_DIEPINT_TXFE (1 << 7) /* Bit 7: Transmit FIFO empty */ + /* Bits 8-31: Reserved, must be kept at reset value */ + +/* Device IN endpoint 0 transfer size register */ + +#define OTGFS_DIEPTSIZ0_XFRSIZ_SHIFT (0) /* Bits 0-6: Transfer size */ +#define OTGFS_DIEPTSIZ0_XFRSIZ_MASK (0x7f << OTGFS_DIEPTSIZ0_XFRSIZ_SHIFT) + /* Bits 7-18: Reserved, must be kept at reset value */ +#define OTGFS_DIEPTSIZ0_PKTCNT_SHIFT (19) /* Bits 19-20: Packet count */ +#define OTGFS_DIEPTSIZ0_PKTCNT_MASK (3 << OTGFS_DIEPTSIZ0_PKTCNT_SHIFT) + /* Bits 21-31: Reserved, must be kept at reset value */ + +/* Device IN endpoint n transfer size register */ + +#define OTGFS_DIEPTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */ +#define OTGFS_DIEPTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_DIEPTSIZ_XFRSIZ_SHIFT) +#define OTGFS_DIEPTSIZ_PKTCNT_SHIFT (19) /* Bit 19-28: Packet count */ +#define OTGFS_DIEPTSIZ_PKTCNT_MASK (0x3ff << OTGFS_DIEPTSIZ_PKTCNT_SHIFT) +#define OTGFS_DIEPTSIZ_MCNT_SHIFT (29) /* Bits 29-30: Multi count */ +#define OTGFS_DIEPTSIZ_MCNT_MASK (3 << OTGFS_DIEPTSIZ_MCNT_SHIFT) + /* Bit 31: Reserved, must be kept at reset value */ + +/* Device OUT endpoint TxFIFO status register */ + +#define OTGFS_DTXFSTS_MASK (0xffff) + +/* Device OUT endpoint 0 control register */ + +#define OTGFS_DOEPCTL0_MPSIZ_SHIFT (0) /* Bits 0-1: Maximum packet size */ +#define OTGFS_DOEPCTL0_MPSIZ_MASK (3 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) +# define OTGFS_DOEPCTL0_MPSIZ_64 (0 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 64 bytes */ +# define OTGFS_DOEPCTL0_MPSIZ_32 (1 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 32 bytes */ +# define OTGFS_DOEPCTL0_MPSIZ_16 (2 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 16 bytes */ +# define OTGFS_DOEPCTL0_MPSIZ_8 (3 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 8 bytes */ + +/* Bits 2-14: Reserved, + * must be kept at reset value + */ +#define OTGFS_DOEPCTL0_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ + /* Bit 16: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL0_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DOEPCTL0_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DOEPCTL0_EPTYP_MASK (3 << OTGFS_DOEPCTL0_EPTYP_SHIFT) +# define OTGFS_DOEPCTL0_EPTYP_CTRL (0 << OTGFS_DOEPCTL0_EPTYP_SHIFT) /* Control (hard-coded) */ + +#define OTGFS_DOEPCTL0_SNPM (1 << 20) /* Bit 20: Snoop mode */ +#define OTGFS_DOEPCTL0_STALL (1 << 21) /* Bit 21: STALL handshake */ + /* Bits 22-25: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL0_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DOEPCTL0_SNAK (1 << 27) /* Bit 27: Set NAK */ + /* Bits 28-29: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL0_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DOEPCTL0_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device OUT endpoint n control register */ + +#define OTGFS_DOEPCTL_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */ +#define OTGFS_DOEPCTL_MPSIZ_MASK (0x7ff << OTGFS_DOEPCTL_MPSIZ_SHIFT) + /* Bits 11-14: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ +#define OTGFS_DOEPCTL_DPID (1 << 16) /* Bit 16: Endpoint data PID (interrupt/bulk) */ +# define OTGFS_DOEPCTL_DATA0 (0) +# define OTGFS_DOEPCTL_DATA1 OTGFS_DOEPCTL_DPID +#define OTGFS_DOEPCTL_EONUM (1 << 16) /* Bit 16: Even/odd frame (isochronous) */ +# define OTGFS_DOEPCTL_EVEN (0) +# define OTGFS_DOEPCTL_ODD OTGFS_DOEPCTL_EONUM +#define OTGFS_DOEPCTL_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DOEPCTL_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DOEPCTL_EPTYP_MASK (3 << OTGFS_DOEPCTL_EPTYP_SHIFT) +# define OTGFS_DOEPCTL_EPTYP_CTRL (0 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Control */ +# define OTGFS_DOEPCTL_EPTYP_ISOC (1 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Isochronous */ +# define OTGFS_DOEPCTL_EPTYP_BULK (2 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Bulk */ +# define OTGFS_DOEPCTL_EPTYP_INTR (3 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Interrupt */ + +#define OTGFS_DOEPCTL_SNPM (1 << 20) /* Bit 20: Snoop mode */ +#define OTGFS_DOEPCTL_STALL (1 << 21) /* Bit 21: STALL handshake */ + /* Bits 22-25: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DOEPCTL_SNAK (1 << 27) /* Bit 27: Set NAK */ +#define OTGFS_DOEPCTL_SD0PID (1 << 28) /* Bit 28: Set DATA0 PID (interrupt/bulk) */ +#define OTGFS_DOEPCTL_SEVNFRM (1 << 28) /* Bit 28: Set even frame (isochronous) */ +#define OTGFS_DOEPCTL_SD1PID (1 << 29) /* Bit 29: Set DATA1 PID (interrupt/bulk) */ +#define OTGFS_DOEPCTL_SODDFRM (1 << 29) /* Bit 29: Set odd frame (isochronous */ +#define OTGFS_DOEPCTL_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DOEPCTL_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device endpoint-n interrupt register */ + +#define OTGFS_DOEPINT_XFRC (1 << 0) /* Bit 0: Transfer completed interrupt */ +#define OTGFS_DOEPINT_EPDISD (1 << 1) /* Bit 1: Endpoint disabled interrupt */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DOEPINT_SETUP (1 << 3) /* Bit 3: SETUP phase done */ +#define OTGFS_DOEPINT_OTEPDIS (1 << 4) /* Bit 4: OUT token received when endpoint disabled */ + /* Bit 5: Reserved, must be kept at reset value */ +#define OTGFS_DOEPINT_B2BSTUP (1 << 6) /* Bit 6: Back-to-back SETUP packets received */ + /* Bits 7-31: Reserved, must be kept at reset value */ + +/* Device OUT endpoint-0 transfer size register */ + +#define OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT (0) /* Bits 0-6: Transfer size */ +#define OTGFS_DOEPTSIZ0_XFRSIZ_MASK (0x7f << OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT) + /* Bits 7-18: Reserved, must be kept at reset value */ +#define OTGFS_DOEPTSIZ0_PKTCNT (1 << 19) /* Bit 19 PKTCNT: Packet count */ + /* Bits 20-28: Reserved, must be kept at reset value */ +#define OTGFS_DOEPTSIZ0_STUPCNT_SHIFT (29) /* Bits 29-30: SETUP packet count */ +#define OTGFS_DOEPTSIZ0_STUPCNT_MASK (3 << OTGFS_DOEPTSIZ0_STUPCNT_SHIFT) + /* Bit 31: Reserved, must be kept at reset value */ + +/* Device OUT endpoint-n transfer size register */ + +#define OTGFS_DOEPTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */ +#define OTGFS_DOEPTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_DOEPTSIZ_XFRSIZ_SHIFT) +#define OTGFS_DOEPTSIZ_PKTCNT_SHIFT (19) /* Bit 19-28: Packet count */ +#define OTGFS_DOEPTSIZ_PKTCNT_MASK (0x3ff << OTGFS_DOEPTSIZ_PKTCNT_SHIFT) +#define OTGFS_DOEPTSIZ_STUPCNT_SHIFT (29) /* Bits 29-30: SETUP packet count */ +#define OTGFS_DOEPTSIZ_STUPCNT_MASK (3 << OTGFS_DOEPTSIZ_STUPCNT_SHIFT) +#define OTGFS_DOEPTSIZ_RXDPID_SHIFT (29) /* Bits 29-30: Received data PID */ +#define OTGFS_DOEPTSIZ_RXDPID_MASK (3 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_DATA0 (0 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_DATA2 (1 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_DATA1 (2 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_MDATA (3 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) + /* Bit 31: Reserved, must be kept at reset value */ + +/* Power and clock gating control register */ + +#define OTGFS_PCGCCTL_STPPCLK (1 << 0) /* Bit 0: Stop PHY clock */ + +#define OTGFS_PCGCCTL_PHYSUSP (1 << 4) /* Bit 4: PHY Suspended */ + /* Bits 5-31: Reserved, must be kept at reset value */ + +#endif /* __ARCH_ARM_SRC_AT32_HARDWARE_AT32FXXXXX_OTGFS_H */ diff --git a/boards/Kconfig b/boards/Kconfig index 6329c25fe7..fd92f454ec 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -2890,6 +2890,13 @@ config ARCH_BOARD_SIM This port does not support interrupts or a real timer (and hence no round robin scheduler) Otherwise, it is complete. +config ARCH_BOARD_AT32F437_MINI + bool "AT32F437-MINI board" + depends on ARCH_CHIP_AT32F437VM + select ARCH_HAVE_LEDS + ---help--- + AT32F437-MINI board based on the Artery AT32F437VMT7 MCU. + config ARCH_BOARD_CUSTOM bool "Custom development board" ---help--- @@ -3256,6 +3263,7 @@ config ARCH_BOARD default "xx3823" if ARCH_BOARD_XX3823 default "s698pm-dkit" if ARCH_BOARD_S698PM_DKIT default "hpm6750evk2" if ARCH_BOARD_HPM6750EVK2 + default "at32f437-mini" if ARCH_BOARD_AT32F437_MINI comment "Common Board Options" @@ -4164,6 +4172,9 @@ endif if ARCH_BOARD_HPM6750EVK2 source "boards/risc-v/hpm6750/hpm6750evk2/Kconfig" endif +if ARCH_BOARD_AT32F437_MINI +source "boards/arm/at32/at32f437-mini/Kconfig" +endif comment "Board-Common Options" diff --git a/boards/arm/at32/at32f437-mini/Kconfig b/boards/arm/at32/at32f437-mini/Kconfig new file mode 100644 index 0000000000..a79f6ddad7 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/Kconfig @@ -0,0 +1,13 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if ARCH_BOARD_AT32F437_MINI + +config HAVE_LEDS + bool "Have user leds" + default y + select ARCH_HAVE_LEDS + +endif diff --git a/boards/arm/at32/at32f437-mini/README.txt b/boards/arm/at32/at32f437-mini/README.txt new file mode 100644 index 0000000000..fab21ceb47 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/README.txt @@ -0,0 +1,94 @@ +README +====== + +This README discusses issues unique to NuttX configurations for the +AT32F437-MINI development board featuring the AT32F437VMT7 +MCU. The AT32F437VMT7 is a 288MHz Cortex-M4 operation with 4Mbyte Flash +memory and 384kbytes. + + +LEDs +==== + LED1 = PE2 + LED2 = PE3 + +USART/UART +==== + USART1 + RX = PA10 + TX = PA9 + The usart1 is used for console. + ./tools/configure.sh at32f437-mini/nsh + make -j16 and flash nuttx.hex,then run it will show: + NuttShell (NSH) NuttX-12.2.1 + nsh> + nsh> + nsh> ps + PID GROUP PRI POLICY TYPE NPX STATE EVENT SIGMASK STACK COMMAND + 0 0 0 FIFO Kthread N-- Ready 0000000000000000 001016 Idle_Task + 2 2 100 RR Task --- Running 0000000000000000 002016 nsh_main + nsh> + + USART2/RS485 + RX = PD6 + TX = PD5 + DIR = PD4 + +CAN +==== + CAN1 + TX = PD1 + RX = PD0 + CAN_CHARDRIVER: ./tools/configure.sh at32f437-mini/can_char + CAN_SOCKET: ./tools/configure.sh at32f437-mini/can_socket + +USB +==== + OTGFS1 + D+ = PA12 + D- = PA11 + +SDIO +==== + SDIO1 + CMD = PD2 + CLK = PC12 + D0 = PC8 + D1 = PC9 + D2 = PC10 + D3 = PC11 + +ETH + RMII_REF_CLK = PA1 + ETH_MDIO = PA2 + RMII_CRS_DV = PA7 + ETH_MDC = PC1 + RMII_RXD0 = PC4 + RMII_RXD1 = PC5 + RMII_TX_EN = PB11 + RMII_TXD0 = PB12 + RMII_TXD1 = PB13 + ETH_RST = PA3 + The eth used lan8720a as phy + + +W25QXX + CLK = PB3 + MISO = PB4 + MOSI = PB5 + CS = PD7 + +RTC +The board used rtc device on chip + +PWM +The pwm test with tim20 chanel1 in PE2 + +ADC + ADC1 chanel8(PB0) + + + + + + diff --git a/boards/arm/at32/at32f437-mini/configs/adc/defconfig b/boards/arm/at32/at32f437-mini/configs/adc/defconfig new file mode 100644 index 0000000000..647ca41fc9 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/adc/defconfig @@ -0,0 +1,52 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ADC=y +CONFIG_ANALOG=y +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_ADC1=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_PWR=y +CONFIG_AT32_USART1=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_EXAMPLES_ADC=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USART1_TXBUFSIZE=128 diff --git a/boards/arm/at32/at32f437-mini/configs/can_char/defconfig b/boards/arm/at32/at32f437-mini/configs/can_char/defconfig new file mode 100644 index 0000000000..84abdaa383 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/can_char/defconfig @@ -0,0 +1,50 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_CAN1=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_PWR=y +CONFIG_AT32_USART1=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_EXAMPLES_CAN=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USART1_TXBUFSIZE=128 diff --git a/boards/arm/at32/at32f437-mini/configs/can_socket/defconfig b/boards/arm/at32/at32f437-mini/configs/can_socket/defconfig new file mode 100644 index 0000000000..0a68f9adbd --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/can_socket/defconfig @@ -0,0 +1,62 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NET_IPv4 is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ALLOW_GPL_COMPONENTS=y +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_CAN1=y +CONFIG_AT32_CAN_SOCKET=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_PWR=y +CONFIG_AT32_USART1=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_CAN=y +CONFIG_CANUTILS_CANDUMP=y +CONFIG_CANUTILS_CANLIB=y +CONFIG_CANUTILS_CANSEND=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NET=y +CONFIG_NETDEV_CAN_BITRATE_IOCTL=y +CONFIG_NETDEV_IFINDEX=y +CONFIG_NET_CAN=y +CONFIG_NET_CAN_SOCK_OPTS=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USART1_TXBUFSIZE=128 diff --git a/boards/arm/at32/at32f437-mini/configs/eth/defconfig b/boards/arm/at32/at32f437-mini/configs/eth/defconfig new file mode 100644 index 0000000000..1785ed89be --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/eth/defconfig @@ -0,0 +1,70 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_ETHMAC=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_PHYADDR=0 +CONFIG_AT32_PHYSR=31 +CONFIG_AT32_PHYSR_100FD=0x0018 +CONFIG_AT32_PHYSR_100HD=0x0008 +CONFIG_AT32_PHYSR_10FD=0x0014 +CONFIG_AT32_PHYSR_10HD=0x0004 +CONFIG_AT32_PHYSR_ALTCONFIG=y +CONFIG_AT32_PHYSR_ALTMODE=0x001c +CONFIG_AT32_PWR=y +CONFIG_AT32_RMII_EXTCLK=y +CONFIG_AT32_USART1=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_ETH0_PHY_LAN8720=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_IOB_NBUFFERS=32 +CONFIG_IOB_THROTTLE=8 +CONFIG_NET=y +CONFIG_NETDEV_IFINDEX=y +CONFIG_NETINIT_DRIPADDR=0xc0a80101 +CONFIG_NETINIT_IPADDR=0xc0a80164 +CONFIG_NET_ICMP=y +CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_TCP=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_PING=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USART1_TXBUFSIZE=128 diff --git a/boards/arm/at32/at32f437-mini/configs/msc/defconfig b/boards/arm/at32/at32f437-mini/configs/msc/defconfig new file mode 100644 index 0000000000..66448ed735 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/msc/defconfig @@ -0,0 +1,57 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_AT32_OTGFS_VBUS_CONTROL is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_OTGFS=y +CONFIG_AT32_PWR=y +CONFIG_AT32_USART1=y +CONFIG_AT32_USBHOST=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FAT_LFN=y +CONFIG_FS_FAT=y +CONFIG_FS_LARGEFILE=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_OTG_ID_GPIO_DISABLE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USART1_TXBUFSIZE=128 +CONFIG_USBHOST_MSC=y diff --git a/boards/arm/at32/at32f437-mini/configs/nsh/defconfig b/boards/arm/at32/at32f437-mini/configs/nsh/defconfig new file mode 100644 index 0000000000..61bcccbc3b --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/nsh/defconfig @@ -0,0 +1,48 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_PWR=y +CONFIG_AT32_USART1=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USART1_TXBUFSIZE=128 diff --git a/boards/arm/at32/at32f437-mini/configs/pwm/defconfig b/boards/arm/at32/at32f437-mini/configs/pwm/defconfig new file mode 100644 index 0000000000..73e18c971b --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/pwm/defconfig @@ -0,0 +1,53 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_PWR=y +CONFIG_AT32_TIM20=y +CONFIG_AT32_TIM20_CH1OUT=y +CONFIG_AT32_TIM20_PWM=y +CONFIG_AT32_USART1=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_EXAMPLES_PWM=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_PWM=y +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USART1_TXBUFSIZE=128 diff --git a/boards/arm/at32/at32f437-mini/configs/rtc/defconfig b/boards/arm/at32/at32f437-mini/configs/rtc/defconfig new file mode 100644 index 0000000000..9350eb044f --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/rtc/defconfig @@ -0,0 +1,51 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_PWR=y +CONFIG_AT32_RTC=y +CONFIG_AT32_RTC_LSICLOCK=y +CONFIG_AT32_USART1=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_RTC_DATETIME=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USART1_TXBUFSIZE=128 diff --git a/boards/arm/at32/at32f437-mini/configs/sdcard/defconfig b/boards/arm/at32/at32f437-mini/configs/sdcard/defconfig new file mode 100644 index 0000000000..6198df143c --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/sdcard/defconfig @@ -0,0 +1,59 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_DMA1=y +CONFIG_AT32_DMA2=y +CONFIG_AT32_DMAMUX1=y +CONFIG_AT32_DMAMUX2=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_PWR=y +CONFIG_AT32_SDIO=y +CONFIG_AT32_USART1=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FAT_LFN=y +CONFIG_FS_FAT=y +CONFIG_FS_LARGEFILE=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_MMCSD=y +CONFIG_MMCSD_SDIO=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USART1_TXBUFSIZE=128 diff --git a/boards/arm/at32/at32f437-mini/configs/systemview/defconfig b/boards/arm/at32/at32f437-mini/configs/systemview/defconfig new file mode 100644 index 0000000000..c5840042f4 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/systemview/defconfig @@ -0,0 +1,57 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_PWR=y +CONFIG_AT32_USART1=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_DRIVERS_NOTE=y +CONFIG_DRIVERS_NOTE_MAX=2 +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_INSTRUMENTATION=y +CONFIG_SCHED_INSTRUMENTATION_FILTER=y +CONFIG_SCHED_INSTRUMENTATION_IRQHANDLER=y +CONFIG_SCHED_INSTRUMENTATION_SWITCH=y +CONFIG_SCHED_INSTRUMENTATION_SYSCALL=y +CONFIG_SCHED_IRQMONITOR=y +CONFIG_SCHED_WAITPID=y +CONFIG_SEGGER_SYSVIEW=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USART1_TXBUFSIZE=128 diff --git a/boards/arm/at32/at32f437-mini/configs/usbnsh/defconfig b/boards/arm/at32/at32f437-mini/configs/usbnsh/defconfig new file mode 100644 index 0000000000..c93244b885 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/usbnsh/defconfig @@ -0,0 +1,53 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_OTGFS=y +CONFIG_AT32_PWR=y +CONFIG_AT32_USART1=y +CONFIG_BOARDCTL_USBDEVCTRL=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_CDCACM=y +CONFIG_CDCACM_CONSOLE=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_OTG_ID_GPIO_DISABLE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_TXBUFSIZE=128 +CONFIG_USBDEV=y diff --git a/boards/arm/at32/at32f437-mini/configs/usbserial/defconfig b/boards/arm/at32/at32f437-mini/configs/usbserial/defconfig new file mode 100644 index 0000000000..b0751b0a9c --- /dev/null +++ b/boards/arm/at32/at32f437-mini/configs/usbserial/defconfig @@ -0,0 +1,53 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="at32f437-mini" +CONFIG_ARCH_BOARD_AT32F437_MINI=y +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_CHIP="at32" +CONFIG_ARCH_CHIP_AT32=y +CONFIG_ARCH_CHIP_AT32F437VM=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AT32_JTAG_SW_ENABLE=y +CONFIG_AT32_OTGFS=y +CONFIG_AT32_PWR=y +CONFIG_AT32_USART1=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=26145 +CONFIG_BUILTIN=y +CONFIG_CDCACM=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_EXAMPLES_USBSERIAL=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_OTG_ID_GPIO_DISABLE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=385024 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_USART1_RXBUFSIZE=128 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USART1_TXBUFSIZE=128 +CONFIG_USBDEV=y diff --git a/boards/arm/at32/at32f437-mini/include/board.h b/boards/arm/at32/at32f437-mini/include/board.h new file mode 100644 index 0000000000..8d5a724b5c --- /dev/null +++ b/boards/arm/at32/at32f437-mini/include/board.h @@ -0,0 +1,271 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/include/board.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_AT32_AT32F437_MINI_INCLUDE_BOARD_H +#define __BOARDS_ARM_AT32_AT32F437_MINI_INCLUDE_BOARD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +# include +#endif + +/* Do not include at32-specific header files here */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Clocking *****************************************************************/ + +/* The AT32F437-MINI board features a single 8MHz crystal. + * Space is provided for a 32kHz RTC backup crystal, but it is not stuffed. + * + * This is the canonical configuration: + * System Clock source : PLL (HSE) + * SYSCLK(Hz) : 288000000 Determined by PLL + * configuration + * HCLK(Hz) : 288000000 (AT32_RCC_CFGR_HPRE) + * AHB Prescaler : 1 (AT32_RCC_CFGR_HPRE) + * APB1 Prescaler : 2 (AT32_RCC_CFGR_PPRE1) + * APB2 Prescaler : 2 (AT32_RCC_CFGR_PPRE2) + * HSE Frequency(Hz) : 8000000 (AT32_BOARD_XTAL) + * PLLM : 1 (AT32_PLLCFG_PLLMS) + * PLLN : 144 (AT32_PLLCFG_PLLNS) + * PLLP : 4 (AT32_PLLCFG_PLLFR) + * Main regulator output voltage : Scale1 mode Needed for high speed + * SYSCLK + * Prefetch Buffer : OFF + * Instruction cache : ON + * Data cache : ON + * Require 48MHz for USB OTG FS, : Enabled + * SDIO clock + */ + +/* HSI - 48 MHz RC factory-trimmed + * LSI - 40 KHz RC + * HSE - On-board crystal frequency is 8MHz + * LSE - 32.768 kHz + */ + +#define AT32_BOARD_XTAL 8000000ul +#define AT32_HSI_FREQUENCY 48000000ul +#define AT32_LSI_FREQUENCY 40000 +#define AT32_HSE_FREQUENCY AT32_BOARD_XTAL +#define AT32_LSE_FREQUENCY 32768 + +/* Main PLL Configuration. + * + * PLL source is HSE + * + * FREQUENCY = HSE * AT32_PLLCFG_PLLN / (AT32_PLLCFG_PLLM * AT32_PLLCFG_PLLP) + * + */ + +#define AT32_PLLCFG_PLLM CRM_PLL_CFG_PLL_MS(1) +#define AT32_PLLCFG_PLLN CRM_PLL_CFG_PLL_NS(144) +#define AT32_PLLCFG_PLLP CRM_PLL_CFG_PLL_FR_4 + +#define AT32_SYSCLK_FREQUENCY 288000000ul + +/* AHB clock (HCLK) is SYSCLK (288MHz) */ + +#define AT32_HCLK_FREQUENCY AT32_SYSCLK_FREQUENCY /* HCLK = SYSCLK / 1 */ + +/* APB1 clock (PCLK1) is HCLK/2 (144MHz) */ + +#define AT32_PCLK1_FREQUENCY (AT32_HCLK_FREQUENCY/2) /* PCLK1 = HCLK / 2 */ + +/* Timers driven from APB1 will be twice PCLK1 */ + +#define AT32_APB1_TIM2_CLKIN (2*AT32_PCLK1_FREQUENCY) +#define AT32_APB1_TIM3_CLKIN (2*AT32_PCLK1_FREQUENCY) +#define AT32_APB1_TIM4_CLKIN (2*AT32_PCLK1_FREQUENCY) +#define AT32_APB1_TIM5_CLKIN (2*AT32_PCLK1_FREQUENCY) +#define AT32_APB1_TIM6_CLKIN (2*AT32_PCLK1_FREQUENCY) +#define AT32_APB1_TIM7_CLKIN (2*AT32_PCLK1_FREQUENCY) +#define AT32_APB1_TIM12_CLKIN (2*AT32_PCLK1_FREQUENCY) +#define AT32_APB1_TIM13_CLKIN (2*AT32_PCLK1_FREQUENCY) +#define AT32_APB1_TIM14_CLKIN (2*AT32_PCLK1_FREQUENCY) + +/* APB2 clock (PCLK2) is HCLK/2 (144MHz) */ + +#define AT32_PCLK2_FREQUENCY (AT32_HCLK_FREQUENCY/2) /* PCLK2 = HCLK / 2 */ + +/* Timers driven from APB2 will be twice PCLK2 */ + +#define AT32_APB2_TIM1_CLKIN (2*AT32_PCLK2_FREQUENCY) +#define AT32_APB2_TIM8_CLKIN (2*AT32_PCLK2_FREQUENCY) +#define AT32_APB2_TIM9_CLKIN (2*AT32_PCLK2_FREQUENCY) +#define AT32_APB2_TIM10_CLKIN (2*AT32_PCLK2_FREQUENCY) +#define AT32_APB2_TIM11_CLKIN (2*AT32_PCLK2_FREQUENCY) +#define AT32_APB2_TIM20_CLKIN (2*AT32_PCLK2_FREQUENCY) + +/* Timer Frequencies, if APBx is set to 1, frequency is same to APBx + * otherwise frequency is 2xAPBx. + * Note: TIM1,8 are on APB2, others on APB1 + */ + +#define BOARD_TIM1_FREQUENCY (AT32_HCLK_FREQUENCY) +#define BOARD_TIM2_FREQUENCY (AT32_HCLK_FREQUENCY) +#define BOARD_TIM3_FREQUENCY (AT32_HCLK_FREQUENCY) +#define BOARD_TIM4_FREQUENCY (AT32_HCLK_FREQUENCY) +#define BOARD_TIM5_FREQUENCY (AT32_HCLK_FREQUENCY) +#define BOARD_TIM6_FREQUENCY (AT32_HCLK_FREQUENCY) +#define BOARD_TIM7_FREQUENCY (AT32_HCLK_FREQUENCY) +#define BOARD_TIM8_FREQUENCY (AT32_HCLK_FREQUENCY) + +/* SDIO dividers. Note that slower clocking is required when DMA is disabled + * in order to avoid RX overrun/TX underrun errors due to delayed responses + * to service FIFOs in interrupt driven mode. These values have not been + * tuned!!! + * + * SDIOCLK=AT32_HCLK_FREQUENCY, SDIO_CK=SDIOCLK/(1438+2)=200 KHz + */ + +#define SDIO_INIT_CLKDIV (1438 << SDIO_CLKCR_CLKDIV_SHIFT) + +/* DMA ON: SDIOCLK=AT32_HCLK_FREQUENCY, SDIO_CK=SDIOCLK/(10+2)=24 MHz + * DMA OFF: SDIOCLK=AT32_HCLK_FREQUENCY, SDIO_CK=SDIOCLK/(22+2)=12 MHz + */ + +#ifdef CONFIG_SDIO_DMA +# define SDIO_MMCXFR_CLKDIV (10 << SDIO_CLKCR_CLKDIV_SHIFT) +#else +# define SDIO_MMCXFR_CLKDIV (22 << SDIO_CLKCR_CLKDIV_SHIFT) +#endif + +/* DMA ON: SDIOCLK=AT32_HCLK_FREQUENCY, SDIO_CK=SDIOCLK/(10+2)=24 MHz + * DMA OFF: SDIOCLK=AT32_HCLK_FREQUENCY, SDIO_CK=SDIOCLK/(22+2)=12 MHz + */ + +#ifdef CONFIG_SDIO_DMA +# define SDIO_SDXFR_CLKDIV (10 << SDIO_CLKCR_CLKDIV_SHIFT) +#else +# define SDIO_SDXFR_CLKDIV (22 << SDIO_CLKCR_CLKDIV_SHIFT) +#endif + +#define GPIO_SDIO_CMD GPIO_SDIO_CMD_1 +#define GPIO_SDIO_CK GPIO_SDIO_CK_1 +#define GPIO_SDIO_D0 GPIO_SDIO_D0_3 +#define GPIO_SDIO_D1 GPIO_SDIO_D1_1 +#define GPIO_SDIO_D2 GPIO_SDIO_D2_1 +#define GPIO_SDIO_D3 GPIO_SDIO_D3_1 + +/* LED definitions **********************************************************/ + +/* If CONFIG_ARCH_LEDS is not defined, then the user can control the LEDs + * in any way. The following definitions are used to access individual LEDs. + */ + +/* LED index values for use with board_userled() */ + +#define BOARD_LED1 0 +#define BOARD_LED2 1 +#define BOARD_NLEDS 2 + +#define BOARD_LED_GREEN BOARD_LED1 +#define BOARD_LED_ORANGE BOARD_LED2 + +/* LED bits for use with board_userled_all() */ + +#define BOARD_LED1_BIT (1 << BOARD_LED1) +#define BOARD_LED2_BIT (1 << BOARD_LED2) + +/* If CONFIG_ARCH_LEDS is defined, then NuttX will control the 2 LEDs on + * board the AT32F437-MINI. The following definitions describe how NuttX + * controls the LEDs: + * + * SYMBOL Meaning LED state + * LED1 LED2 + * ------------------- ----------------------- -------- -------- + * LED_STARTED NuttX has been started OFF OFF + * LED_HEAPALLOCATE Heap has been allocated OFF OFF + * LED_IRQSENABLED Interrupts enabled OFF OFF + * LED_STACKCREATED Idle stack created ON OFF + * LED_INIRQ In an interrupt No change + * LED_SIGNAL In a signal handler No change + * LED_ASSERTION An assertion failed No change + * LED_PANIC The system has crashed OFF Blinking + * LED_IDLE AT32 is is sleep mode Not used + */ + +#define LED_STARTED 0 +#define LED_HEAPALLOCATE 0 +#define LED_IRQSENABLED 0 +#define LED_STACKCREATED 1 +#define LED_INIRQ 2 +#define LED_SIGNAL 2 +#define LED_ASSERTION 2 +#define LED_PANIC 3 + +/* USB */ + +/** + * pll clock = AT32_HCLK_FREQUENCY(288MHz) + * usb clock use pll + * usb_clk = 288/6 = 48MHz + * **/ +#define USB_CONFIG_USBDIV (CRM_MISC2_USBDIV_6P0) + +/* USART1 */ + +# define GPIO_USART1_TX GPIO_USART1_TX_1 +# define GPIO_USART1_RX GPIO_USART1_RX_1 + +/* USART2 for RS485 */ +# define GPIO_USART2_TX GPIO_USART2_TX_2 +# define GPIO_USART2_RX GPIO_USART2_RX_2 +# define GPIO_USART2_RS485_DIR (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_DRV_STRONG |\ + GPIO_OUTPUT_CLEAR | GPIO_PORTD | GPIO_PIN4) + +/* SPI1 */ + +#define GPIO_SPI1_MISO GPIO_SPI1_MISO_2 +#define GPIO_SPI1_MOSI GPIO_SPI1_MOSI_2 +#define GPIO_SPI1_SCK GPIO_SPI1_SCK_2 + +/* CAN */ + +#define GPIO_CAN1_RX GPIO_CAN1_RX_3 +#define GPIO_CAN1_TX GPIO_CAN1_TX_3 + +/* ETH */ + +#define GPIO_ETH_RMII_TX_EN GPIO_ETH_RMII_TX_EN_1 //PB11 +#define GPIO_ETH_RMII_TXD0 GPIO_ETH_RMII_TXD0_1 //PB12 +#define GPIO_ETH_RMII_TXD1 GPIO_ETH_RMII_TXD1_1 //PB13 + +/* I2C */ + +#define GPIO_I2C3_SCL GPIO_I2C3_SCL_2 +#define GPIO_I2C3_SDA GPIO_I2C3_SDA_2 + +/* PWM */ + +#define GPIO_TIM3_CH1OUT GPIO_TIM3_CH1OUT_4 +#define GPIO_TIM20_CH1OUT GPIO_TIM20_CH1OUT_2 + +#endif /* __BOARDS_ARM_AT32_AT32F437-MINN_INCLUDE_BOARD_H */ diff --git a/boards/arm/at32/at32f437-mini/include/nsh_romfsimg.h b/boards/arm/at32/at32f437-mini/include/nsh_romfsimg.h new file mode 100644 index 0000000000..db6d674d88 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/include/nsh_romfsimg.h @@ -0,0 +1,111 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/include/nsh_romfsimg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +unsigned char romfs_img[] = +{ + 0x2d, 0x72, 0x6f, 0x6d, 0x31, 0x66, 0x73, 0x2d, 0x00, 0x00, 0x03, 0x70, + 0xc4, 0x28, 0xb0, 0x57, 0x72, 0x6f, 0x6d, 0x66, 0x73, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xff, 0xff, 0x97, + 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xff, 0x80, 0x2e, 0x2e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x29, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x2d, 0x93, 0xe3, 0x69, 0x6e, 0x69, 0x74, 0x2e, 0x64, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xaa, 0xb5, 0x65, 0x83, + 0x72, 0x63, 0x2e, 0x73, 0x79, 0x73, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x23, 0x69, 0x66, 0x75, 0x70, 0x20, 0x63, 0x61, + 0x6e, 0x30, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x5b, 0x20, 0x2d, 0x62, 0x20, + 0x22, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x6d, 0x74, 0x64, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x30, 0x22, 0x20, 0x5d, 0x3b, 0x20, 0x74, 0x68, 0x65, 0x6e, + 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x2d, 0x74, 0x20, 0x76, 0x66, + 0x61, 0x74, 0x20, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x6d, 0x74, 0x64, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x30, 0x20, 0x2f, 0x66, 0x6c, 0x61, 0x73, 0x68, + 0x0a, 0x66, 0x69, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x5b, 0x20, 0x2d, 0x62, + 0x20, 0x22, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x6d, 0x6d, 0x63, 0x73, 0x64, + 0x30, 0x22, 0x20, 0x5d, 0x3b, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x2d, 0x74, 0x20, 0x76, 0x66, 0x61, 0x74, + 0x20, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x6d, 0x6d, 0x63, 0x73, 0x64, 0x30, + 0x20, 0x2f, 0x73, 0x64, 0x0a, 0x66, 0x69, 0x0a, 0x0a, 0x23, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x20, 0x2d, 0x74, 0x20, 0x76, 0x66, 0x61, 0x74, 0x20, + 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x6d, 0x74, 0x64, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x30, 0x20, 0x2f, 0x6d, 0x6e, 0x74, 0x0a, 0x23, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x20, 0x2d, 0x74, 0x20, 0x76, 0x66, 0x61, 0x74, 0x20, 0x2f, + 0x64, 0x65, 0x76, 0x2f, 0x6d, 0x6d, 0x63, 0x73, 0x64, 0x30, 0x20, 0x2f, + 0x73, 0x64, 0x63, 0x61, 0x72, 0x64, 0x0a, 0x23, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x20, 0x2d, 0x74, 0x20, 0x76, 0x66, 0x61, 0x74, 0x20, 0x2f, 0x64, + 0x65, 0x76, 0x2f, 0x73, 0x64, 0x61, 0x20, 0x2f, 0x75, 0x73, 0x62, 0x0a, + 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xfe, 0x20, + 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x00, 0xd1, 0xff, 0xfd, 0xc0, 0x2e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, + 0x8d, 0x9c, 0xac, 0xe7, 0x72, 0x63, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x20, 0x2d, 0x74, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x66, 0x73, 0x20, + 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x02, 0x40, + 0x00, 0x00, 0x00, 0x00, 0xb6, 0x18, 0x23, 0xeb, 0x73, 0x79, 0x73, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x39, 0x00, 0x00, 0x02, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x50, 0x35, 0x5a, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2d, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x00, 0x00, 0x00, 0x02, 0xf2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0xc7, 0x32, 0x33, 0xcf, + 0x69, 0x70, 0x63, 0x66, 0x67, 0x2d, 0x65, 0x74, 0x68, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x3d, 0x65, + 0x74, 0x68, 0x30, 0x0a, 0x49, 0x50, 0x76, 0x34, 0x50, 0x52, 0x4f, 0x54, + 0x4f, 0x3d, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x0a, 0x49, 0x50, 0x76, + 0x34, 0x49, 0x50, 0x41, 0x44, 0x44, 0x52, 0x3d, 0x31, 0x39, 0x32, 0x2e, + 0x31, 0x36, 0x38, 0x2e, 0x31, 0x2e, 0x39, 0x30, 0x0a, 0x49, 0x50, 0x76, + 0x34, 0x4e, 0x45, 0x54, 0x4d, 0x41, 0x53, 0x4b, 0x3d, 0x32, 0x35, 0x35, + 0x2e, 0x32, 0x35, 0x35, 0x2e, 0x32, 0x35, 0x35, 0x2e, 0x30, 0x0a, 0x49, + 0x50, 0x76, 0x34, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x52, 0x3d, 0x31, 0x39, + 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x31, 0x2e, 0x31, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10, + 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xfa, 0xd0, + 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, + 0x00, 0x00, 0x00, 0x00, 0xd1, 0xff, 0xfd, 0xc0, 0x2e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x50, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0xd1, 0xd1, 0xfc, 0x90, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xff, 0xfd, 0xe0, + 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +unsigned int romfs_img_len = 1024; diff --git a/boards/arm/at32/at32f437-mini/kernel/Makefile b/boards/arm/at32/at32f437-mini/kernel/Makefile new file mode 100644 index 0000000000..cf1b4df31e --- /dev/null +++ b/boards/arm/at32/at32f437-mini/kernel/Makefile @@ -0,0 +1,92 @@ +############################################################################ +# boards/arm/at32/at32f437-mini/kernel/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(TOPDIR)/Make.defs + +# The entry point name (if none is provided in the .config file) + +CONFIG_INIT_ENTRYPOINT ?= user_start +ENTRYPT = $(patsubst "%",%,$(CONFIG_INIT_ENTRYPOINT)) + +# Get the paths to the libraries and the links script path in format that +# is appropriate for the host OS + +USER_LIBPATHS = $(addprefix -L,$(call CONVERT_PATH,$(addprefix $(TOPDIR)$(DELIM),$(dir $(USERLIBS))))) +USER_LDSCRIPT = -T $(call CONVERT_PATH,$(BOARD_DIR)$(DELIM)scripts$(DELIM)memory.ld) +USER_LDSCRIPT += -T $(call CONVERT_PATH,$(BOARD_DIR)$(DELIM)scripts$(DELIM)user-space.ld) +USER_HEXFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.hex) +USER_SRECFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.srec) +USER_BINFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.bin) + +USER_LDFLAGS = --undefined=$(ENTRYPT) --entry=$(ENTRYPT) $(USER_LDSCRIPT) +USER_LDLIBS = $(patsubst lib%,-l%,$(basename $(notdir $(USERLIBS)))) +USER_LIBGCC = "${shell "$(CC)" $(ARCHCPUFLAGS) -print-libgcc-file-name}" + +# Source files + +CSRCS = at32_userspace.c +COBJS = $(CSRCS:.c=$(OBJEXT)) +OBJS = $(COBJS) + +# Targets: + +all: $(TOPDIR)$(DELIM)nuttx_user.elf $(TOPDIR)$(DELIM)User.map +.PHONY: nuttx_user.elf depend clean distclean + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +# Create the nuttx_user.elf file containing all of the user-mode code + +nuttx_user.elf: $(OBJS) + $(Q) $(LD) -o $@ $(USER_LDFLAGS) $(USER_LIBPATHS) $(OBJS) --start-group $(USER_LDLIBS) $(USER_LIBGCC) --end-group + +$(TOPDIR)$(DELIM)nuttx_user.elf: nuttx_user.elf + @echo "LD: nuttx_user.elf" + $(Q) cp -a nuttx_user.elf $(TOPDIR)$(DELIM)nuttx_user.elf +ifeq ($(CONFIG_INTELHEX_BINARY),y) + @echo "CP: nuttx_user.hex" + $(Q) $(OBJCOPY) $(OBJCOPYARGS) -O ihex nuttx_user.elf $(USER_HEXFILE) +endif +ifeq ($(CONFIG_MOTOROLA_SREC),y) + @echo "CP: nuttx_user.srec" + $(Q) $(OBJCOPY) $(OBJCOPYARGS) -O srec nuttx_user.elf $(USER_SRECFILE) +endif +ifeq ($(CONFIG_RAW_BINARY),y) + @echo "CP: nuttx_user.bin" + $(Q) $(OBJCOPY) $(OBJCOPYARGS) -O binary nuttx_user.elf $(USER_BINFILE) +endif + +$(TOPDIR)$(DELIM)User.map: nuttx_user.elf + @echo "MK: User.map" + $(Q) $(NM) nuttx_user.elf >$(TOPDIR)$(DELIM)User.map + $(Q) $(CROSSDEV)size nuttx_user.elf + +.depend: + +depend: .depend + +clean: + $(call DELFILE, nuttx_user.elf) + $(call DELFILE, "$(TOPDIR)$(DELIM)nuttx_user.*") + $(call DELFILE, "$(TOPDIR)$(DELIM)User.map") + $(call CLEAN) + +distclean: clean diff --git a/boards/arm/at32/at32f437-mini/kernel/at32_userspace.c b/boards/arm/at32/at32f437-mini/kernel/at32_userspace.c new file mode 100644 index 0000000000..898045eb31 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/kernel/at32_userspace.c @@ -0,0 +1,100 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/kernel/at32_userspace.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include + +#if defined(CONFIG_BUILD_PROTECTED) && !defined(__KERNEL__) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_NUTTX_USERSPACE +# error "CONFIG_NUTTX_USERSPACE not defined" +#endif + +#if CONFIG_NUTTX_USERSPACE != 0x08060000 +# error "CONFIG_NUTTX_USERSPACE must be 0x08060000 to match memory.ld" +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* These 'addresses' of these values are setup by the linker script. */ + +extern uint8_t _stext[]; /* Start of .text */ +extern uint8_t _etext[]; /* End_1 of .text + .rodata */ +extern const uint8_t _eronly[]; /* End+1 of read only section (.text + .rodata) */ +extern uint8_t _sdata[]; /* Start of .data */ +extern uint8_t _edata[]; /* End+1 of .data */ +extern uint8_t _sbss[]; /* Start of .bss */ +extern uint8_t _ebss[]; /* End+1 of .bss */ + +const struct userspace_s userspace locate_data(".userspace") = +{ + /* General memory map */ + + .us_entrypoint = CONFIG_INIT_ENTRYPOINT, + .us_textstart = (uintptr_t)_stext, + .us_textend = (uintptr_t)_etext, + .us_datasource = (uintptr_t)_eronly, + .us_datastart = (uintptr_t)_sdata, + .us_dataend = (uintptr_t)_edata, + .us_bssstart = (uintptr_t)_sbss, + .us_bssend = (uintptr_t)_ebss, + + /* Memory manager heap structure */ + + .us_heap = &g_mmheap, + + /* Task/thread startup routines */ + + .task_startup = nxtask_startup, + + /* Signal handler trampoline */ + + .signal_handler = up_signal_handler, + + /* User-space work queue support (declared in include/nuttx/wqueue.h) */ + +#ifdef CONFIG_LIBC_USRWORK + .work_usrstart = work_usrstart, +#endif +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#endif /* CONFIG_BUILD_PROTECTED && !__KERNEL__ */ diff --git a/boards/arm/at32/at32f437-mini/romfs/init.d/rc.sysinit b/boards/arm/at32/at32f437-mini/romfs/init.d/rc.sysinit new file mode 100644 index 0000000000..0e2ea790a7 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/romfs/init.d/rc.sysinit @@ -0,0 +1,15 @@ +#ifup can0 + +if [ -b "/dev/mtdblock0" ]; then +mount -t vfat /dev/mtdblock0 /flash +fi + +if [ -b "/dev/mmcsd0" ]; then +mount -t vfat /dev/mmcsd0 /sd +fi + +#mount -t vfat /dev/mtdblock0 /mnt +#mount -t vfat /dev/mmcsd0 /sdcard +#mount -t vfat /dev/sda /usb + + diff --git a/boards/arm/at32/at32f437-mini/romfs/init.d/rcS b/boards/arm/at32/at32f437-mini/romfs/init.d/rcS new file mode 100644 index 0000000000..d5b9512cfb --- /dev/null +++ b/boards/arm/at32/at32f437-mini/romfs/init.d/rcS @@ -0,0 +1,2 @@ +mount -t procfs /proc + diff --git a/boards/arm/at32/at32f437-mini/romfs/sysconfig/network-scripts/ipcfg-eth0 b/boards/arm/at32/at32f437-mini/romfs/sysconfig/network-scripts/ipcfg-eth0 new file mode 100644 index 0000000000..c72981d487 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/romfs/sysconfig/network-scripts/ipcfg-eth0 @@ -0,0 +1,5 @@ +DEVICE=eth0 +IPv4PROTO=static +IPv4IPADDR=192.168.1.90 +IPv4NETMASK=255.255.255.0 +IPv4ROUTER=192.168.1.1 \ No newline at end of file diff --git a/boards/arm/at32/at32f437-mini/scripts/Make.defs b/boards/arm/at32/at32f437-mini/scripts/Make.defs new file mode 100644 index 0000000000..fbbe492f29 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/scripts/Make.defs @@ -0,0 +1,54 @@ +############################################################################ +# boards/arm/at32/at32f437-mini/scripts/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(TOPDIR)/.config +include $(TOPDIR)/tools/Config.mk +include $(TOPDIR)/arch/arm/src/armv7-m/Toolchain.defs + +LDSCRIPT = ld.script +ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) + +ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10 + +CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe +CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) +CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe +CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS) +CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +AFLAGS := $(CFLAGS) -D__ASSEMBLY__ + +NXFLATLDFLAGS1 = -r -d -warn-common +NXFLATLDFLAGS2 = $(NXFLATLDFLAGS1) -T$(TOPDIR)/binfmt/libnxflat/gnu-nxflat-pcrel.ld -no-check-sections +LDNXFLATFLAGS = -e main -s 2048 + +# Loadable module definitions + +CMODULEFLAGS = $(CFLAGS) -mlong-calls # --target1-abs + +LDMODULEFLAGS = -r -e module_initialize +LDMODULEFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld) + +# ELF module definitions + +CELFFLAGS = $(CFLAGS) -mlong-calls # --target1-abs +CXXELFFLAGS = $(CXXFLAGS) -mlong-calls # --target1-abs + +LDELFFLAGS = -r -e main +LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/binfmt/libelf/gnu-elf.ld) diff --git a/boards/arm/at32/at32f437-mini/scripts/kernel-space.ld b/boards/arm/at32/at32f437-mini/scripts/kernel-space.ld new file mode 100644 index 0000000000..cc7c55453c --- /dev/null +++ b/boards/arm/at32/at32f437-mini/scripts/kernel-space.ld @@ -0,0 +1,96 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/scripts/kernel-space.ld + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* NOTE: This depends on the memory.ld script having been included prior to + * this script. + */ + +OUTPUT_ARCH(arm) +ENTRY(_stext) +SECTIONS +{ + .text : { + _stext = ABSOLUTE(.); + *(.vectors) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > kflash + + .init_section : { + _sinit = ABSOLUTE(.); + *(.init_array .init_array.*) + _einit = ABSOLUTE(.); + } > kflash + + .ARM.extab : { + *(.ARM.extab*) + } > kflash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : { + *(.ARM.exidx*) + } > kflash + + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > ksram AT > kflash + + .bss : { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > ksram + + /* Stabs debugging sections */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/arm/at32/at32f437-mini/scripts/ld.script b/boards/arm/at32/at32f437-mini/scripts/ld.script new file mode 100644 index 0000000000..e392e1663f --- /dev/null +++ b/boards/arm/at32/at32f437-mini/scripts/ld.script @@ -0,0 +1,126 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/scripts/ld.script + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* The AT32F437VM has 4032KB of FLASH beginning at address 0x0800:0000 and + * 384KB of SRAM. SRAM is split up into one or two blocks: + * + * 1) 384KB of SRAM beginning at address 0x2000:0000 + * or + * 1) 64KB of SRAM beginning at address 0x1000:0000 + * 2) 320KB of SRAM beginning at address 0x2000:0000 + * + * When booting from FLASH, FLASH memory is aliased to address 0x0000:0000 + * where the code expects to begin execution by jumping to the entry point in + * the 0x0800:0000 address + * range. + */ + +MEMORY +{ + flash (rx) : ORIGIN = 0x08000000, LENGTH = 4032K + sram (rwx) : ORIGIN = 0x20000000, LENGTH = 384K +} + +OUTPUT_ARCH(arm) +ENTRY(_stext) +EXTERN(_vectors) +SECTIONS +{ + .text : { + _stext = ABSOLUTE(.); + *(.vectors) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > flash + + .init_section : ALIGN(4) { + _sinit = ABSOLUTE(.); + KEEP(*(.init_array .init_array.*)) + _einit = ABSOLUTE(.); + } > flash + + .ARM.extab : ALIGN(4) { + *(.ARM.extab*) + } > flash + + .ARM.exidx : ALIGN(4) { + __exidx_start = ABSOLUTE(.); + *(.ARM.exidx*) + __exidx_end = ABSOLUTE(.); + } > flash + + .tdata : { + _stdata = ABSOLUTE(.); + *(.tdata .tdata.* .gnu.linkonce.td.*); + _etdata = ABSOLUTE(.); + } > flash + + .tbss : { + _stbss = ABSOLUTE(.); + *(.tbss .tbss.* .gnu.linkonce.tb.* .tcommon); + _etbss = ABSOLUTE(.); + } > flash + + _eronly = ABSOLUTE(.); + + .data : ALIGN(4) { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > sram AT > flash = 0xff + + .bss : ALIGN(4) { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + + + /* Stabs debugging sections. */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/arm/at32/at32f437-mini/scripts/memory.ld b/boards/arm/at32/at32f437-mini/scripts/memory.ld new file mode 100644 index 0000000000..2fd34cb050 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/scripts/memory.ld @@ -0,0 +1,86 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/scripts/memory.ld + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* The AT32F437VM has 4032KB of FLASH beginning at address 0x0800:0000 and + * 384KB of SRAM. SRAM is split up into one or two blocks: + * + * 1) 384KB of SRAM beginning at address 0x2000:0000 + * or + * 1) 64KB of SRAM beginning at address 0x1000:0000 + * 2) 320KB of SRAM beginning at address 0x2000:0000 + * + * When booting from FLASH, FLASH memory is aliased to address 0x0000:0000 + * where the code expects to begin execution by jumping to the entry point in + * the 0x0800:0000 address range. + * + * For MPU support, the kernel-mode NuttX section is assumed to be 128KB of + * FLASH and 4KB of SRAM. That is an excessive amount for the kernel which + * should fit into 64KB and, of course, can be optimized as needed (See + * also boards/arm/at32/at32f437-mini/scripts/kernel-space.ld). Allowing the + * additional does permit addition debug instrumentation to be added to the + * kernel space without overflowing the partition. + * + * Alignment of the user space FLASH partition is also a critical factor: + * The user space FLASH partition will be spanned with a single region of + * size 2**n bytes. The alignment of the user-space region must be the same. + * As a consequence, as the user-space increases in size, the alignment + * requirement also increases. + * + * This alignment requirement means that the largest user space FLASH region + * you can have will be 3904KB at it would have to be positioned at + * 0x08800000. If you change this address, don't forget to change the + * CONFIG_NUTTX_USERSPACE configuration setting to match and to modify + * the check in kernel/userspace.c. + * + * For the same reasons, the maximum size of the SRAM mapping is limited to + * 4KB. Both of these alignment limitations could be reduced by using + * multiple regions to map the FLASH/SDRAM range or perhaps with some + * clever use of subregions. + * + * A detailed memory map for the 112KB SRAM region is as follows: + * + * 0x20000 0000: Kernel .data region. Typical size: 0.1KB + * ------- ---- Kernel .bss region. Typical size: 1.8KB + * 0x20000 0800: Kernel IDLE thread stack (approximate). Size is + * determined by CONFIG_IDLETHREAD_STACKSIZE and + * adjustments for alignment. Typical is 1KB. + * ------- ---- Padded to 4KB + * 0x20000 1000: User .data region. Size is variable. + * ------- ---- User .bss region Size is variable. + * 0x20000 2000: Beginning of kernel heap. Size determined by + * CONFIG_MM_KERNEL_HEAPSIZE. + * ------- ---- Beginning of user heap. Can vary with other settings. + * 0x20006 0000: End+1 of CPU RAM + */ + +MEMORY +{ + /* 4032Kb FLASH */ + + kflash (rx) : ORIGIN = 0x08000000, LENGTH = 128K + uflash (rx) : ORIGIN = 0x08020000, LENGTH = 128K + xflash (rx) : ORIGIN = 0x08040000, LENGTH = 3776K + + /* 384Kb of contiguous SRAM */ + + ksram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K + usram (rwx) : ORIGIN = 0x20001000, LENGTH = 4K + xsram (rwx) : ORIGIN = 0x20002000, LENGTH = 376K +} diff --git a/boards/arm/at32/at32f437-mini/scripts/user-space.ld b/boards/arm/at32/at32f437-mini/scripts/user-space.ld new file mode 100644 index 0000000000..1ad01e5830 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/scripts/user-space.ld @@ -0,0 +1,98 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/scripts/user-space.ld + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* NOTE: This depends on the memory.ld script having been included prior to + * this script. + */ + +OUTPUT_ARCH(arm) +SECTIONS +{ + .userspace : { + *(.userspace) + } > uflash + + .text : { + _stext = ABSOLUTE(.); + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > uflash + + .init_section : { + _sinit = ABSOLUTE(.); + *(.init_array .init_array.*) + _einit = ABSOLUTE(.); + } > uflash + + .ARM.extab : { + *(.ARM.extab*) + } > uflash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : { + *(.ARM.exidx*) + } > uflash + + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > usram AT > uflash + + .bss : { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > usram + + /* Stabs debugging sections */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/arm/at32/at32f437-mini/src/Makefile b/boards/arm/at32/at32f437-mini/src/Makefile new file mode 100644 index 0000000000..f0d5bc351e --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/Makefile @@ -0,0 +1,83 @@ +############################################################################ +# boards/arm/at32/at32f437-mini/src/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(TOPDIR)/Make.defs + +CSRCS = at32_boot.c at32_bringup.c + +ifeq ($(CONFIG_BOARDCTL),y) + CSRCS += at32_appinit.c +endif + +ifeq ($(CONFIG_DEV_GPIO),y) + CSRCS += at32_gpio.c +endif + +ifeq ($(CONFIG_ARCH_LEDS),y) + CSRCS += at32_autoleds.c +else + CSRCS += at32_userleds.c +endif + +ifeq ($(CONFIG_SPI),y) + CSRCS += at32_spi.c +endif + +ifeq ($(CONFIG_MTD_W25),y) + CSRCS += at32_w25.c +endif + +ifeq ($(CONFIG_AT32_CAN_CHARDRIVER),y) + CSRCS += at32_can.c +endif + +ifeq ($(CONFIG_AT32_CAN_SOCKET),y) + CSRCS += at32_cansock.c +endif + +ifeq ($(CONFIG_AT32_ETHMAC),y) + CSRCS += at32_ethernet.c +endif + +ifeq ($(CONFIG_AT32_OTGFS),y) + CSRCS += at32_usb.c +endif + +ifeq ($(CONFIG_AT32_SDIO),y) + CSRCS += at32_mmcsd.c +endif + +ifeq ($(CONFIG_AT32_PWM),y) + CSRCS += at32_pwm.c +endif + +ifeq ($(CONFIG_TIMER),y) + CSRCS += at32_timer.c +endif + +ifeq ($(CONFIG_AT32_ADC),y) + CSRCS += at32_adc.c +endif + +ifeq ($(CONFIG_MTD_AT24XX),y) + CSRCS += at32_at24.c +endif + +include $(TOPDIR)/boards/Board.mk \ No newline at end of file diff --git a/boards/arm/at32/at32f437-mini/src/at32_adc.c b/boards/arm/at32/at32f437-mini/src/at32_adc.c new file mode 100644 index 0000000000..72526bab8e --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_adc.c @@ -0,0 +1,235 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_adc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "at32.h" +#include "at32_adc.h" +#include "at32f437-mini.h" + +#if defined(CONFIG_ADC) && (defined(CONFIG_AT32_ADC1) || defined(CONFIG_AT32_ADC3)) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* 1 or 2 ADC devices (DEV1, DEV2). + * ADC1 and ADC3 supported for now. + */ + +#if defined(CONFIG_AT32_ADC1) +# define DEV1_PORT 1 +#endif + +#if defined(CONFIG_AT32_ADC3) +# if defined(DEV1_PORT) +# define DEV2_PORT 3 +# else +# define DEV1_PORT 3 +# endif +#endif + +/* The number of ADC channels in the conversion list */ + +/* TODO DMA */ + +#define ADC1_NCHANNELS 2 +#define ADC3_NCHANNELS 1 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* DEV 1 */ + +#if DEV1_PORT == 1 + +#define DEV1_NCHANNELS ADC1_NCHANNELS + +/* Identifying number of each ADC channel (even if NCHANNELS is less ) */ + +static const uint8_t g_chanlist1[1] = +{ + 8, +}; + +/* Configurations of pins used by each ADC channel */ + +static const uint32_t g_pinlist1[1] = +{ + GPIO_ADC1_IN8, /* PB0 */ +}; + +#elif DEV1_PORT == 3 + +#define DEV1_NCHANNELS ADC3_NCHANNELS + +/* Identifying number of each ADC channel */ + +static const uint8_t g_chanlist1[1] = +{ + 4, +}; + +/* Configurations of pins used by each ADC channel */ + +static const uint32_t g_pinlist1[1] = +{ + GPIO_ADC3_IN4, /* PF6 */ +}; + +#endif /* DEV1_PORT == 1 */ + +#ifdef DEV2_PORT + +/* DEV 2 */ + +#if DEV2_PORT == 3 + +#define DEV2_NCHANNELS ADC3_NCHANNELS + +/* Identifying number of each ADC channel */ + +static const uint8_t g_chanlist2[3] = +{ + 8, + 9, + 10 +}; + +/* Configurations of pins used by each ADC channel */ + +static const uint32_t g_pinlist2[3] = +{ + GPIO_ADC3_IN8, /* PF10 */ + GPIO_ADC3_IN9, /* PF3 */ + GPIO_ADC3_IN10, /* PC0 */ +}; + +#endif /* DEV2_PORT == 3 */ +#endif /* DEV2_PORT */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_adc_setup + * + * Description: + * Initialize ADC and register the ADC driver. + * + ****************************************************************************/ + +int at32_adc_setup(void) +{ + static bool initialized = false; + struct adc_dev_s *adc; + int ret; + int i; + + /* Check if we have already initialized */ + + if (!initialized) + { + /* DEV1 */ + + /* Configure the pins as analog inputs for the selected channels */ + + for (i = 0; i < DEV1_NCHANNELS; i++) + { + at32_configgpio(g_pinlist1[i]); + } + + /* Call at32_adcinitialize() to get an instance of the ADC interface */ + + adc = at32_adcinitialize(DEV1_PORT, g_chanlist1, DEV1_NCHANNELS); + if (adc == NULL) + { + aerr("ERROR: Failed to get ADC interface 1\n"); + return -ENODEV; + } + + /* Register the ADC driver at "/dev/adc0" */ + + ret = adc_register("/dev/adc0", adc); + if (ret < 0) + { + aerr("ERROR: adc_register /dev/adc0 failed: %d\n", ret); + return ret; + } + +#ifdef DEV2_PORT + /* DEV2 */ + + /* Configure the pins as analog inputs for the selected channels */ + + for (i = 0; i < DEV2_NCHANNELS; i++) + { + at32_configgpio(g_pinlist2[i]); + } + + /* Call at32_adcinitialize() to get an instance of the ADC interface */ + + adc = at32_adcinitialize(DEV2_PORT, g_chanlist2, DEV2_NCHANNELS); + if (adc == NULL) + { + aerr("ERROR: Failed to get ADC interface 2\n"); + return -ENODEV; + } + + /* Register the ADC driver at "/dev/adc1" */ + + ret = adc_register("/dev/adc1", adc); + if (ret < 0) + { + aerr("ERROR: adc_register /dev/adc1 failed: %d\n", ret); + return ret; + } +#endif + + initialized = true; + } + + return OK; +} + +#endif /* CONFIG_ADC && (CONFIG_AT32_ADC1 || CONFIG_AT32_ADC3) */ diff --git a/boards/arm/at32/at32f437-mini/src/at32_appinit.c b/boards/arm/at32/at32f437-mini/src/at32_appinit.c new file mode 100644 index 0000000000..2dba8d7564 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_appinit.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_appinit.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "at32f437-mini.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_app_initialize + * + * Description: + * Perform application specific initialization. This function is never + * called directly from application code, but only indirectly via the + * (non-standard) boardctl() interface using the command BOARDIOC_INIT. + * + * Input Parameters: + * arg - The boardctl() argument is passed to the board_app_initialize() + * implementation without modification. The argument has no + * meaning to NuttX; the meaning of the argument is a contract + * between the board-specific initialization logic and the + * matching application logic. The value could be such things as a + * mode enumeration value, a set of DIP switch switch settings, a + * pointer to configuration data read from a file or serial FLASH, + * or whatever you would like to do with it. Every implementation + * should accept zero/NULL as a default configuration. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure to indicate the nature of the failure. + * + ****************************************************************************/ + +int board_app_initialize(uintptr_t arg) +{ +#ifdef CONFIG_BOARD_LATE_INITIALIZE + /* Board initialization already performed by board_late_initialize() */ + + return OK; +#else + /* Perform board-specific initialization */ + + return at32_bringup(); +#endif +} diff --git a/boards/arm/at32/at32f437-mini/src/at32_at24.c b/boards/arm/at32/at32f437-mini/src/at32_at24.c new file mode 100644 index 0000000000..ccfe0dde48 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_at24.c @@ -0,0 +1,128 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_at24.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "at32_i2c.h" +#include "at32f437-mini.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_at24_automount + * + * Description: + * Initialize and configure the AT24 serial EEPROM + * + ****************************************************************************/ + +int at32_at24_automount(int minor) +{ + struct i2c_master_s *i2c; + struct mtd_dev_s *mtd; + static bool initialized = false; + int ret; + + /* Have we already initialized? */ + + if (!initialized) + { + /* No.. Get the I2C bus driver */ + + finfo("Initialize I2C%d\n", AT24_I2C_BUS); + i2c = at32_i2cbus_initialize(AT24_I2C_BUS); + if (!i2c) + { + ferr("ERROR: Failed to initialize I2C%d\n", AT24_I2C_BUS); + return -ENODEV; + } + + /* Now bind the I2C interface to the AT24 I2C EEPROM driver */ + + finfo("Bind the AT24 EEPROM driver to I2C%d\n", AT24_I2C_BUS); + mtd = at24c_initialize(i2c); + if (!mtd) + { + ferr("ERROR: Failed to bind TWI%d to the AT24 EEPROM driver\n", + AT24_I2C_BUS); + return -ENODEV; + } + +#if defined(CONFIG_FS_NXFFS) + /* Initialize to provide NXFFS on the MTD interface */ + + finfo("Initialize the NXFFS file system\n"); + ret = nxffs_initialize(mtd); + if (ret < 0) + { + ferr("ERROR: NXFFS initialization failed: %d\n", ret); + return ret; + } + + /* Mount the file system at /mnt/at24 */ + + finfo("Mount the NXFFS file system at /dev/at24\n"); + ret = nx_mount(NULL, "/mnt/at24", "nxffs", 0, NULL); + if (ret < 0) + { + ferr("ERROR: Failed to mount the NXFFS volume: %d\n", ret); + return ret; + } +#else + /* And use the FTL layer to wrap the MTD driver as a block driver */ + + finfo("Initialize the FTL layer to create /dev/mtdblock%d\n", + AT24_MINOR); + ret = ftl_initialize(AT24_MINOR, mtd); + if (ret < 0) + { + ferr("ERROR: Failed to initialize the FTL layer: %d\n", ret); + return ret; + } +#endif + + /* Now we are initialized */ + + initialized = true; + } + + return OK; +} + diff --git a/boards/arm/at32/at32f437-mini/src/at32_autoleds.c b/boards/arm/at32/at32f437-mini/src/at32_autoleds.c new file mode 100644 index 0000000000..23ee5b3c1a --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_autoleds.c @@ -0,0 +1,122 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_autoleds.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "chip.h" +#include "at32.h" +#include "at32f437-mini.h" + +#ifdef CONFIG_ARCH_LEDS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* If CONFIG_ARCH_LEDS is defined, then NuttX will control the 2 LEDs on + * board the AT32F437-MINI. The following definitions describe how NuttX + * controls the LEDs: + * + * SYMBOL Meaning LED state + * LED1 LED2 + * ------------------- ----------------------- -------- -------- + * LED_STARTED NuttX has been started OFF OFF + * LED_HEAPALLOCATE Heap has been allocated OFF OFF + * LED_IRQSENABLED Interrupts enabled OFF OFF + * LED_STACKCREATED Idle stack created ON OFF + * LED_INIRQ In an interrupt No change + * LED_SIGNAL In a signal handler No change + * LED_ASSERTION An assertion failed No change + * LED_PANIC The system has crashed OFF Blinking + * LED_IDLE AT32 is is sleep mode Not used + */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_autoled_initialize + ****************************************************************************/ + +void board_autoled_initialize(void) +{ + /* Configure LED1-2 GPIOs for output */ + + at32_configgpio(GPIO_LED1); + at32_configgpio(GPIO_LED2); +} + +/**************************************************************************** + * Name: board_autoled_on + ****************************************************************************/ + +void board_autoled_on(int led) +{ + bool led1on = false; + bool led2on = false; + + switch (led) + { + case 0: /* LED_STARTED, LED_HEAPALLOCATE, LED_IRQSENABLED */ + break; + + case 1: /* LED_STACKCREATED */ + led1on = true; + break; + + default: + case 2: /* LED_INIRQ, LED_SIGNAL, LED_ASSERTION */ + return; + + case 3: /* LED_PANIC */ + led2on = true; + break; + } + + at32_gpiowrite(GPIO_LED1, led1on); + at32_gpiowrite(GPIO_LED2, led2on); +} + +/**************************************************************************** + * Name: board_autoled_off + ****************************************************************************/ + +void board_autoled_off(int led) +{ + if (led != 2) + { + at32_gpiowrite(GPIO_LED1, false); + at32_gpiowrite(GPIO_LED2, false); + } +} + +#endif /* CONFIG_ARCH_LEDS */ diff --git a/boards/arm/at32/at32f437-mini/src/at32_boot.c b/boards/arm/at32/at32f437-mini/src/at32_boot.c new file mode 100644 index 0000000000..1f07c6a87a --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_boot.c @@ -0,0 +1,115 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_boot.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "arm_internal.h" +#include "nvic.h" +#include "itm.h" + +#include "at32.h" +#include "at32f437-mini.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_boardinitialize + * + * Description: + * All at32 architectures must provide the following entry point. This + * entry point is called early in the initialization -- after all memory + * has been configured and mapped but before any devices have been + * initialized. + * + ****************************************************************************/ + +void at32_boardinitialize(void) +{ +#if defined(CONFIG_AT32_SPI1) || defined(CONFIG_AT32_SPI2) || \ +defined(CONFIG_AT32_SPI3) || defined(CONFIG_AT32_SPI4) + /* Configure SPI chip selects if 1) SPI is not disabled, and 2) the weak + * function at32_spidev_initialize() has been brought into the link. + */ + + if (at32_spidev_initialize) + { + at32_spidev_initialize(); + } +#endif + +#ifdef CONFIG_AT32_OTGFS + /* Initialize USB if the 1) OTG FS controller is in the configuration and + * 2) disabled, and 3) the weak function at32_usbinitialize() has been + * brought into the build. Presumably either CONFIG_USBDEV or + * CONFIG_USBHOST is also selected. + */ + + at32_usbinitialize(); + +#endif + +#ifdef HAVE_NETMONITOR + /* Configure board resources to support networking. */ + + if (at32_netinitialize) + { + at32_netinitialize(); + } +#endif + +#ifdef CONFIG_ARCH_LEDS + /* Configure on-board LEDs if LED support has been selected. */ + + board_autoled_initialize(); +#endif +} + +/**************************************************************************** + * Name: board_late_initialize + * + * Description: + * If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional + * initialization call will be performed in the boot-up sequence to a + * function called board_late_initialize(). board_late_initialize() will be + * called immediately after up_initialize() is called and just before the + * initial application is started. This additional initialization phase + * may be used, for example, to initialize board-specific device drivers. + * + ****************************************************************************/ + +#ifdef CONFIG_BOARD_LATE_INITIALIZE +void board_late_initialize(void) +{ + /* Perform board-specific initialization */ + + at32_bringup(); +} +#endif diff --git a/boards/arm/at32/at32f437-mini/src/at32_bringup.c b/boards/arm/at32/at32f437-mini/src/at32_bringup.c new file mode 100644 index 0000000000..4f7ed92b9b --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_bringup.c @@ -0,0 +1,231 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_bringup.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "at32.h" +#include "../include/board.h" +#include "at32f437-mini.h" + +#ifdef HAVE_RTC_DRIVER +# include +# include "at32_rtc.h" +#endif + +#ifdef CONFIG_USERLED +# include +#endif + +/**************************************************************************** + * Name: at32_bringup + * + * Description: + * Perform architecture-specific initialization + * + * CONFIG_BOARD_LATE_INITIALIZE=y : + * Called from board_late_initialize(). + * + * CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y : + * Called from the NSH library + * + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +int at32_bringup(void) +{ + int ret = OK; + +#ifdef HAVE_RTC_DRIVER + struct rtc_lowerhalf_s *lower; +#endif + +#ifdef CONFIG_FS_PROCFS + /* Mount the procfs file system */ + + ret = nx_mount(NULL, AT32_PROCFS_MOUNTPOINT, "procfs", 0, NULL); + if (ret < 0) + { + serr("ERROR: Failed to mount procfs at %s: %d\n", + AT32_PROCFS_MOUNTPOINT, ret); + } +#endif + +#ifdef CONFIG_DEV_GPIO + at32_gpio_initialize(); +#endif + +#ifdef CONFIG_USERLED + /* Register the LED driver */ + + ret = userled_lower_initialize("/dev/userleds"); + if (ret < 0) + { + syslog(LOG_ERR, \ + "ERROR: userled_lower_initialize() failed: %d\n", ret); + } +#endif + +#ifdef HAVE_RTC_DRIVER + /* Instantiate the AT32 lower-half RTC driver */ + + lower = at32_rtc_lowerhalf(); + if (!lower) + { + serr("ERROR: Failed to instantiate the RTC lower-half driver\n"); + return -ENOMEM; + } + else + { + /* Bind the lower half driver and register the combined RTC driver + * as /dev/rtc0 + */ + + ret = rtc_initialize(0, lower); + if (ret < 0) + { + serr("ERROR: Failed to bind/register the RTC driver: %d\n", ret); + return ret; + } + } +#endif + +#ifdef CONFIG_AT32_IWDG + /* Initialize the watchdog timer */ + + at32_iwdginitialize("/dev/watchdog0", AT32_LSI_FREQUENCY); +#endif + +#ifdef CONFIG_MTD_W25 + /* Initialize and register the W25 FLASH file system. */ + + ret = at32_w25initialize(W25QXX_FLASH_MINOR); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize W25 minor %d: %d\n", + W25QXX_FLASH_MINOR, ret); + return ret; + } +#endif + +#ifdef CONFIG_AT32_CAN_CHARDRIVER + /* Initialize CAN and register the CAN driver. */ +#if defined(CONFIG_AT32_CAN1) + ret = at32_can_setup(1); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: at32_can_setup can1 failed: %d\n", ret); + } +#endif + +#endif + +#ifdef CONFIG_AT32_CAN_SOCKET + /* Initialize CAN socket interface */ +#if defined(CONFIG_AT32_CAN1) + ret = at32_cansock_setup(1); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: at32_cansock_setup failed: %d\n", ret); + } +#endif + +#endif + +#ifdef HAVE_USBHOST + ret = at32_usbhost_initialize(); + if (ret != OK) + { + uerr("ERROR: Failed to initialize USB host: %d\n", ret); + return ret; + } +#endif + +#ifdef CONFIG_AT32_SDIO + /* Initialize the SDIO block driver */ + + ret = at32_sdinitialize(0); + if (ret != OK) + { + syslog(LOG_ERR, \ + "ERROR: Failed to initialize MMC/SD driver: %d\n", ret); + } +#endif + +#ifdef CONFIG_AT32_PWM + /* Initialize PWM and register the PWM device. */ + + ret = at32_pwm_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: at32_pwm_setup() failed: %d\n", ret); + } +#endif + +#if defined(CONFIG_AT32_TIM) && defined(CONFIG_TIMER) + /* Initialize TIM and register the TIM device. */ + + ret = at32_timer_driver_setup("/dev/timer0", AT32F437_MINI_TIMER); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: timer setup failed: %d\n", ret); + } +#endif + +#ifdef CONFIG_AT32_ADC + /* Initialize ADC and register the ADC device. */ + + ret = at32_adc_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: at32_adc_setup() failed: %d\n", ret); + } +#endif + +#ifdef CONFIG_MTD_AT24XX + /* Initialize the AT24 driver */ + + ret = at32_at24_automount(AT24_MINOR); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: at32_at24_automount() failed: %d\n", ret); + return ret; + } +#endif + + return ret; +} diff --git a/boards/arm/at32/at32f437-mini/src/at32_can.c b/boards/arm/at32/at32f437-mini/src/at32_can.c new file mode 100644 index 0000000000..1d131b7cfc --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_can.c @@ -0,0 +1,102 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_can.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "chip.h" +#include "arm_internal.h" +#include "at32.h" +#include "at32_can.h" +#include "at32f437-mini.h" + +#include + +#ifdef CONFIG_CAN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#if !defined(CONFIG_AT32_CAN1) && !defined(CONFIG_AT32_CAN2) +#warning "Both CAN1 and CAN2 are not enabled." +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_can_setup + * + * Description: + * Initialize CAN and register the CAN device + * + ****************************************************************************/ + +int at32_can_setup(int port) +{ +#if defined(CONFIG_AT32_CAN1) || defined(CONFIG_AT32_CAN2) + struct can_dev_s *can; + int ret; + char device_name[16]; + + if ((port > 2) || (port < 1)) + return -ENODEV; + + /* Call at32_caninitialize() to get an instance of the CAN interface */ + + can = at32_caninitialize(port); + + if (can == NULL) + { + canerr("ERROR: Failed to get CAN interface\n"); + return -ENODEV; + } + + /* Register the CAN driver at "/dev/can0" */ + + sprintf(device_name, "/dev/can%d", port - 1); + + ret = can_register(device_name, can); + if (ret < 0) + { + canerr("ERROR: can_register failed: %d\n", ret); + return ret; + } + + return OK; +#else + return -ENODEV; +#endif +} + +#endif /* CONFIG_CAN */ diff --git a/boards/arm/at32/at32f437-mini/src/at32_cansock.c b/boards/arm/at32/at32f437-mini/src/at32_cansock.c new file mode 100644 index 0000000000..66c3c04a7c --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_cansock.c @@ -0,0 +1,58 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_cansock.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "at32_can.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_cansock_setup + * + * Description: + * Initialize CAN socket interface + * + ****************************************************************************/ + +int at32_cansock_setup(int port) +{ + int ret; + + /* Call at32_caninitialize() to get an instance of the CAN interface */ + + ret = at32_cansockinitialize(port); + if (ret < 0) + { + canerr("ERROR: Failed to get CAN %d interface %d\n", port, ret); + + return ret; + } + + return OK; +} diff --git a/boards/arm/at32/at32f437-mini/src/at32_ethernet.c b/boards/arm/at32/at32f437-mini/src/at32_ethernet.c new file mode 100644 index 0000000000..8795e890fc --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_ethernet.c @@ -0,0 +1,240 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_ethernet.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/* Force verbose debug on in this file only to support unit-level testing. */ + +#ifdef CONFIG_NETDEV_PHY_DEBUG +# undef CONFIG_DEBUG_INFO +# define CONFIG_DEBUG_INFO 1 +# undef CONFIG_DEBUG_NET +# define CONFIG_DEBUG_NET 1 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "at32_gpio.h" +#include "at32_eth.h" + +#include "at32f437-mini.h" + +#if defined(CONFIG_AT32_ETHMAC) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define AT32_ETHMAC_DEVNAME "eth0" + +#undef HAVE_NETMONITOR + +/* Debug ********************************************************************/ + +/* Extra, in-depth debug output that is only available if + * CONFIG_NETDEV_PHY_DEBUG us defined. + */ + +#ifdef CONFIG_NETDEV_PHY_DEBUG +# define phyerr _err +# define phywarn _warn +# define phyinfo _info +#else +# define phyerr(x...) +# define phywarn(x...) +# define phyinfo(x...) +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef HAVE_NETMONITOR +static xcpt_t g_ethmac_handler; +static void *g_ethmac_arg; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_emac0_phy_enable + ****************************************************************************/ + +#ifdef HAVE_NETMONITOR +static void at32_emac0_phy_enable(bool enable) +{ + phyinfo("enable=%d\n", enable); + if (enable && g_ethmac_handler != NULL) + { + /* Attach and enable GPIO interrupt (and event) on the falling edge */ + + at32_gpiosetevent(GPIO_EMAC_NINT, false, true, true, + g_ethmac_handler, g_ethmac_arg); + } + else + { + /* Detach and disable GPIO interrupt */ + + at32_gpiosetevent(GPIO_EMAC_NINT, false, false, false, + NULL, NULL); + } +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_netinitialize + * + * Description: + * Configure board resources to support networking. + * + ****************************************************************************/ + +void at32_netinitialize(void) +{ +#ifdef HAVE_NETMONITOR + /* Configure the PHY interrupt GPIO */ + + phyinfo("Configuring %08x\n", GPIO_EMAC_NINT); + at32_configgpio(GPIO_EMAC_NINT); +#endif + + /* Configure PHY /RESET output */ + + at32_configgpio(GPIO_EMAC_NRST); +} + +/**************************************************************************** + * Name: arch_phy_irq + * + * Description: + * This function may be called to register an interrupt handler that will + * be called when a PHY interrupt occurs. This function both attaches + * the interrupt handler and enables the interrupt if 'handler' is non- + * NULL. If handler is NULL, then the interrupt is detached and disabled + * instead. + * + * The PHY interrupt is always disabled upon return. The caller must + * call back through the enable function point to control the state of + * the interrupt. + * + * This interrupt may or may not be available on a given platform depending + * on how the network hardware architecture is implemented. In a typical + * case, the PHY interrupt is provided to board-level logic as a GPIO + * interrupt (in which case this is a board-specific interface and really + * should be called board_phy_irq()); In other cases, the PHY interrupt + * may be cause by the chip's MAC logic (in which case arch_phy_irq()) is + * an appropriate name. Other other boards, there may be no PHY interrupts + * available at all. If client attachable PHY interrupts are available + * from the board or from the chip, then CONFIG_ARCH_PHY_INTERRUPT should + * be defined to indicate that fact. + * + * Typical usage: + * a. OS service logic (not application logic*) attaches to the PHY + * PHY interrupt and enables the PHY interrupt. + * b. When the PHY interrupt occurs: (1) the interrupt should be + * disabled and () work should be scheduled on the worker thread (or + * perhaps a dedicated application thread). + * c. That worker thread should use the SIOCGMIIPHY, SIOCGMIIREG, + * and SIOCSMIIREG ioctl calls** to communicate with the PHY, + * determine what network event took place (Link Up/Down?), and + * take the appropriate actions. + * d. It should then interact the PHY to clear any pending + * interrupts, then re-enable the PHY interrupt. + * + * * This is an OS internal interface and should not be used from + * application space. Rather applications should use the SIOCMIISIG + * ioctl to receive a signal when a PHY event occurs. + * ** This interrupt is really of no use if the Ethernet MAC driver + * does not support these ioctl calls. + * + * Input Parameters: + * intf - Identifies the network interface. For example "eth0". Only + * useful on platforms that support multiple Ethernet interfaces + * and, hence, multiple PHYs and PHY interrupts. + * handler - The client interrupt handler to be invoked when the PHY + * asserts an interrupt. Must reside in OS space, but can + * signal tasks in user space. A value of NULL can be passed + * in order to detach and disable the PHY interrupt. + * arg - The argument that will accompany the interrupt + * enable - A function pointer that be unused to enable or disable the + * PHY interrupt. + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * failure. + * + ****************************************************************************/ + +#ifdef HAVE_NETMONITOR +int arch_phy_irq(const char *intf, xcpt_t handler, void *arg, + phy_enable_t *enable) +{ + phy_enable_t enabler; + irqstate_t flags; + + ninfo("%s: handler=%p\n", intf, handler); + phyinfo("ETHMAC: devname=%s\n", AT32_ETHMAC_DEVNAME); + + DEBUGASSERT(intf); + + flags = enter_critical_section(); + + if (strcmp(intf, AT32_ETHMAC_DEVNAME) == 0) + { + phyinfo("Select ETHMAC\n"); + g_ethmac_handler = handler; + g_ethmac_arg = arg; + enabler = at32_emac0_phy_enable; + } + else + { + nerr("ERROR: Unsupported interface: %s\n", intf); + enabler = NULL; + } + + if (enable) + { + *enable = enabler; + } + + leave_critical_section(flags); + return OK; +} +#endif + +#endif /* CONFIG_AT32_ETHMAC */ diff --git a/boards/arm/at32/at32f437-mini/src/at32_gpio.c b/boards/arm/at32/at32f437-mini/src/at32_gpio.c new file mode 100644 index 0000000000..6fe0fd13e9 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_gpio.c @@ -0,0 +1,322 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_gpio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "chip.h" +#include "at32_gpio.h" +#include "at32f437-mini.h" + +#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct at32gpio_dev_s +{ + struct gpio_dev_s gpio; + uint8_t id; +}; + +struct at32gpint_dev_s +{ + struct at32gpio_dev_s at32gpio; + pin_interrupt_t callback; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int gpin_read(struct gpio_dev_s *dev, bool *value); +static int gpout_read(struct gpio_dev_s *dev, bool *value); +static int gpout_write(struct gpio_dev_s *dev, bool value); +static int gpint_read(struct gpio_dev_s *dev, bool *value); +static int gpint_attach(struct gpio_dev_s *dev, + pin_interrupt_t callback); +static int gpint_enable(struct gpio_dev_s *dev, bool enable); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct gpio_operations_s gpin_ops = + { + .go_read = gpin_read, + .go_write = NULL, + .go_attach = NULL, + .go_enable = NULL, +}; + +static const struct gpio_operations_s gpout_ops = + { + .go_read = gpout_read, + .go_write = gpout_write, + .go_attach = NULL, + .go_enable = NULL, +}; + +static const struct gpio_operations_s gpint_ops = + { + .go_read = gpint_read, + .go_write = NULL, + .go_attach = gpint_attach, + .go_enable = gpint_enable, +}; + +/* This array maps the GPIO pins used as INPUT */ + +#if (BOARD_NGPIOIN > 0) +static const uint32_t g_gpioinputs[BOARD_NGPIOIN] = + { +#if 0 + GPIO_IN1, +#endif +}; + +static struct at32gpio_dev_s g_gpin[BOARD_NGPIOIN]; + +#endif + +/* This array maps the GPIO pins used as OUTPUT */ + +static const uint32_t g_gpiooutputs[BOARD_NGPIOOUT] = + { + GPIO_OUT1, +}; + +static struct at32gpio_dev_s g_gpout[BOARD_NGPIOOUT]; + +/* This array maps the GPIO pins used as INTERRUPT INPUTS */ + +static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] = + { +#if 0 + GPIO_INT1, +#endif +}; + +static struct at32gpint_dev_s g_gpint[BOARD_NGPIOINT]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int at32gpio_interrupt(int irq, void *context, void *arg) +{ + struct at32gpint_dev_s *at32gpint = + (struct at32gpint_dev_s *)arg; + + DEBUGASSERT(at32gpint != NULL && at32gpint->callback != NULL); + gpioinfo("Interrupt! callback=%p\n", at32gpint->callback); + + at32gpint->callback(&at32gpint->at32gpio.gpio, + at32gpint->at32gpio.id); + return OK; +} + +static int gpin_read(struct gpio_dev_s *dev, bool *value) +{ + struct at32gpio_dev_s *at32gpio = + (struct at32gpio_dev_s *)dev; + + DEBUGASSERT(at32gpio != NULL && value != NULL); + DEBUGASSERT(at32gpio->id < BOARD_NGPIOIN); + gpioinfo("Reading...\n"); + + *value = at32_gpioread(g_gpioinputs[at32gpio->id]); + return OK; +} + +static int gpout_read(struct gpio_dev_s *dev, bool *value) +{ + struct at32gpio_dev_s *at32gpio = + (struct at32gpio_dev_s *)dev; + + DEBUGASSERT(at32gpio != NULL && value != NULL); + DEBUGASSERT(at32gpio->id < BOARD_NGPIOOUT); + gpioinfo("Reading...\n"); + + *value = at32_gpioread(g_gpiooutputs[at32gpio->id]); + return OK; +} + +static int gpout_write(struct gpio_dev_s *dev, bool value) +{ + struct at32gpio_dev_s *at32gpio = + (struct at32gpio_dev_s *)dev; + + DEBUGASSERT(at32gpio != NULL); + DEBUGASSERT(at32gpio->id < BOARD_NGPIOOUT); + gpioinfo("Writing %d\n", (int)value); + + at32_gpiowrite(g_gpiooutputs[at32gpio->id], value); + return OK; +} + +static int gpint_read(struct gpio_dev_s *dev, bool *value) +{ + struct at32gpint_dev_s *at32gpint = + (struct at32gpint_dev_s *)dev; + + DEBUGASSERT(at32gpint != NULL && value != NULL); + DEBUGASSERT(at32gpint->at32gpio.id < BOARD_NGPIOINT); + gpioinfo("Reading int pin...\n"); + + *value = at32_gpioread(g_gpiointinputs[at32gpint->at32gpio.id]); + return OK; +} + +static int gpint_attach(struct gpio_dev_s *dev, + pin_interrupt_t callback) +{ + struct at32gpint_dev_s *at32gpint = + (struct at32gpint_dev_s *)dev; + + gpioinfo("Attaching the callback\n"); + + /* Make sure the interrupt is disabled */ + + at32_gpiosetevent(g_gpiointinputs[at32gpint->at32gpio.id], false, + false, false, NULL, NULL); + + gpioinfo("Attach %p\n", callback); + at32gpint->callback = callback; + return OK; +} + +static int gpint_enable(struct gpio_dev_s *dev, bool enable) +{ + struct at32gpint_dev_s *at32gpint = + (struct at32gpint_dev_s *)dev; + + if (enable) + { + if (at32gpint->callback != NULL) + { + gpioinfo("Enabling the interrupt\n"); + + /* Configure the interrupt for falling edge */ + + at32_gpiosetevent(g_gpiointinputs[at32gpint->at32gpio.id], + false, true, false, at32gpio_interrupt, + &g_gpint[at32gpint->at32gpio.id]); + } + } + else + { + gpioinfo("Disable the interrupt\n"); + at32_gpiosetevent(g_gpiointinputs[at32gpint->at32gpio.id], + false, false, false, NULL, NULL); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_gpio_initialize + * + * Description: + * Initialize GPIO drivers for use with /apps/examples/gpio + * + ****************************************************************************/ + +int at32_gpio_initialize(void) +{ + int i; + int pincount = 0; + +#if (BOARD_NGPIOIN > 0) + for (i = 0; i < BOARD_NGPIOIN; i++) + { + /* Setup and register the GPIO pin */ + + g_gpin[i].gpio.gp_pintype = GPIO_INPUT_PIN; + g_gpin[i].gpio.gp_ops = &gpin_ops; + g_gpin[i].id = i; + gpio_pin_register(&g_gpin[i].gpio, pincount); + + /* Configure the pin that will be used as input */ + + at32_configgpio(g_gpioinputs[i]); + + pincount++; + } +#endif + +#if (BOARD_NGPIOOUT > 0) + for (i = 0; i < BOARD_NGPIOOUT; i++) + { + /* Setup and register the GPIO pin */ + + g_gpout[i].gpio.gp_pintype = GPIO_OUTPUT_PIN; + g_gpout[i].gpio.gp_ops = &gpout_ops; + g_gpout[i].id = i; + gpio_pin_register(&g_gpout[i].gpio, pincount); + + /* Configure the pin that will be used as output */ + + at32_gpiowrite(g_gpiooutputs[i], 0); + at32_configgpio(g_gpiooutputs[i]); + + pincount++; + } +#endif + +#if (BOARD_NGPIOINT > 0) + for (i = 0; i < BOARD_NGPIOINT; i++) + { + /* Setup and register the GPIO pin */ + + g_gpint[i].at32gpio.gpio.gp_pintype = GPIO_INTERRUPT_PIN; + g_gpint[i].at32gpio.gpio.gp_ops = &gpint_ops; + g_gpint[i].at32gpio.id = i; + gpio_pin_register(&g_gpint[i].at32gpio.gpio, pincount); + + /* Configure the pin that will be used as interrupt input */ + + at32_configgpio(g_gpiointinputs[i]); + + pincount++; + } +#endif + + return 0; +} +#endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */ diff --git a/boards/arm/at32/at32f437-mini/src/at32_mmcsd.c b/boards/arm/at32/at32f437-mini/src/at32_mmcsd.c new file mode 100644 index 0000000000..e00c2c0c16 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_mmcsd.c @@ -0,0 +1,109 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_mmcsd.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "at32_sdio.h" +#include "at32f437-mini.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#define HAVE_MMCSD 1 /* Assume that we have SD support */ +#define AT32_MMCSDSLOTNO 0 /* There is only one slot */ + +/* Can't support MMC/SD features if the SDIO peripheral is disabled */ + +#ifndef CONFIG_AT32_SDIO +# undef HAVE_MMCSD +#endif + +/* Can't support MMC/SD features if mountpoints are disabled */ + +#ifdef CONFIG_DISABLE_MOUNTPOINT +# undef HAVE_MMCSD +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_sdinitialize + * + * Description: + * Initialize the SPI-based SD card. Requires CONFIG_DISABLE_MOUNTPOINT=n + * and CONFIG_AT32_SDIO=y + * + ****************************************************************************/ + +int at32_sdinitialize(int minor) +{ +#ifdef HAVE_MMCSD + struct sdio_dev_s *sdio; + int ret; + + /* First, get an instance of the SDIO interface */ + + sdio = sdio_initialize(AT32_MMCSDSLOTNO); + if (!sdio) + { + ferr("ERROR: Failed to initialize SDIO slot %d\n", AT32_MMCSDSLOTNO); + return -ENODEV; + } + + finfo("Initialized SDIO slot %d\n", AT32_MMCSDSLOTNO); + + /* Now bind the SDIO interface to the MMC/SD driver */ + + ret = mmcsd_slotinitialize(minor, sdio); + if (ret != OK) + { + ferr("ERROR:"); + ferr(" Failed to bind SDIO slot %d to the MMC/SD driver, minor=%d\n", + AT32_MMCSDSLOTNO, minor); + } + + finfo("Bound SDIO slot %d to the MMC/SD driver, minor=%d\n", + AT32_MMCSDSLOTNO, minor); + + /* Then let's guess and say that there is a card in the slot. + * I need to check to see if the M3 Wildfire board supports a GPIO to + * detect if there is a card in the slot. + */ + + sdio_mediachange(sdio, true); +#endif + return OK; +} diff --git a/boards/arm/at32/at32f437-mini/src/at32_pwm.c b/boards/arm/at32/at32f437-mini/src/at32_pwm.c new file mode 100644 index 0000000000..9645e3b392 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_pwm.c @@ -0,0 +1,107 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_pwm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include + +#include "chip.h" +#include "arm_internal.h" +#include "at32_pwm.h" +#include "at32f437-mini.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* PWM + * + * The at32f437-mini has no real on-board PWM devices + * + * PE2 TIM20_CH1 + * + */ + +#define HAVE_PWM 1 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_pwm_setup + * + * Description: + * Initialize PWM and register the PWM device. + * + ****************************************************************************/ + +int at32_pwm_setup(void) +{ +#ifdef HAVE_PWM + static bool initialized = false; + struct pwm_lowerhalf_s *pwm; + int ret; + + /* Have we already initialized? */ + + if (!initialized) + { + /* Call at32_pwminitialize() to get an instance of the PWM interface */ + + pwm = at32_pwminitialize(AT32F437_PWMTIMER); + if (!pwm) + { + aerr("ERROR: Failed to get the AT32 PWM lower half\n"); + return -ENODEV; + } + + /* Register the PWM driver at "/dev/pwm0" */ + + ret = pwm_register("/dev/pwm0", pwm); + if (ret < 0) + { + aerr("ERROR: pwm_register failed: %d\n", ret); + return ret; + } + + /* Now we are initialized */ + + initialized = true; + } + + return OK; +#else + return -ENODEV; +#endif +} diff --git a/boards/arm/at32/at32f437-mini/src/at32_spi.c b/boards/arm/at32/at32f437-mini/src/at32_spi.c new file mode 100644 index 0000000000..3574a5c829 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_spi.c @@ -0,0 +1,188 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_spi.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "arm_internal.h" +#include "chip.h" +#include "at32.h" +#include "at32f437-mini.h" + +#if defined(CONFIG_AT32_SPI1) || defined(CONFIG_AT32_SPI2) || \ +defined(CONFIG_AT32_SPI3)|| defined(CONFIG_AT32_SPI4) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_spidev_initialize + * + * Description: + * Called to configure SPI chip select GPIO pins for the HY-MiniAT32 + * board. + * + ****************************************************************************/ + +void at32_spidev_initialize(void) +{ + /* NOTE: Clocking for SPI1 and/or SPI2 was already provided in at32_rcc.c. + * Configurations of SPI pins is performed in at32_spi.c. + * Here, we only initialize chip select pins unique to the board + * architecture. + */ + +#ifdef CONFIG_MTD_W25 + at32_configgpio(FLASH_SPI1_CS); /* FLASH chip select */ +#endif +} + +/**************************************************************************** + * Name: at32_spi1/2select and at32_spi1/2status + * + * Description: + * The external functions, at32_spi1/2/3select and at32_spi1/2/3status + * must be provided by board-specific logic. They are implementations of + * the select and status methods of the SPI interface defined by struct + * spi_ops_s (see include/nuttx/spi/spi.h). All other methods (including + * at32_spibus_initialize()) are provided by common AT32 logic. + * To use this common SPI logic on your board: + * + * 1. Provide logic in at32_boardinitialize() to configure SPI chip select + * pins. + * 2. Provide at32_spi1/2/3select() and at32_spi1/2/3status() functions + * in your board-specific logic. These functions will perform chip + * selection and status operations using GPIOs in the way your board is + * configured. + * 3. Add a calls to at32_spibus_initialize() in your low level + * application initialization logic + * 4. The handle returned by at32_spibus_initialize() may then be used to + * bind the SPI driver to higher level logic (e.g., calling + * mmcsd_spislotinitialize(), for example, will bind the SPI driver to + * the SPI MMC/SD driver). + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SPI1 +void at32_spi1select(struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + switch (devid) + { + #ifdef CONFIG_MTD_W25 + case SPIDEV_FLASH(0): + at32_gpiowrite(FLASH_SPI1_CS, !selected); + break; + #endif + + default: + break; + } +} + +uint8_t at32_spi1status(struct spi_dev_s *dev, uint32_t devid) +{ + uint8_t status = 0; + + return status; +} +#endif + +#ifdef CONFIG_AT32_SPI2 +void at32_spi2select(struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ +} + +uint8_t at32_spi2status(struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} +#endif + +#ifdef CONFIG_AT32_SPI3 +void at32_spi3select(struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ +} + +uint8_t at32_spi3status(struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} +#endif + +#ifdef CONFIG_AT32_SPI4 +void at32_spi4select(struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ +} + +uint8_t at32_spi4status(struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} +#endif + +/**************************************************************************** + * Name: at32_spi1cmddata + * + * Description: + * Set or clear the SH1101A A0 or SD1306 D/C n bit to select data (true) + * or command (false). This function must be provided by platform-specific + * logic. This is an implementation of the cmddata method of the SPI + * interface defined by struct spi_ops_s (see include/nuttx/spi/spi.h). + * + * Input Parameters: + * + * spi - SPI device that controls the bus the device that requires the CMD/ + * DATA selection. + * devid - If there are multiple devices on the bus, this selects which one + * to select cmd or data. NOTE: This design restricts, for example, + * one one SPI display per SPI bus. + * cmd - true: select command; false: select data + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_CMDDATA +#ifdef CONFIG_AT32_SPI1 +int at32_spi1cmddata(struct spi_dev_s *dev, uint32_t devid, + bool cmd) +{ + return -ENODEV; +} +#endif +#endif + +#endif /* CONFIG_AT32_SPI1 || CONFIG_AT32_SPI2 */ diff --git a/boards/arm/at32/at32f437-mini/src/at32_timer.c b/boards/arm/at32/at32f437-mini/src/at32_timer.c new file mode 100644 index 0000000000..126b9aea52 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_timer.c @@ -0,0 +1,65 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_timer.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include + +#include "at32_tim.h" +#include "at32f437-mini.h" + +#ifdef CONFIG_AT32_TIM + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_timer_driver_setup + * + * Description: + * Configure the timer driver. + * + * Input Parameters: + * devpath - The full path to the timer device. + * This should be of the form /dev/timer0 + * timer - The timer's number. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int at32_timer_driver_setup(const char *devpath, int timer) +{ + return at32_timer_initialize(devpath, timer); +} + +#endif diff --git a/boards/arm/at32/at32f437-mini/src/at32_usb.c b/boards/arm/at32/at32f437-mini/src/at32_usb.c new file mode 100644 index 0000000000..e79c653663 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_usb.c @@ -0,0 +1,347 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_usb.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "arm_internal.h" +#include "at32.h" +#include "at32_otgfs.h" +#include "at32f437-mini.h" + +#ifdef CONFIG_AT32_OTGFS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_USBDEV) || defined(CONFIG_USBHOST) +# define HAVE_USB 1 +#else +# warning "CONFIG_AT32_OTGFS is enabled but neither CONFIG_USBDEV nor CONFIG_USBHOST" +# undef HAVE_USB +#endif + +#ifndef CONFIG_AT32F437_MINI_USBHOST_PRIO +# define CONFIG_AT32F437_MINI_USBHOST_PRIO 100 +#endif + +#ifndef CONFIG_AT32F437_MINI_USBHOST_STACKSIZE +# define CONFIG_AT32F437_MINI_USBHOST_STACKSIZE 2048 +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_USBHOST +static struct usbhost_connection_s *g_usbconn; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usbhost_waiter + * + * Description: + * Wait for USB devices to be connected. + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST +static int usbhost_waiter(int argc, char *argv[]) +{ + struct usbhost_hubport_s *hport; + + uinfo("Running\n"); + for (; ; ) + { + /* Wait for the device to change state */ + + DEBUGVERIFY(CONN_WAIT(g_usbconn, &hport)); + uinfo("%s\n", hport->connected ? "connected" : "disconnected"); + + /* Did we just become connected? */ + + if (hport->connected) + { + /* Yes.. enumerate the newly connected device */ + + CONN_ENUMERATE(g_usbconn, hport); + } + } + + /* Keep the compiler from complaining */ + + return 0; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_usbinitialize + * + * Description: + * Called from at32_usbinitialize very early in inialization to setup + * USB-related GPIO pins for the AT32F407_MINIvery board. + * + ****************************************************************************/ + +void at32_usbinitialize(void) +{ + /* The OTG FS has an internal soft pull-up. + * No GPIO configuration is required + */ + + /* Configure the OTG FS VBUS sensing GPIO, + * Power On, and Overcurrent GPIOs + */ + +#ifdef CONFIG_AT32_OTGFS + +#ifdef CONFIG_AT32_OTGFS_VBUS_CONTROL + at32_configgpio(GPIO_OTGFS_VBUS); + at32_configgpio(GPIO_OTGFS_PWRON); + at32_configgpio(GPIO_OTGFS_OVER); +#endif + +#endif +} + +/**************************************************************************** + * Name: at32_usbhost_initialize + * + * Description: + * Called at application startup time to initialize the USB host + * functionality. + * This function will start a thread that will monitor for device + * connection/disconnection events. + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST +int at32_usbhost_initialize(void) +{ + int ret; + + /* First, register all of the class drivers needed to support the drivers + * that we care about: + */ + + uinfo("Register class drivers\n"); + +#ifdef CONFIG_USBHOST_HUB + /* Initialize USB hub class support */ + + ret = usbhost_hub_initialize(); + if (ret < 0) + { + uerr("ERROR: usbhost_hub_initialize failed: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_MSC + /* Register the USB mass storage class class */ + + ret = usbhost_msc_initialize(); + if (ret != OK) + { + uerr("ERROR: Failed to register the mass storage class: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_CDCACM + /* Register the CDC/ACM serial class */ + + ret = usbhost_cdcacm_initialize(); + if (ret != OK) + { + uerr("ERROR: Failed to register the CDC/ACM serial class: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_HIDKBD + /* Initialize the HID keyboard class */ + + ret = usbhost_kbdinit(); + if (ret != OK) + { + uerr("ERROR: Failed to register the HID keyboard class\n"); + } +#endif + +#ifdef CONFIG_USBHOST_HIDMOUSE + /* Initialize the HID mouse class */ + + ret = usbhost_mouse_init(); + if (ret != OK) + { + uerr("ERROR: Failed to register the HID mouse class\n"); + } +#endif + +#ifdef CONFIG_USBHOST_XBOXCONTROLLER + /* Initialize the HID mouse class */ + + ret = usbhost_xboxcontroller_init(); + if (ret != OK) + { + uerr("ERROR: Failed to register the XBox Controller class\n"); + } +#endif + + /* Then get an instance of the USB host interface */ + + uinfo("Initialize USB host\n"); + g_usbconn = at32_otgfshost_initialize(0); + if (g_usbconn) + { + /* Start a thread to handle device connection. */ + + uinfo("Start usbhost_waiter\n"); + + ret = kthread_create("usbhost", CONFIG_AT32F437_MINI_USBHOST_PRIO, + CONFIG_AT32F437_MINI_USBHOST_STACKSIZE, + usbhost_waiter, NULL); + return ret < 0 ? -ENOEXEC : OK; + } + + return -ENODEV; +} +#endif + +/**************************************************************************** + * Name: at32_usbhost_vbusdrive + * + * Description: + * Enable/disable driving of VBUS 5V output. This function must be + * provided be each platform that implements the AT32 OTG FS host + * interface + * + * "On-chip 5 V VBUS generation is not supported. For this reason, a + * charge pump or, if 5 V are available on the application board, a + * basic power switch, must be added externally to drive the 5 V VBUS + * line. The external charge pump can be driven by any GPIO output. + * When the application decides to power on VBUS using the chosen GPIO, + * it must also set the port power bit in the host port control and + * status register (PPWR bit in OTG_FS_HPRT). + * + * "The application uses this field to control power to this port, + * and the core clears this bit on an overcurrent condition." + * + * Input Parameters: + * iface - For future growth to handle multiple USB host interface. + * Should be zero. + * enable - true: enable VBUS power; false: disable VBUS power + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST +void at32_usbhost_vbusdrive(int iface, bool enable) +{ + DEBUGASSERT(iface == 0); +#ifdef CONFIG_AT32_OTGFS_VBUS_CONTROL + if (enable) + { + /* Enable the Power Switch by driving the enable pin low */ + + at32_gpiowrite(GPIO_OTGFS_PWRON, false); + } + else + { + /* Disable the Power Switch by driving the enable pin high */ + + at32_gpiowrite(GPIO_OTGFS_PWRON, true); + } +#endif +} +#endif + +/**************************************************************************** + * Name: at32_setup_overcurrent + * + * Description: + * Setup to receive an interrupt-level callback if an overcurrent + * condition is detected. + * + * Input Parameters: + * handler - New overcurrent interrupt handler + * arg - The argument provided for the interrupt handler + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise, a negated errno value + * is returned to indicate the nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST +int at32_setup_overcurrent(xcpt_t handler, void *arg) +{ +#ifdef CONFIG_AT32_OTGFS_VBUS_CONTROL + return at32_gpiosetevent(GPIO_OTGFS_OVER, true, true, true, handler, arg); +#endif + + return 0; +} +#endif + +/**************************************************************************** + * Name: at32_usbsuspend + * + * Description: + * Board logic must provide the at32_usbsuspend logic if the USBDEV + * driver is used. This function is called whenever the USB enters or + * leaves suspend mode. This is an opportunity for the board logic to + * shutdown clocks, power, etc. while the USB is suspended. + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV +void at32_usbsuspend(struct usbdev_s *dev, bool resume) +{ + uinfo("resume: %d\n", resume); +} +#endif + +#endif /* CONFIG_AT32_OTGFS */ diff --git a/boards/arm/at32/at32f437-mini/src/at32_userleds.c b/boards/arm/at32/at32f437-mini/src/at32_userleds.c new file mode 100644 index 0000000000..c9587cd8e4 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_userleds.c @@ -0,0 +1,215 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_userleds.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include + +#include "chip.h" +#include "arm_internal.h" +#include "at32.h" +#include "at32f437-mini.h" + +#ifndef CONFIG_ARCH_LEDS + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This array maps an LED number to GPIO pin configuration */ + +static uint32_t g_ledcfg[BOARD_NLEDS] = +{ + GPIO_LED1, GPIO_LED2 +}; + +/**************************************************************************** + * Private Function Protototypes + ****************************************************************************/ + +/* LED Power Management */ + +#ifdef CONFIG_PM +static void led_pm_notify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +static int led_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_PM +static struct pm_callback_s g_ledscb = +{ + .notify = led_pm_notify, + .prepare = led_pm_prepare, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: led_pm_notify + * + * Description: + * Notify the driver of new power state. This callback is called after + * all drivers have had the opportunity to prepare for the new power state. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void led_pm_notify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + switch (pmstate) + { + case(PM_NORMAL): + { + /* Restore normal LEDs operation */ + + board_userled(BOARD_LED1, true); + } + break; + + case(PM_IDLE): + { + /* Entering IDLE mode - Turn leds off */ + + board_userled(BOARD_LED1, false); + } + break; + + case(PM_STANDBY): + { + /* Entering STANDBY mode - Logic for PM_STANDBY goes here */ + } + break; + + case(PM_SLEEP): + { + /* Entering SLEEP mode - Logic for PM_SLEEP goes here */ + } + break; + + default: + { + /* Should not get here */ + } + break; + } +} +#endif + +/**************************************************************************** + * Name: led_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a warning + * that the system is about to enter into a new power state. The driver + * should begin whatever operations that may be required to enter power + * state. The driver may abort the state change mode by returning a + * non-zero value from the callback function. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static int led_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + /* No preparation to change power modes is required by the LEDs driver. + * We always accept the state change by returning OK. + */ + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_userled_initialize + ****************************************************************************/ + +uint32_t board_userled_initialize(void) +{ + /* Configure LED1-2 GPIOs for output */ + + at32_configgpio(GPIO_LED1); + at32_configgpio(GPIO_LED2); + + return BOARD_NLEDS; +} + +/**************************************************************************** + * Name: board_userled + ****************************************************************************/ + +void board_userled(int led, bool ledon) +{ + if ((unsigned)led < BOARD_NLEDS) + { + at32_gpiowrite(g_ledcfg[led], ledon); + } +} + +/**************************************************************************** + * Name: board_userled_all + ****************************************************************************/ + +void board_userled_all(uint32_t ledset) +{ + at32_gpiowrite(GPIO_LED1, (ledset & BOARD_LED1_BIT) == 0); + at32_gpiowrite(GPIO_LED2, (ledset & BOARD_LED2_BIT) == 0); +} + +/**************************************************************************** + * Name: at32_led_pminitialize + ****************************************************************************/ + +#ifdef CONFIG_PM +void at32_led_pminitialize(void) +{ + /* Register to receive power management callbacks */ + + int ret = pm_register(&g_ledscb); + if (ret != OK) + { + board_autoled_on(LED_ASSERTION); + } +} +#endif /* CONFIG_PM */ + +#endif /* !CONFIG_ARCH_LEDS */ diff --git a/boards/arm/at32/at32f437-mini/src/at32_w25.c b/boards/arm/at32/at32f437-mini/src/at32_w25.c new file mode 100644 index 0000000000..7e5b40f9d5 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32_w25.c @@ -0,0 +1,281 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32_w25.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_AT32_SPI1 +#include +#include +#include +#include +#endif + +#include "at32_spi.h" + +#include "at32f437-mini.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Debug ********************************************************************/ + +/* Non-standard debug that may be enabled just for testing the watchdog + * timer + */ + +#define W25_SPI_PORT 1 + +/* Configuration ************************************************************/ + +/* Can't support the W25 device if it SPI1 or W25 support is not enabled */ + +#define HAVE_W25 1 +#if !defined(CONFIG_AT32_SPI1) || !defined(CONFIG_MTD_W25) +#undef HAVE_W25 +#endif + +/* Can't support W25 features if mountpoints are disabled */ + +#if defined(CONFIG_DISABLE_MOUNTPOINT) +#undef HAVE_W25 +#endif + +/* Can't support both FAT and SMARTFS */ + +#if defined(CONFIG_FS_FAT) && defined(CONFIG_FS_SMARTFS) +#warning "Can't support both FAT and SMARTFS -- using FAT" +#endif + +#define FLASH_PART_NAMES "w25qxx" + +#define FLASH_PART 1 + +#define FLASH_PART_LIST "4096, 4096, 4096" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_w25initialize + * + * Description: + * Initialize and register the W25 FLASH file system. + * + ****************************************************************************/ + +int at32_w25initialize(int minor) +{ + int ret; +#ifdef HAVE_W25 + struct spi_dev_s *spi; + struct mtd_dev_s *mtd; +#if defined(CONFIG_MTD_PARTITION_NAMES) + const char *partname = FLASH_PART_NAMES; +#endif + + /* Get the SPI port */ + + spi = at32_spibus_initialize(W25_SPI_PORT); + if (!spi) + { + syslog(LOG_ERR, "ERROR: Failed to initialize SPI port %d\n", + W25_SPI_PORT); + return -ENODEV; + } + + /* Now bind the SPI interface to the W25 SPI FLASH driver */ + + mtd = w25_initialize(spi); + if (!mtd) + { + syslog(LOG_ERR, "ERROR: Failed to bind SPI port %d to the Winbond" + "W25 FLASH driver\n", + W25_SPI_PORT); + return -ENODEV; + } + +#ifndef CONFIG_FS_SMARTFS + /* And use the FTL layer to wrap the MTD driver as a block driver */ + + ret = ftl_initialize(minor, mtd); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Initialize the FTL layer\n"); + return ret; + } +#else + /* Initialize to provide SMARTFS on the MTD interface */ + +#ifdef FLASH_PART +{ + int partno; + int partsize; + int partoffset; + int partszbytes; + int erasesize; + const char *partstring = FLASH_PART_LIST; + const char *ptr; + struct mtd_dev_s *mtd_part; + char partref[16]; + struct mtd_geometry_s geo; + + /* Now create a partition on the FLASH device */ + + partno = 0; + ptr = partstring; + partoffset = 0; + + /* Get the geometry of the FLASH device */ + + ret = mtd->ioctl(mtd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&geo)); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: mtd->ioctl failed: %d\n", ret); + return ret; + } + + /* Get the Flash erase size */ + + erasesize = geo.erasesize; + + while (*ptr != '\0') + { + /* Get the partition size */ + + partsize = atoi(ptr); + partszbytes = (partsize << 10); /* partsize is defined in KB */ + + /* Check if partition size is bigger then erase block */ + + if (partszbytes < erasesize) + { + syslog(LOG_ERR, + "ERROR: Partition size is lesser than erasesize!\n"); + return -1; + } + + /* Check if partition size is multiple of erase block */ + + if ((partszbytes % erasesize) != 0) + { + syslog(LOG_ERR, + "ERROR: Partition size isn't multiple of erasesize!\n"); + return -1; + } + + mtd_part = mtd_partition(mtd, partoffset, partszbytes / erasesize); + partoffset += partszbytes / erasesize; + +#ifdef FLASH_CONFIG_PART + /* Test if this is the config partition */ + + if (FLASH_CONFIG_PART_NUMBER == partno) + { + /* Register the partition as the config device */ + + mtdconfig_register(mtd_part); + } + else +#endif + { + /* Now initialize a SMART Flash block device and bind it + * to the MTD device. + */ + + #if defined(CONFIG_MTD_SMART) && defined(CONFIG_FS_SMARTFS) + snprintf(partref, sizeof(partref), "p%d", partno); + smart_initialize(W25QXX_FLASH_MINOR, + mtd_part, partref); + #endif + } + + /* Set the partition name */ + +#if defined(CONFIG_MTD_PARTITION_NAMES) + if (!mtd_part) + { + syslog(LOG_ERR, "Error: failed to create partition %s\n", + partname); + return -1; + } + + mtd_setpartitionname(mtd_part, partname); + + /* Now skip to next name. We don't need to split the string here + * because the MTD partition logic will only display names up to + * the comma, thus allowing us to use a single static name + * in the code. + */ + + while (*partname != ',' && *partname != '\0') + { + /* Skip to next ',' */ + + partname++; + } + + if (*partname == ',') + { + partname++; + } +#endif + + /* Update the pointer to point to the next size in the list */ + + while ((*ptr >= '0') && (*ptr <= '9')) + { + ptr++; + } + + if (*ptr == ',') + { + ptr++; + } + + /* Increment the part number */ + + partno++; + } +} + +#else /* CONFIG_FLASH_PART */ + + /* Configure the device with no partition support */ + + smart_initialize(W25QXX_FLASH_MINOR, mtd, NULL); + +#endif /* CONFIG_FLASH_PART */ +#endif /* CONFIG_FS_SMARTFS */ +#endif /* HAVE_W25 */ + + return OK; +} diff --git a/boards/arm/at32/at32f437-mini/src/at32f437-mini.h b/boards/arm/at32/at32f437-mini/src/at32f437-mini.h new file mode 100644 index 0000000000..6def42624f --- /dev/null +++ b/boards/arm/at32/at32f437-mini/src/at32f437-mini.h @@ -0,0 +1,458 @@ +/**************************************************************************** + * boards/arm/at32/at32f437-mini/src/at32f437-mini.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_AT32_AT32F437_MINI_SRC_AT32F437_MINI_H +#define __BOARDS_ARM_AT32_AT32F437_MINI_SRC_AT32F437_MINI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Assume that we have everything */ + +#define HAVE_USBDEV 1 +#define HAVE_USBHOST 1 +#define HAVE_USBMONITOR 0 +#define HAVE_SDIO 1 +#define HAVE_RTC_DRIVER 1 +#define HAVE_W25 1 + +/* Can't support USB host or device features if USB OTG FS is not enabled */ + +#ifndef CONFIG_AT32_OTGFS +# undef HAVE_USBDEV +# undef HAVE_USBHOST +#endif + +/* Can't support USB device if USB device is not enabled */ + +#ifndef CONFIG_USBDEV +# undef HAVE_USBDEV +#endif + +/* Can't support USB host is USB host is not enabled */ + +#ifndef CONFIG_USBHOST +# undef HAVE_USBHOST +#endif + +/* Check if we should enable the USB monitor before starting NSH */ + +#ifndef CONFIG_USBMONITOR +# undef HAVE_USBMONITOR +#endif + +#ifndef HAVE_USBDEV +# undef CONFIG_USBDEV_TRACE +#endif + +#ifndef HAVE_USBHOST +# undef CONFIG_USBHOST_TRACE +#endif + +#if !defined(CONFIG_USBDEV_TRACE) && !defined(CONFIG_USBHOST_TRACE) +# undef HAVE_USBMONITOR +#endif + +/* Can't support MMC/SD features if mountpoints are disabled or if SDIO + * support is not enabled. + */ + +#if defined(CONFIG_DISABLE_MOUNTPOINT) || !defined(CONFIG_AT32_SDIO) +# undef HAVE_SDIO +#endif + +#undef SDIO_MINOR /* Any minor number, default 0 */ +#define SDIO_SLOTNO 0 /* Only one slot */ + +#ifdef HAVE_SDIO +# if !defined(CONFIG_NSH_MMCSDSLOTNO) +# define CONFIG_NSH_MMCSDSLOTNO SDIO_SLOTNO +# elif CONFIG_NSH_MMCSDSLOTNO != 0 +# warning "Only one MMC/SD slot, slot 0" +# undef CONFIG_NSH_MMCSDSLOTNO +# define CONFIG_NSH_MMCSDSLOTNO SDIO_SLOTNO +# endif + +# if defined(CONFIG_NSH_MMCSDMINOR) +# define SDIO_MINOR CONFIG_NSH_MMCSDMINOR +# else +# define SDIO_MINOR 0 +# endif +#endif + +/* Check if we can support the RTC driver */ + +#if !defined(CONFIG_RTC) || !defined(CONFIG_RTC_DRIVER) +# undef HAVE_RTC_DRIVER +#endif + +/* procfs File System */ + +#ifdef CONFIG_FS_PROCFS +# ifdef CONFIG_NSH_PROC_MOUNTPOINT +# define AT32_PROCFS_MOUNTPOINT CONFIG_NSH_PROC_MOUNTPOINT +# else +# define AT32_PROCFS_MOUNTPOINT "/proc" +# endif +#endif + +/* Check if we have the prerequisites for an HCI UART */ + +#if !defined(CONFIG_AT32_HCIUART) || !defined(CONFIG_BLUETOOTH_UART) +# undef HAVE_HCIUART +#elif defined(CONFIG_AT32_USART1_HCIUART) +# define HCIUART_SERDEV HCIUART1 +#elif defined(CONFIG_AT32_USART2_HCIUART) +# define HCIUART_SERDEV HCIUART2 +#elif defined(CONFIG_AT32_USART3_HCIUART) +# define HCIUART_SERDEV HCIUART3 +#elif defined(CONFIG_AT32_USART6_HCIUART) +# define HCIUART_SERDEV HCIUART6 +#elif defined(CONFIG_AT32_UART7_HCIUART) +# define HCIUART_SERDEV HCIUART7 +#elif defined(CONFIG_AT32_UART8_HCIUART) +# define HCIUART_SERDEV HCIUART8 +#else +# error No HCI UART specifified +#endif + +/* AT32F4 Mini GPIOs ********************************************************/ + +#define BOARD_NGPIOIN 0 +#define BOARD_NGPIOOUT 1 +#define BOARD_NGPIOINT 0 + +#define GPIO_OUT1 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_DRV_MODETATE|\ + GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN2) +#define GPIO_IN1 +#define GPIO_INT1 + +/* LEDs */ + +#define GPIO_LED1 (GPIO_OUTPUT|GPIO_PUSHPULL|\ + GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN2) +#define GPIO_LED2 (GPIO_OUTPUT|GPIO_PUSHPULL|\ + GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN3) + +/* SPI1 W25QXX */ + +#define W25QXX_FLASH_MINOR 0 + +#define FLASH_SPI1_CS (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_DRV_MODETATE | \ + GPIO_OUTPUT_SET | GPIO_PORTD | GPIO_PIN7) + +/* ETH */ + +# define GPIO_EMAC_NINT (GPIO_INPUT|GPIO_PULLUP|GPIO_EXTI|\ + GPIO_PORTA|GPIO_PIN1) +# define GPIO_EMAC_NRST (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_DRV_MODETATE|\ + GPIO_OUTPUT_SET|GPIO_PORTA|GPIO_PIN3) + +/* PWM */ + +#define AT32F437_PWMTIMER 20 +#define AT32F437_PWMCHANNEL 1 + +/* TIMER */ + +#define AT32F437_MINI_TIMER 3 + +/* I2C */ + +#define AT24_I2C_BUS 3 /* AT24Cxx connected to I2C3 */ +#define AT24_MINOR 0 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: at32_bringup + * + * Description: + * Perform architecture-specific initialization + * + * CONFIG_BOARD_LATE_INITIALIZE=y : + * Called from board_late_initialize(). + * + * CONFIG_BOARD_LATE_INITIALIZE=y && CONFIG_BOARDCTL=y : + * Called from the NSH library + * + ****************************************************************************/ + +int at32_bringup(void); + +/**************************************************************************** + * Name: at32_spidev_initialize + * + * Description: + * Called to configure SPI chip select GPIO pins for the at32f437-mini + * board. + * + ****************************************************************************/ + +void weak_function at32_spidev_initialize(void); + +/**************************************************************************** + * Name: at32_i2sdev_initialize + * + * Description: + * Called to configure I2S chip select GPIO pins for the at32f437-mini + * board. + * + ****************************************************************************/ + +void weak_function at32_i2sdev_initialize(void); + +/**************************************************************************** + * Name: at32_usbinitialize + * + * Description: + * Called from at32_usbinitialize very early in initialization to setup + * USB-related GPIO pins for the at32f437-mini board. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_OTGFS +void weak_function at32_usbinitialize(void); +#endif + +/**************************************************************************** + * Name: at32_usbhost_initialize + * + * Description: + * Called at application startup time to initialize the USB host + * functionality. This function will start a thread that will monitor for + * device connection/disconnection events. + * + ****************************************************************************/ + +#if defined(CONFIG_AT32_OTGFS) && defined(CONFIG_USBHOST) +int at32_usbhost_initialize(void); +#endif + +/**************************************************************************** + * Name: at32_netinitialize + * + * Description: + * Configure board resources to support networking. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_ETHMAC +void weak_function at32_netinitialize(void); +#endif + +/**************************************************************************** + * Name: at32_gpio_initialize + * + * Description: + * Called to configure GPIO pins for the at32f437-mini + * board. + * + ****************************************************************************/ + +#ifdef CONFIG_DEV_GPIO +int at32_gpio_initialize(void); +#endif + +/**************************************************************************** + * Name: at32_spidev_initialize + * + * Description: + * Called to configure SPI chip select GPIO pins for the at32f437-mini + * board. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI +void at32_spidev_initialize(void); +#endif + +/**************************************************************************** + * Name: at32_w25initialize + * + * Description: + * Called to configure W25 for the at32f437-mini + * board. + * + ****************************************************************************/ + +#ifdef CONFIG_MTD_W25 +int at32_w25initialize(int minor); +#endif + +/**************************************************************************** + * Name: at32_can_setup + * + * Description: + * Called to configure can chardriver for the at32f437-mini + * board. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_CHARDRIVER +int at32_can_setup(int port); +#endif + +/**************************************************************************** + * Name: at32_cansock_setup + * + * Description: + * Called to configure can socket for the at32f437-mini + * board. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_CAN_SOCKET +int at32_cansock_setup(int port); +#endif + +/**************************************************************************** + * Name: at32_netinitialize + * + * Description: + * Called to configure eth net for the at32f437-mini + * board. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_ETHMAC +void at32_netinitialize(void); +#endif + +/**************************************************************************** + * Name: at32_sdinitialize + * + * Description: + * Called to configure sd card for the at32f437-mini + * board. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_SDIO +int at32_sdinitialize(int minor); +#endif + +/**************************************************************************** + * Name: at32_pwm_setup + * + * Description: + * Called to configure pwm for the at32f437-mini + * board. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_PWM +int at32_pwm_setup(void); +#endif + +/**************************************************************************** + * Name: at32_timer_driver_setup + * + * Description: + * Called to configure timer for the at32f437-mini + * board. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_TIM +int at32_timer_driver_setup(const char *devpath, int timer); +#endif + +/**************************************************************************** + * Name: at32_adc_setup + * + * Description: + * Called to configure adc for the at32f437-mini + * board. + * + ****************************************************************************/ + +#ifdef CONFIG_AT32_ADC +int at32_adc_setup(void); +#endif + +/**************************************************************************** + * Name: at32_at24_automount + * + * Description: + * Called to configure at24cxx for the at32f437-mini + * board. + * + ****************************************************************************/ + +#ifdef CONFIG_MTD_AT24XX +int at32_at24_automount(int minor); +#endif + +#ifdef CONFIG_USERLED + +/**************************************************************************** + * Name: board_userled_initialize + * + * Description: + * Called to configure user led for the at32f437-mini + * board. + * + ****************************************************************************/ + +uint32_t board_userled_initialize(void); + +#ifdef CONFIG_PM + +/**************************************************************************** + * Name: at32_led_pminitialize + * + * Description: + * Called to configure led pm for the at32f437-mini + * board. + * + ****************************************************************************/ + +void at32_led_pminitialize(void); +#endif + +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_AT32_AT32F437_MINI_SRC_AT32F437_MINI_H */ diff --git a/boards/arm/at32/at32f437-mini/tool/mkromfs.sh b/boards/arm/at32/at32f437-mini/tool/mkromfs.sh new file mode 100644 index 0000000000..5d97fc8d30 --- /dev/null +++ b/boards/arm/at32/at32f437-mini/tool/mkromfs.sh @@ -0,0 +1,11 @@ +#/bin/sh + + +genromfs -f romfs.img -d ../romfs -v -V "romfs" + +xxd -i romfs.img nsh_romfsimg.h + +cp nsh_romfsimg.h ../include + +rm romfs.img nsh_romfsimg.h +