diff --git a/arch/arm/soc/fsl_frdm_k64f/Kconfig b/arch/arm/soc/fsl_frdm_k64f/Kconfig index 202b46617e1..9e7ada45ee5 100644 --- a/arch/arm/soc/fsl_frdm_k64f/Kconfig +++ b/arch/arm/soc/fsl_frdm_k64f/Kconfig @@ -157,6 +157,9 @@ config GPIO config PINMUX def_bool y +config PWM + def_bool n + if GPIO config GPIO_K64 @@ -241,4 +244,11 @@ config PRESERVE_JTAG_IO_PINS endif #PINMUX +if PWM +config PWM_K64_FTM + def_bool y +config PWM_K64_FTM_0 + def_bool y +endif + endif diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index bb84c3273cc..70ba0614e3c 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -22,6 +22,10 @@ menuconfig PWM help Enable config options for PWM drivers. +################################################ +# PCA9685 +################################################ + config PWM_PCA9685 bool "PCA9685 I2C-based PWM chip" depends on PWM && I2C @@ -119,3 +123,482 @@ config PWM_DW_NUM_PORTS Specify how many PWM ports on the IP block. Default is 1. + +################################################ +# K64 Flex Timer Module (FTM) +################################################ + +config PWM_K64_FTM + bool "PWM with Freescale K64 Flex Timer Module (FTM)" + depends on PWM + default n + help + Enable Pulse Width Modulation driver for Freescale + K64 Flex Timer Module (FTM). + +config PWM_K64_FTM_DEBUG + bool "Enable Debugging for pwm_ftm driver" + depends on PWM_K64_FTM + default n + help + Enable debugging for pwm_ftm driver. + +#### FTM0 ##### + +config PWM_K64_FTM_0 + bool "K64 FTM PWM Module 0" + depends on PWM_K64_FTM + default n + help + Enable config PWM options for FTM0 source module. + +config PWM_K64_FTM_0_DEV_NAME + string "K64 FTM PWM Module 0 Device Name" + depends on PWM_K64_FTM_0 + default "PWM_K64_FTM0" + help + Specify the device name for the FTM0 source module. + +config PWM_K64_FTM_0_REG_BASE + hex "K64 FTM0 Register Base Address" + depends on PWM_K64_FTM_0 + default 0x40038000 + help + Specify the memory mapped base address of FTM0. This is the address + of FTM0_SC which is the first register of the module + +config PWM_K64_FTM_0_PRESCALE + int "K64 FTM0 prescale value" + default 1 + depends on PWM_K64_FTM_0 + help + Specify the FTM timer prescale value. The valid values are + 1, 2, 4, 8, 16, 32, 64, or 128. + +config PWM_K64_FTM_0_PERIOD + int "K64 FTM0 period value" + default 65535 + depends on PWM_K64_FTM_0 + help + Specify the FTM0 PWM period in ticks + +menu "K64 FTM0 Clock Source" + +choice PWM_K64_FTM_0_CLOCK_SOURCE_CHOICE + prompt "Choose the K64 FTM0 clock source" + default PWM_K64_FTM_0_CLOCK_SOURCE_SYSTEM + +config PWM_K64_FTM_0_CLOCK_SOURCE_NONE + bool "No clock selected (FTM counter disable)" + +config PWM_K64_FTM_0_CLOCK_SOURCE_SYSTEM + bool "System clock" + +config PWM_K64_FTM_0_CLOCK_SOURCE_FIXED + bool "Fixed Frequency Clock" + +config PWM_K64_FTM_0_CLOCK_SOURCE_EXTERNAL + bool "External Clock" + +config PWM_K64_FTM_0_CLOCK_SOURCE_QUAD + bool "Quadrature Decoder" + +endchoice + +endmenu + +config PWM_K64_FTM_0_CLOCK_SOURCE + int + # Omit prompt to signify "hidden" option + default 0 if PWM_K64_FTM_0_CLOCK_SOURCE_NONE + default 1 if PWM_K64_FTM_0_CLOCK_SOURCE_SYSTEM + default 2 if PWM_K64_FTM_0_CLOCK_SOURCE_FIXED + default 3 if PWM_K64_FTM_0_CLOCK_SOURCE_EXTERNAL + default 4 if PWM_K64_FTM_0_CLOCK_SOURCE_QUAD + help + Specify K64 FTM0 clock source + +config PWM_K64_FTM_0_PHASE_ENABLE_0 + bool "FTM0 Enable Phase for channel 0" + depends on PWM_K64_FTM_0 + default n + help + Allow a phase offset on FTM0 channel 0. This configures + channels 0 and 1 to be in combine mode therefore + channel 1 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_K64_FTM_0_PHASE_ENABLE_2 + bool "FTM0 Enable Phase for channel 2" + depends on PWM_K64_FTM_0 + default n + help + Allow a phase offset on FTM0 channel 2. This configures + channels 2 and 3 to be in combine mode therefore + channel 3 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_K64_FTM_0_PHASE_ENABLE_4 + bool "FTM0 Enable Phase for channel 4" + depends on PWM_K64_FTM_0 + default n + help + Allow a phase offset on FTM0 channel 4. This configures + channels 4 and 5 to be in combine mode therefore + channel 5 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_K64_FTM_0_PHASE_ENABLE_6 + bool "FTM0 Enable Phase for channel 6" + depends on PWM_K64_FTM_0 + default n + help + Allow a phase offset on FTM0 channel 6. This configures + channels 6 and 7 to be in combine mode therefore + channel 7 is not valid as an output signal. + Note: phase is an unsupported feature. + +#### FTM1 ##### + +config PWM_K64_FTM_1 + bool "K64 FTM PWM Module 1" + depends on PWM_K64_FTM + default n + help + Enable config PWM options for FTM1 source module. + +config PWM_K64_FTM_1_DEV_NAME + string "K64 FTM PWM Module 1 Device Name" + depends on PWM_K64_FTM_1 + default "PWM_K64_FTM1" + help + Specify the device name for the FTM1 source module. + +config PWM_K64_FTM_1_REG_BASE + hex "K64 FTM1 Register Base Address" + depends on PWM_K64_FTM_1 + default 0x40039000 + help + Specify the memory mapped base address of FTM1. This is the address + of FTM1_SC which is the first register of the module + +config PWM_K64_FTM_1_PRESCALE + int "FTM1 prescale value" + default 1 + depends on PWM_K64_FTM_1 + help + Specify the FTM1 timer prescale value. The valid values are + 1, 2, 4, 8, 16, 32, 64, or 128 + +config PWM_K64_FTM_1_PERIOD + int "FTM1 period value" + default 65535 + depends on PWM_K64_FTM_1 + help + Specify the FTM1 PWM period in ticks + +menu "K64 FTM1 Clock Source" + +choice PWM_K64_FTM_1_CLOCK_SOURCE_CHOICE + prompt "Choose the FTM1 clock source" + default PWM_K64_FTM_1_CLOCK_SOURCE_SYSTEM + +config PWM_K64_FTM_1_CLOCK_SOURCE_NONE + bool "No clock selected (FTM counter disable)" + +config PWM_K64_FTM_1_CLOCK_SOURCE_SYSTEM + bool "System clock" + +config PWM_K64_FTM_1_CLOCK_SOURCE_FIXED + bool "Fixed Frequency Clock" + +config PWM_K64_FTM_1_CLOCK_SOURCE_EXTERNAL + bool "External Clock" + +config PWM_K64_FTM_1_CLOCK_SOURCE_QUAD + bool "Quadrature Decoder" + +endchoice + +endmenu + +config PWM_K64_FTM_1_CLOCK_SOURCE + int + # Omit prompt to signify "hidden" option + default 0 if PWM_K64_FTM_1_CLOCK_SOURCE_NONE + default 1 if PWM_K64_FTM_1_CLOCK_SOURCE_SYSTEM + default 2 if PWM_K64_FTM_1_CLOCK_SOURCE_FIXED + default 3 if PWM_K64_FTM_1_CLOCK_SOURCE_EXTERNAL + default 4 if PWM_K64_FTM_1_CLOCK_SOURCE_QUAD + help + Specify K64 FTM1 clock source + +config PWM_K64_FTM_1_PHASE_ENABLE_0 + bool "FTM1 Enable Phase for channel 0" + depends on PWM_K64_FTM_1 + default n + help + Allow a phase offset on FTM1 channel 0. This configures + channels 0 and 1 to be in combine mode therefore + channel 1 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_FTM_1_PHASE_ENABLE_2 + bool "FTM1 Enable Phase for channel 2" + depends on PWM_K64_FTM_1 + default n + help + Allow a phase offset on FTM1 channel 2. This configures + channels 2 and 3 to be in combine mode therefore + channel 3 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_FTM_1_PHASE_ENABLE_4 + bool "FTM1 Enable Phase for channel 4" + depends on PWM_K64_FTM_1 + default n + help + Allow a phase offset on FTM1 channel 4. This configures + channels 4 and 5 to be in combine mode therefore + channel 5 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_FTM_1_PHASE_ENABLE_6 + bool "FTM1 Enable Phase for channel 6" + depends on PWM_K64_FTM_1 + default n + help + Allow a phase offset on FTM1 channel 6. This configures + channels 6 and 7 to be in combine mode therefore + channel 7 is not valid as an output signal. + Note: phase is an unsupported feature. + +#### FTM2 ##### + +config PWM_K64_FTM_2 + bool "K64 FTM PWM Module 2" + depends on PWM_K64_FTM + default n + help + Enable config PWM options for FTM2 source module. + +config PWM_K64_FTM_2_DEV_NAME + string "K64 FTM PWM Module 2 Device Name" + depends on PWM_K64_FTM_2 + default "PWM_K64_FTM2" + help + Specify the device name for the FTM2 source module. + +config PWM_K64_FTM_2_REG_BASE + hex "K64 FTM2 Register Base Address" + depends on PWM_K64_FTM_2 + default 0x4003A000 + help + Specify the memory mapped base address of FTM2. This is the address + of FTM2_SC which is the first register of the module + +config PWM_K64_FTM_2_PRESCALE + int "FTM2 prescale value" + default 1 + depends on PWM_K64_FTM_2 + help + Specify the FTM2 timer prescale value. The valid values are + 1, 2, 4, 8, 16, 32, 64, or 128 + +config PWM_K64_FTM_2_PERIOD + int "FTM2 period value" + default 65535 + depends on PWM_K64_FTM_2 + help + Specify the FTM2 PWM period in ticks + +menu "K64 FTM2 Clock Source" + +choice PWM_K64_FTM_2_CLOCK_SOURCE_CHOICE + prompt "Choose the FTM2 clock source" + default PWM_K64_FTM_2_CLOCK_SOURCE_SYSTEM + +config PWM_K64_FTM_2_CLOCK_SOURCE_NONE + bool "No clock selected (FTM counter disable)" + +config PWM_K64_FTM_2_CLOCK_SOURCE_SYSTEM + bool "System clock" + +config PWM_K64_FTM_2_CLOCK_SOURCE_FIXED + bool "Fixed Frequency Clock" + +config PWM_K64_FTM_2_CLOCK_SOURCE_EXTERNAL + bool "External Clock" + +config PWM_K64_FTM_2_CLOCK_SOURCE_QUAD + bool "Quadrature Decoder" + +endchoice + +endmenu + +config PWM_K64_FTM_2_CLOCK_SOURCE + int + # Omit prompt to signify "hidden" option + default 0 if PWM_K64_FTM_2_CLOCK_SOURCE_NONE + default 1 if PWM_K64_FTM_2_CLOCK_SOURCE_SYSTEM + default 2 if PWM_K64_FTM_2_CLOCK_SOURCE_FIXED + default 3 if PWM_K64_FTM_2_CLOCK_SOURCE_EXTERNAL + default 4 if PWM_K64_FTM_2_CLOCK_SOURCE_QUAD + help + Specify K64 FTM2 clock source + +config PWM_K64_FTM_2_PHASE_ENABLE_0 + bool "FTM2 Enable Phase for channel 0" + depends on PWM_K64_FTM_2 + default n + help + Allow a phase offset on FTM2 channel 0. This configures + channels 0 and 1 to be in combine mode therefore + channel 1 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_K64_FTM_2_PHASE_ENABLE_2 + bool "FTM2 Enable Phase for channel 2" + depends on PWM_K64_FTM_2 + default n + help + Allow a phase offset on FTM2 channel 2. This configures + channels 2 and 3 to be in combine mode therefore + channel 3 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_K64_FTM_2_PHASE_ENABLE_4 + bool "FTM2 Enable Phase for channel 4" + depends on PWM_K64_FTM_2 + default n + help + Allow a phase offset on FTM2 channel 4. This configures + channels 4 and 5 to be in combine mode therefore + channel 5 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_K64_FTM_2_PHASE_ENABLE_6 + bool "FTM2 Enable Phase for channel 6" + depends on PWM_K64_FTM_2 + default n + help + Allow a phase offset on FTM2 channel 6. This configures + channels 6 and 7 to be in combine mode therefore + channel 7 is not valid as an output signal. + Note: phase is an unsupported feature. + +#### FTM3 ##### + +config PWM_K64_FTM_3 + bool "K64 FTM PWM Module 3" + depends on PWM_K64_FTM + default n + help + Enable config PWM options for K64 FTM3 source module. + +config PWM_K64_FTM_3_DEV_NAME + string "K64 FTM PWM Module 3 Device Name" + depends on PWM_K64_FTM_3 + default "PWM_K64_FTM3" + help + Specify the device name for the FTM3 source module. + +config PWM_K64_FTM_3_REG_BASE + hex "K64 FTM3 Register Base Address" + depends on PWM_K64_FTM_3 + default 0x400B9000 + help + Specify the memory mapped base address of FTM3. This is the address + of FTM3_SC which is the first register of the module + +config PWM_K64_FTM_3_PRESCALE + int "FTM3 prescale value" + default 3 + depends on PWM_K64_FTM_3 + help + Specify the FTM timer prescale value. The valid values are + 1, 2, 4, 8, 16, 32, 64, or 128 + +config PWM_K64_FTM_3_PERIOD + int "FTM3 period value" + default 65535 + depends on PWM_K64_FTM_3 + help + Specify the FTM3 PWM period in ticks + +menu "K64 FTM3 Clock Source" + +choice PWM_K64_FTM_3_CLOCK_SOURCE_CHOICE + prompt "Choose the FTM3 clock source" + default PWM_K64_FTM_3_CLOCK_SOURCE_SYSTEM + +config PWM_K64_FTM_3_CLOCK_SOURCE_NONE + bool "No clock selected (FTM counter disable)" + +config PWM_K64_FTM_3_CLOCK_SOURCE_SYSTEM + bool "System clock" + +config PWM_K64_FTM_3_CLOCK_SOURCE_FIXED + bool "Fixed Frequency Clock" + +config PWM_K64_FTM_3_CLOCK_SOURCE_EXTERNAL + bool "External Clock" + +config PWM_K64_FTM_3_CLOCK_SOURCE_QUAD + bool "Quadrature Decoder" + +endchoice + +endmenu + +config PWM_K64_FTM_3_CLOCK_SOURCE + int + # Omit prompt to signify "hidden" option + default 0 if PWM_K64_FTM_3_CLOCK_SOURCE_NONE + default 1 if PWM_K64_FTM_3_CLOCK_SOURCE_SYSTEM + default 2 if PWM_K64_FTM_3_CLOCK_SOURCE_FIXED + default 3 if PWM_K64_FTM_3_CLOCK_SOURCE_EXTERNAL + default 4 if PWM_K64_FTM_3_CLOCK_SOURCE_QUAD + help + Specify K64 FTM3 clock source + +config PWM_K64_FTM_3_PHASE_ENABLE_0 + bool "FTM3 Enable Phase for channel 0" + depends on PWM_K64_FTM_3 + default n + help + Allow a phase offset on FTM3 channel 0. This configures + channels 0 and 1 to be in combine mode therefore + channel 1 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_K64_FTM_3_PHASE_ENABLE_2 + bool "FTM3 Enable Phase for channel 2" + depends on PWM_K64_FTM_3 + default n + help + Allow a phase offset on FTM3 channel 2. This configures + channels 2 and 3 to be in combine mode therefore + channel 3 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_K64_FTM_3_PHASE_ENABLE_4 + bool "FTM3 Enable Phase for channel 4" + depends on PWM_K64_FTM_3 + default n + help + Allow a phase offset on FTM3 channel 4. This configures + channels 4 and 5 to be in combine mode therefore + channel 5 is not valid as an output signal. + Note: phase is an unsupported feature. + +config PWM_K64_FTM_3_PHASE_ENABLE_6 + bool "FTM3 Enable Phase for channel 6" + depends on PWM_K64_FTM_3 + default n + help + Allow a phase offset on FTM3 channel 6. This configures + channels 6 and 7 to be in combine mode therefore + channel 7 is not valid as an output signal. + Note: phase is an unsupported feature. diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index c83bbc621e2..2b20a9db5d4 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -5,3 +5,5 @@ ccflags-$(CONFIG_PWM_QMSI) += -I$(CONFIG_QMSI_INSTALL_PATH)/include obj-$(CONFIG_PWM_PCA9685) += pwm_pca9685.o obj-$(CONFIG_PWM_DW) += pwm_dw.o obj-$(CONFIG_PWM_QMSI) += pwm_qmsi.o +obj-$(CONFIG_PWM_K64_FTM) += pwm_k64_ftm.o + diff --git a/drivers/pwm/pwm_k64_ftm.c b/drivers/pwm/pwm_k64_ftm.c new file mode 100644 index 00000000000..70dddfa51ee --- /dev/null +++ b/drivers/pwm/pwm_k64_ftm.c @@ -0,0 +1,900 @@ +/* + * Copyright (c) 2016, Wind River Systems, Inc. + * + * Licensed 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. + */ + +/** + * @file PWM driver for Freescale K64 FlexTimer Module (FTM) + * + * This file implements Pulse Width Modulation using the Freescale FlexTimer + * Module (FTM). Basic functionality is implemented using edge-aligned PWM + * mode. More complex functionality such as non-zero phase is not supported + * since combined mode operation is not implemented. + * + * The following configuration options are supported. ("x" can be one of the + * following values: 0, 1, 2, or 3 representing one of the four FMT modules + * FTM0, FTM1, FTM2, or FTM3.) + * + * - CONFIG_PWM_K64_FTM_x_DEV_NAME: string representing the device name + * - CONFIG_PWM_K64_FTM_x_REG_BASE: the base address of FTM (FTMx_SC) + * - CONFIG_PWM_K64_FTM_x_PRESCALE: the clock prescaler value + * - CONFIG_PWM_K64_FTM_x_CLOCK_SOURCE: the clock source + * - CONFIG_PWM_K64_FTM_DEBUG: enable debug log output for the driver + * - CONFIG_STDOUT_CONSOLE: choose debug logs using printf of printk + * + * The following configuration options are not supported. These are place + * holders for future functionality + * + * - CONFIG_PWM_K64_FTM_x_PHASE_ENABLE_0 support non-zero phase on channel 0 + * - CONFIG_PWM_K64_FTM_x_PHASE_ENABLE_1 support non-zero phase on channel 1 + * - CONFIG_PWM_K64_FTM_x_PHASE_ENABLE_2 support non-zero phase on channel 2 + * - CONFIG_PWM_K64_FTM_x_PHASE_ENABLE_3 support non-zero phase on channel 3 + */ + +#include + +#include +#include +#include + +#include "pwm_k64_ftm.h" +#include + +/* + * Non-zero phase is not supported because combine mode is not yet + * implemented. + */ +#undef COMBINE_MODE_SUPPORT + +#ifndef CONFIG_PWM_K64_FTM_DEBUG +#define DBG(...) do { } while ((0)) +#else /* CONFIG_PWM_K64_FTM_DEBUG */ +#if defined(CONFIG_STDOUT_CONSOLE) +#include +#define DBG printf +#else +#include +#define DBG printk +#endif /* CONFIG_STDOUT_CONSOLE */ +#endif /* CONFIG_PWM_K64_FTM_DEBUG */ + +/* Maximum PWM outputs */ +#define MAX_PWM_OUT 8 + +/** + * @brief Enable the clock for the FTM subsystem + * + * This function must be called before writing to FTM registers. Failure to + * do so may result in bus fault. + * + * @param ftm_num index indicating which FTM + * + * @return DEV_OK if successful, failed otherwise + */ + +static int pwm_ftm_clk_enable(uint8_t ftm_num) +{ + + volatile struct K20_SIM *sim = + (volatile struct K20_SIM *)PERIPH_ADDR_BASE_SIM; /* sys integ. ctl */ + + if (ftm_num > 3) { + DBG("ERROR: Illegal FTM number (%d).\n" + " Cannot enable PWM clock\n", ftm_num); + return DEV_INVALID_CONF; + } + + /* enabling the FTM by setting one of the bits SIM_SCGC6[26:24] */ + + sim->scgc6 |= 1 << (24 + ftm_num); + + return DEV_OK; +} + + + +/** + * @brief Initial FTM configuration + * + * Initialize the FTM hardware based on configuration options. + * + * @param dev Device struct + * @param access_op Access operation (pin or port) + * @param channel The pwm channel number + * @param flags Device flags (unused) + * + * @return DEV_OK if successful, failed otherwise + */ + +static int pwm_ftm_configure(struct device *dev, int access_op, + uint32_t channel, int flags) +{ + int return_val = DEV_OK; + + uint32_t clock_source; + uint32_t prescale; + uint32_t polarity; + + uint32_t reg_val; + + + DBG("pwm_ftm_configure...\n"); + + const struct pwm_ftm_config * const config = + dev->config->config_info; + + ARG_UNUSED(access_op); + ARG_UNUSED(flags); + + /* enable the clock for the FTM subsystem */ + pwm_ftm_clk_enable(config->ftm_num); + + /* + * Initialize: + * clock source = x (system, fixed, external) from config + * prescaler divide-by x=(1,2,4,8,16,32,64,128) from config + * free-running count-up + * edge-aligned PWM mode + * pair: independent outputs + * polarity + + * no interrupt + */ + + /* + * PS[2:0] = prescale + * MOD = pulse width + */ + + clock_source = (config->clock_source & 0x3) << PWM_K64_FTM_SC_CLKS_SHIFT; + + if (clock_source == 0) { + DBG("Warning: no clock source. PWM is disabled\n"); + } + + + switch (config->prescale) { + case PWM_K64_FTM_PRESCALE_1: + prescale = PWM_K64_FTM_SC_PS_D1; + break; + + case PWM_K64_FTM_PRESCALE_2: + prescale = PWM_K64_FTM_SC_PS_D2; + break; + + case PWM_K64_FTM_PRESCALE_4: + prescale = PWM_K64_FTM_SC_PS_D4; + break; + + case PWM_K64_FTM_PRESCALE_8: + prescale = PWM_K64_FTM_SC_PS_D8; + break; + + case PWM_K64_FTM_PRESCALE_16: + prescale = PWM_K64_FTM_SC_PS_D16; + break; + + case PWM_K64_FTM_PRESCALE_32: + prescale = PWM_K64_FTM_SC_PS_D32; + break; + + case PWM_K64_FTM_PRESCALE_64: + prescale = PWM_K64_FTM_SC_PS_D64; + break; + + case PWM_K64_FTM_PRESCALE_128: + prescale = PWM_K64_FTM_SC_PS_D128; + break; + + default: + /* Illegal prescale value. Default to 1. */ + prescale = PWM_K64_FTM_SC_PS_D1; + return_val = DEV_INVALID_OP; + break; + } + + +#ifdef COMBINE_MODE_SUPPORT + /* Enable FTMEN=1 and set outputs to initial value */ + mode_reg_val = sys_read32(PWM_K64_FTM_MODE(config->reg_base)); + mode_reg_val |= PWM_K64_FTM_MODE_FTMEN | PWM_K64_FTM_MODE_INIT; + + DBG("pwm_ftm_configure sys_write32(0x%08x, 0x%08x)..\n", + mode_reg_val, PWM_K64_FTM_MODE(config->reg_base)); + + sys_write32(mode_reg_val, PWM_K64_FTM_MODE(config->reg_base)); + + /* Enable enhanced synchronization */ + + DBG("pwm_ftm_configure sys_write32(0x%08x, 0x%08x)..\n", + PWM_K64_FTM_SYNCONF_SYNCMODE|PWM_K64_FTM_SYNCONF_CNTINC, + PWM_K64_FTM_SYNCONF(config->reg_base)); + + sys_write32(PWM_K64_FTM_SYNCONF_SYNCMODE|PWM_K64_FTM_SYNCONF_CNTINC, + PWM_K64_FTM_SYNCONF(config->reg_base)); + +#endif /*COMBINE_MODE_SUPPORT*/ + + /* Configure: PS | CLKS | up-counter | disable TOF intr */ + reg_val = prescale | clock_source; + + DBG("pwm_ftm_configure sys_write32(0x%08x, 0x%08x)..\n", + reg_val, PWM_K64_FTM_SC(config->reg_base)); + + sys_write32(reg_val, PWM_K64_FTM_SC(config->reg_base)); + + DBG("pwm_ftm_configure sys_write32(0x%08x, 0x%08x)..\n", + config->period, PWM_K64_FTM_MOD(config->reg_base)); + + /* set MOD to max */ + sys_write32(config->period, PWM_K64_FTM_MOD(config->reg_base)); + + /* set channel control to edge-aligned */ + reg_val = PWM_K64_FTM_CNSC_MSB | PWM_K64_FTM_CNSC_ELSB; + + DBG("pwm_ftm_configure sys_write32(0x%08x, 0x%08x)..\n", + reg_val, PWM_K64_FTM_CNSC(config->reg_base, channel)); + + sys_write32(reg_val, PWM_K64_FTM_CNSC(config->reg_base, channel)); + + DBG("pwm_ftm_configure sys_read32 4..\n"); + + /* set polarity high for this channel */ + polarity = sys_read32(PWM_K64_FTM_POL(config->reg_base)); + polarity &= ~(1<reg_base)); + + sys_write32(polarity, PWM_K64_FTM_POL(config->reg_base)); + + return return_val; +} + + +/** + * @brief API call to set the on/off timer values + * + * @param dev Device struct + * @param access_op Access operation (pin or port) + * @param channel The pwm channel number + * @param on Timer count value for the start of the pulse on each cycle + * (must be 0) + * @param off Timer count value for the end of the pulse. After this, the + * signal will be off (low if positive polarity) for the rest of + * the cycle. + * + * @return DEV_OK if successful, failed otherwise + */ + +static int pwm_ftm_set_values(struct device *dev, int access_op, + uint32_t channel, uint32_t on, uint32_t off) +{ + const struct pwm_ftm_config * const config = + dev->config->config_info; + struct pwm_ftm_drv_data * const drv_data = + (struct pwm_ftm_drv_data * const)dev->driver_data; + + DBG("pwm_ftm_set_values (on=%d, off=%d)\n", on, off); + + uint32_t pwm_pair; + uint32_t combine; + + switch (access_op) { + case PWM_ACCESS_BY_PIN: + break; + case PWM_ACCESS_ALL: + return DEV_INVALID_OP; + default: + return DEV_INVALID_OP; + } + + /* If either ON and/or OFF > max ticks, treat PWM as 100%. + * If OFF value == 0, treat it as 0%. + * Otherwise, populate registers accordingly. + */ + + if ((on >= config->period) || (off >= config->period)) { + /* Fully on. Set to 100% */ + + DBG("pwm_ftm_set_values sys_write32(0x%08x, 0x%08x)..\n", + config->period, PWM_K64_FTM_CNV(config->reg_base, channel)); + + /* CnV = pulse width */ + sys_write32(config->period, PWM_K64_FTM_CNV(config->reg_base, channel)); + + } else if (off == 0) { + /* Fully off. Set to 0% */ + + DBG("pwm_ftm_set_values sys_write32(0x%08x, 0x%08x)..\n", + 0, PWM_K64_FTM_CNV(config->reg_base, channel)); + + /* CnV = 0 */ + sys_write32(0, PWM_K64_FTM_CNV(config->reg_base, channel)); + + } else { + + + /* if on != 0 then set to combine mode and pwm must be even */ + if (on != 0) { + +#ifdef COMBINE_MODE_SUPPORT + /* TODO should verify that the other channel is not in + * use in non-combine mode + */ + + + /* If phase != 0 enable combine mode */ + if (channel % 2 != 0) { + DBG("If Phase is non-zero pwm must be 0, 2, 4, 6.\n"); + return DEV_INVALID_CONF; + } + + DBG("Note: Enabling phase on pwm%d therefore " + "pwm%d is not valid for output\n", channel, channel+1); + + pwm_pair = channel / 2; + + /* verify that the pair is configured for non-zero phase */ + switch (pwm_pair) { + case 0: + if (!config->phase_enable0) { + DBG("Error: Phase capability must be enabled on FTM0\n"); + return DEV_INVALID_CONF; + } + break; + + case 1: + if (!config->phase_enable2) { + DBG("Error: Phase capability must be enabled on FTM2\n"); + return DEV_INVALID_CONF; + } + drv_data->phase[1] = on; + break; + + case 2: + if (!config->phase_enable4) { + DBG("Error: Phase capability must be enabled on FTM4\n"); + return DEV_INVALID_CONF; + } + break; + + case 3: + if (!config->phase_enable6) { + DBG("Error: Phase capability must be enabled on FTM0\n"); + return DEV_INVALID_CONF; + } + break; + + default: + return DEV_INVALID_CONF; + } + + drv_data->phase[pwm_pair] = on; + + combine = + sys_read32(PWM_K64_FTM_COMBINE(config->reg_base)); + combine |= 1 << (pwm_pair * 8); + + DBG("pwm_ftm_set_values sys_write32(0x%08x, 0x%08x)..\n", + combine, PWM_K64_FTM_COMBINE(config->reg_base)); + + sys_write32(combine, PWM_K64_FTM_COMBINE(config->reg_base)); + + DBG("pwm_ftm_set_values sys_write32(0x%08x, 0x%08x)..\n", + on, PWM_K64_FTM_CNV(config->reg_base, channel)); + + /* set the on value */ + sys_write32(on, PWM_K64_FTM_CNV(config->reg_base, channel)); + + DBG("pwm_ftm_set_values sys_write32(0x%08x, 0x%08x)..\n", + off, PWM_K64_FTM_CNV(config->reg_base, channel+1)); + + /* set the off value */ + sys_write32(off, PWM_K64_FTM_CNV(config->reg_base, channel+1)); +#else /*COMBINE_MODE_SUPPORT*/ + DBG("Error: \"on\" value must be zero. Phase is not supported\n"); + return DEV_INVALID_CONF; +#endif /*COMBINE_MODE_SUPPORT*/ + + } else { + + /* zero phase. No need to combine two channels. */ + + if (channel % 2 != 0) { + pwm_pair = (channel - 1) / 2; + } else { + pwm_pair = channel / 2; + } + + drv_data->phase[pwm_pair] = 0; + + combine = + sys_read32(PWM_K64_FTM_COMBINE(config->reg_base)); + combine &= ~(1 << (pwm_pair * 8)); + + DBG("pwm_ftm_set_values sys_write32(0x%08x, 0x%08x)..\n", + combine, PWM_K64_FTM_COMBINE(config->reg_base)); + + sys_write32(combine, PWM_K64_FTM_COMBINE(config->reg_base)); + + /* set the off value */ + + DBG("pwm_ftm_set_values sys_write32(0x%08x, 0x%08x)..\n", + off, PWM_K64_FTM_CNV(config->reg_base, channel)); + + sys_write32(off, PWM_K64_FTM_CNV(config->reg_base, channel)); + } + + } + + DBG("pwm_ftm_set_values done.\n"); + + return DEV_OK; +} + +/** + * @brief API call to set the duty cycle + * + * Duty cycle describes the percentage of time a signal is in the ON state. + * + * @param dev Device struct + * @param access_op Access operation (pin or port) + * @param channel The pwm channel number + * @param duty Percentage of time signal is on (value between 0 and 100) + * + * @return DEV_OK if successful, failed otherwise + */ + +static int pwm_ftm_set_duty_cycle(struct device *dev, int access_op, + uint32_t channel, uint8_t duty) +{ + uint32_t on, off; + + const struct pwm_ftm_config * const config = + dev->config->config_info; + struct pwm_ftm_drv_data * const drv_data = + (struct pwm_ftm_drv_data * const)dev->driver_data; + + ARG_UNUSED(access_op); + + DBG("pwm_ftm_set_duty_cycle...\n"); + + if (duty == 0) { + /* Turn off PWM */ + on = 0; + off = 0; + } else if (duty >= 100) { + /* Force PWM to be 100% */ + on = 0; + off = config->period + 1; + } else { + + on = 0; + + /* + * Set the "on" value to the phase offset if it was set by + * pwm_ftm_set_phase() + */ + + switch (channel) { + case 0: + if (config->phase_enable0) + on = drv_data->phase[0]; + break; + + case 2: + if (config->phase_enable2) + on = drv_data->phase[1]; + break; + + case 4: + if (config->phase_enable4) + on = drv_data->phase[2]; + break; + + case 6: + if (config->phase_enable6) + on = drv_data->phase[3]; + break; + + default: + break; + } + + + /* Calculate the timer value for when to stop the pulse */ + + off = on + config->period * duty / 100; + + DBG("pwm_ftm_set_duty_cycle on=%d, off=%d, " + "period=%d, duty=%d.\n", + on, off, config->period, duty); + + /* check for valid off value */ + if (off > config->period) + return DEV_INVALID_OP; + } + + return pwm_ftm_set_values(dev, access_op, channel, on, off); + + DBG("pwm_ftm_set_duty_cycle done.\n"); + +} + +/** + * @brief API call to set the phase + * + * Phase describes number of clock ticks of delay before the start of the + * pulse. The maximum count of the FTM timer is 65536 so the phase value is + * an integer from 0 to 65536. + * + * A non-zero phase value requires the timer pair to be set to combined mode + * so the odd-numbered (n+1) channel is not available for output + * + * Note: non-zero phase is not supported in this implementation + * + * @param dev Device struct + * @param access_op Access operation (pin or port) + * @param channel The pwm channel number + * @param phase Clock ticks of delay before start of the pulse (must be 0) + * + * @return DEV_OK if successful, failed otherwise + */ + +static int pwm_ftm_set_phase(struct device *dev, int access_op, + uint32_t channel, uint8_t phase) +{ + +#ifdef COMBINE_MODE_SUPPORT + const struct pwm_ftm_config * const config = + dev->config->config_info; + struct pwm_ftm_drv_data * const drv_data = + (struct pwm_ftm_drv_data * const)dev->driver_data; + + ARG_UNUSED(access_op); + + DBG("pwm_ftm_set_phase...\n"); + + if ((phase < 0) || (phase > config->period)) + return DEV_INVALID_OP; + + switch (channel) { + case 0: + if (!config->phase_enable0) + return DEV_INVALID_OP; + drv_data->phase[0] = phase; + break; + + case 2: + if (!config->phase_enable2) + return DEV_INVALID_OP; + drv_data->phase[1] = phase; + break; + + case 4: + if (!config->phase_enable4) + return DEV_INVALID_OP; + drv_data->phase[2] = phase; + break; + + case 6: + if (!config->phase_enable6) + return DEV_INVALID_OP; + drv_data->phase[3] = phase; + break; + + default: + /* channel must be 0, 2, 4, or 6 */ + return DEV_INVALID_OP; + } + + DBG("pwm_ftm_set_phase done.\n"); + + return DEV_OK; +#else /*COMBINE_MODE_SUPPORT*/ + + ARG_UNUSED(dev); + ARG_UNUSED(access_op); + ARG_UNUSED(channel); + ARG_UNUSED(phase); + + DBG("ERROR: non-zero phase is not supported.\n"); + + return DEV_INVALID_OP; +#endif /*COMBINE_MODE_SUPPORT*/ +} + +/** + * @brief API call to disable FTM + * + * This function simply sets the clock source to "no clock selected" thus + * disabling the FTM + * + * @param dev Device struct + * + * @return DEV_OK if successful, failed otherwise + */ + +static int pwm_ftm_suspend(struct device *dev) +{ + uint32_t reg_val; + + const struct pwm_ftm_config * const config = + dev->config->config_info; + + DBG("pwm_ftm_suspend...\n"); + + /* set clock source to "no clock selected" */ + + reg_val = sys_read32(PWM_K64_FTM_SC(config->reg_base)); + + reg_val &= ~PWM_K64_FTM_SC_CLKS_MASK; + + reg_val |= PWM_K64_FTM_SC_CLKS_DISABLE; + + sys_write32(reg_val, PWM_K64_FTM_SC(config->reg_base)); + + DBG("pwm_ftm_suspend done.\n"); + + return DEV_OK; + +} + +/** + * @brief API call to reenable FTM + * + * This function simply sets the clock source to the configuration value with + * the assumption that FTM was previously disabled by setting the clock source + * to "no clock selected" due to a call to pwm_ftm_suspend. + * + * @param dev Device struct + * + * @return DEV_OK if successful, failed otherwise + */ + +static int pwm_ftm_resume(struct device *dev) +{ + uint32_t clock_source; + uint32_t reg_val; + + /* set clock source to config value */ + + const struct pwm_ftm_config * const config = + dev->config->config_info; + + DBG("pwm_ftm_resume...\n"); + + clock_source = (config->clock_source << PWM_K64_FTM_SC_CLKS_SHIFT) && + PWM_K64_FTM_SC_CLKS_MASK; + + reg_val = sys_read32(PWM_K64_FTM_SC(config->reg_base)); + + reg_val &= ~PWM_K64_FTM_SC_CLKS_MASK; + + reg_val |= clock_source; + + sys_write32(reg_val, PWM_K64_FTM_SC(config->reg_base)); + + DBG("pwm_ftm_resume done.\n"); + + return DEV_OK; +} + +static struct pwm_driver_api pwm_ftm_drv_api_funcs = { + .config = pwm_ftm_configure, + .set_values = pwm_ftm_set_values, + .set_duty_cycle = pwm_ftm_set_duty_cycle, + .set_phase = pwm_ftm_set_phase, + .suspend = pwm_ftm_suspend, + .resume = pwm_ftm_resume, +}; + +/** + * @brief Initialization function of FTM + * + * @param dev Device struct + * @return DEV_OK if successful, failed otherwise. + */ +int pwm_ftm_init(struct device *dev) +{ + + DBG("pwm_ftm_init...\n"); + + dev->driver_api = &pwm_ftm_drv_api_funcs; + + return DEV_OK; +} + +/* Initialization for PWM_K64_FTM_0 */ +#ifdef CONFIG_PWM_K64_FTM_0 +#include +#include + +static struct pwm_ftm_config pwm_ftm_0_cfg = { + .ftm_num = 0, + .reg_base = CONFIG_PWM_K64_FTM_0_REG_BASE, + .prescale = CONFIG_PWM_K64_FTM_0_PRESCALE, + .clock_source = CONFIG_PWM_K64_FTM_0_CLOCK_SOURCE, + +#ifdef CONFIG_PWM_K64_FTM_0_PHASE_ENABLE_0 + .phase_enable0 = 1, +#else + .phase_enable0 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_0_PHASE_ENABLE_2 + .phase_enable2 = 1, +#else + .phase_enable2 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_0_PHASE_ENABLE_4 + .phase_enable4 = 1, +#else + .phase_enable4 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_0_PHASE_ENABLE_6 + .phase_enable6 = 1, +#else + .phase_enable6 = 0, +#endif + + .period = CONFIG_PWM_K64_FTM_0_PERIOD, +}; + +static struct pwm_ftm_drv_data pwm_ftm_0_drvdata; + +DEVICE_INIT(pwm_ftm_0, CONFIG_PWM_K64_FTM_0_DEV_NAME, pwm_ftm_init, + &pwm_ftm_0_drvdata, &pwm_ftm_0_cfg, + SECONDARY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +#endif /* CONFIG_PWM_K64_FTM_0 */ + +/* Initialization for PWM_K64_FTM_1 */ +#ifdef CONFIG_PWM_K64_FTM_1 +#include +#include + +static struct pwm_ftm_config pwm_ftm_1_cfg = { + .ftm_num = 1, + .reg_base = CONFIG_PWM_K64_FTM_1_REG_BASE, + .prescale = CONFIG_PWM_K64_FTM_1_PRESCALE, + .clock_source = CONFIG_PWM_K64_FTM_1_CLOCK_SOURCE, + +#ifdef CONFIG_PWM_K64_FTM_1_PHASE_ENABLE_0 + .phase_enable0 = 1, +#else + .phase_enable0 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_1_PHASE_ENABLE_2 + .phase_enable2 = 1, +#else + .phase_enable2 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_1_PHASE_ENABLE_4 + .phase_enable4 = 1, +#else + .phase_enable4 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_1_PHASE_ENABLE_6 + .phase_enable6 = 1, +#else + .phase_enable6 = 0, +#endif + +}; + +static struct pwm_ftm_drv_data pwm_ftm_1_drvdata; + +DEVICE_INIT(pwm_ftm_1, CONFIG_PWM_K64_FTM_1_DEV_NAME, pwm_ftm_init, + &pwm_ftm_1_drvdata, &pwm_ftm_1_cfg, + SECONDARY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +#endif /* CONFIG_PWM_K64_FTM_1 */ + + +/* Initialization for PWM_K64_FTM_2 */ +#ifdef CONFIG_PWM_K64_FTM_2 +#include +#include + +static struct pwm_ftm_config pwm_ftm_2_cfg = { + .ftm_num = 2, + .reg_base = CONFIG_PWM_K64_FTM_2_REG_BASE, + .prescale = CONFIG_PWM_K64_FTM_2_PRESCALE, + .clock_source = CONFIG_PWM_K64_FTM_2_CLOCK_SOURCE, + +#ifdef CONFIG_PWM_K64_FTM_2_PHASE_ENABLE_0 + .phase_enable0 = 1, +#else + .phase_enable0 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_2_PHASE_ENABLE_2 + .phase_enable2 = 1, +#else + .phase_enable2 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_2_PHASE_ENABLE_4 + .phase_enable4 = 1, +#else + .phase_enable4 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_2_PHASE_ENABLE_6 + .phase_enable6 = 1, +#else + .phase_enable6 = 0, +#endif + +}; + +static struct pwm_ftm_drv_data pwm_ftm_2_drvdata; + +DEVICE_INIT(pwm_ftm_2, CONFIG_PWM_K64_FTM_2_DEV_NAME, pwm_ftm_init, + &pwm_ftm_2_drvdata, &pwm_ftm_2_cfg, + SECONDARY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +#endif /* CONFIG_PWM_K64_FTM_2 */ + + +/* Initialization for PWM_K64_FTM_3 */ +#ifdef CONFIG_PWM_K64_FTM_3 +#include +#include + +static struct pwm_ftm_config pwm_ftm_3_cfg = { + .ftm_num = 3, + .reg_base = CONFIG_PWM_K64_FTM_3_REG_BASE, + .prescale = CONFIG_PWM_K64_FTM_3_PRESCALE, + .clock_source = CONFIG_PWM_K64_FTM_3_CLOCK_SOURCE, + +#ifdef CONFIG_PWM_K64_FTM_3_PHASE_ENABLE_0 + .phase_enable0 = 1, +#else + .phase_enable0 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_3_PHASE_ENABLE_2 + .phase_enable2 = 1, +#else + .phase_enable2 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_3_PHASE_ENABLE_4 + .phase_enable4 = 1, +#else + .phase_enable4 = 0, +#endif + +#ifdef CONFIG_PWM_K64_FTM_3_PHASE_ENABLE_6 + .phase_enable6 = 1, +#else + .phase_enable6 = 0, +#endif + +}; + +static struct pwm_ftm_drv_data pwm_ftm_3_drvdata; + +DEVICE_INIT(pwm_ftm_3, CONFIG_PWM_K64_FTM_3_DEV_NAME, pwm_ftm_init, + &pwm_ftm_3_drvdata, &pwm_ftm_3_cfg, + SECONDARY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +#endif /* CONFIG_PWM_K64_FTM_3 */ diff --git a/drivers/pwm/pwm_k64_ftm.h b/drivers/pwm/pwm_k64_ftm.h new file mode 100644 index 00000000000..25fa41d8cdf --- /dev/null +++ b/drivers/pwm/pwm_k64_ftm.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2016, Wind River Systems, Inc. + * + * Licensed 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. + */ + +/** + * @file Header file for the PWM driver for Freescale K64 FlexTimer Module (FTM) + */ + +#ifndef __PWM_K64_FTM_H__ +#define __PWM_K64_FTM_H__ + +#include + +/* Valid prescale values */ +#define PWM_K64_FTM_PRESCALE_1 1 +#define PWM_K64_FTM_PRESCALE_2 2 +#define PWM_K64_FTM_PRESCALE_4 4 +#define PWM_K64_FTM_PRESCALE_8 8 +#define PWM_K64_FTM_PRESCALE_16 16 +#define PWM_K64_FTM_PRESCALE_32 32 +#define PWM_K64_FTM_PRESCALE_64 64 +#define PWM_K64_FTM_PRESCALE_128 128 + +/* flags are not used. This value can be passed into pwm_pin_configure */ +#define PWM_K64_FTM_FLAG_NONE 0 + + +/* FTM register bit definitions */ + + +#define PWM_K64_FTM_SC(base) ((base)+0x00) /* Status And Control */ +#define PWM_K64_FTM_CNT(base) ((base)+0x04) /* Counter */ +#define PWM_K64_FTM_MOD(base) ((base)+0x08) /* Modulo */ + +#define PWM_K64_FTM_CNSC(base, ch) ((base)+0x0C+(ch)*8) /* Channel Status&Ctrl*/ +#define PWM_K64_FTM_CNV(base, ch) ((base)+0x10+(ch)*8) /* Channel Value */ + +#define PWM_K64_FTM_CNTIN(base) ((base)+0x4C) /* Counter Initial Value */ +#define PWM_K64_FTM_STATUS(base) ((base)+0x50) /* Capture And Compare Status*/ +#define PWM_K64_FTM_MODE(base) ((base)+0x54) /* Features Mode Selection */ +#define PWM_K64_FTM_SYNC(base) ((base)+0x58) /* Synchronization */ +#define PWM_K64_FTM_OUTINIT(base) ((base)+0x5C) /* Initial Channels Output */ +#define PWM_K64_FTM_OUTMASK(base) ((base)+0x60) /* Output Mask */ +#define PWM_K64_FTM_COMBINE(base) ((base)+0x64) /* Function For Linked Chans */ +#define PWM_K64_FTM_DEADTIME(base) ((base)+0x68) /* Deadtime Insertion Ctrl */ +#define PWM_K64_FTM_EXTTRIG(base) ((base)+0x6C) /* FTM External Trigger */ +#define PWM_K64_FTM_POL(base) ((base)+0x70) /* Channels Polarity */ +#define PWM_K64_FTM_FMS(base) ((base)+0x74) /* Fault Mode Status */ +#define PWM_K64_FTM_FILTER(base) ((base)+0x78) /* Input Capture Filter Ctrl */ +#define PWM_K64_FTM_FLTCTRL(base) ((base)+0x7C) /* Fault Control */ +#define PWM_K64_FTM_QDCTRL(base) ((base)+0x80) /* Quadrature Decoder Ctrl */ +#define PWM_K64_FTM_CONF(base) ((base)+0x84) /* Configuration */ +#define PWM_K64_FTM_FLTPOL(base) ((base)+0x88) /* FTM Fault Input Polarity */ +#define PWM_K64_FTM_SYNCONF(base) ((base)+0x8C) /* Synchronization Config */ +#define PWM_K64_FTM_INVCTRL(base) ((base)+0x90) /* FTM Inverting Control */ +#define PWM_K64_FTM_SWOCTRL(base) ((base)+0x94) /* FTM Software Output Ctrl */ +#define PWM_K64_FTM_PWMLOAD(base) ((base)+0x98) /* FTM PWM Load */ + +/* PWM_K64_FTM_SC Status And Control */ + +#define PWM_K64_FTM_SC_CLKS_MASK 0x18 +#define PWM_K64_FTM_SC_CLKS_SHIFT 3 + +#define PWM_K64_FTM_SC_CLKS_DISABLE 0x0 +#define PWM_K64_FTM_SC_CLKS_SYSTEM 0x1 +#define PWM_K64_FTM_SC_CLKS_FIXED 0x2 +#define PWM_K64_FTM_SC_CLKS_EXTERNAL 0x3 + +#define PWM_K64_FTM_SC_PS_D1 (0x0<<0) +#define PWM_K64_FTM_SC_PS_D2 (0x1<<0) +#define PWM_K64_FTM_SC_PS_D4 (0x2<<0) +#define PWM_K64_FTM_SC_PS_D8 (0x3<<0) +#define PWM_K64_FTM_SC_PS_D16 (0x4<<0) +#define PWM_K64_FTM_SC_PS_D32 (0x5<<0) +#define PWM_K64_FTM_SC_PS_D64 (0x6<<0) +#define PWM_K64_FTM_SC_PS_D128 (0x7<<0) + +#define PWM_K64_FTM_SC_PS_MASK (0x7<<0) + +/* PWM_K64_FTM_CNSC (FTMx_CnSC) Channel-n Status And Control */ +#define PWM_K64_FTM_CNSC_DMA (0x1<<0) +#define PWM_K64_FTM_CNSC_ELSA (0x1<<2) +#define PWM_K64_FTM_CNSC_ELSB (0x1<<3) +#define PWM_K64_FTM_CNSC_MSA (0x1<<4) +#define PWM_K64_FTM_CNSC_MSB (0x1<<5) +#define PWM_K64_FTM_CNSC_CHIE (0x1<<6) +#define PWM_K64_FTM_CNSC_CHF (0x1<<7) + +/* PWM_K64_FTM_MODE Features Mode Selection */ +#define PWM_K64_FTM_MODE_FTMEN (0x1<<0) +#define PWM_K64_FTM_MODE_INIT (0x1<<1) +#define PWM_K64_FTM_MODE_WPDIS (0x1<<2) +#define PWM_K64_FTM_MODE_PWMSYNC (0x1<<3) +#define PWM_K64_FTM_MODE_CAPTEST (0x1<<4) + +#define PWM_K64_FTM_MODE_FAULTM_DISABLE (0x0<<5) +#define PWM_K64_FTM_MODE_FAULTM_EVEN (0x1<<5) +#define PWM_K64_FTM_MODE_FAULTM_MANUAL (0x2<<5) +#define PWM_K64_FTM_MODE_FAULTM_AUTO (0x3<<5) +#define PWM_K64_FTM_MODE_FAULTM_MASK (0x3<<5) + +#define PWM_K64_FTM_MODE_FAULTIE (0x1<<7) + +/* PWM_K64_FTM_SYNC PWM Synchronization */ +#define PWM_K64_FTM_SYNC_CNTMIN (0x1<<0) +#define PWM_K64_FTM_SYNC_CNTMAX (0x1<<1) +#define PWM_K64_FTM_SYNC_REINIT (0x1<<2) +#define PWM_K64_FTM_SYNC_SYNCHOM (0x1<<3) +#define PWM_K64_FTM_SYNC_TRIG0 (0x1<<4) +#define PWM_K64_FTM_SYNC_TRIG1 (0x1<<5) +#define PWM_K64_FTM_SYNC_TRIG2 (0x1<<6) +#define PWM_K64_FTM_SYNC_SWSYNC (0x1<<7) + +/* PWM_K64_FTM_EXTTRIG FTM External Trigger */ +#define PWM_K64_FTM_EXTTRIG_CH2TRIG (0x1<<0) +#define PWM_K64_FTM_EXTTRIG_CH3TRIG (0x1<<1) +#define PWM_K64_FTM_EXTTRIG_CH4TRIG (0x1<<2) +#define PWM_K64_FTM_EXTTRIG_CH5TRIG (0x1<<3) +#define PWM_K64_FTM_EXTTRIG_CH0TRIG (0x1<<4) +#define PWM_K64_FTM_EXTTRIG_CH1TRIG (0x1<<5) +#define PWM_K64_FTM_EXTTRIG_INTTRIGEN (0x1<<6) +#define PWM_K64_FTM_EXTTRIG_TRIGF (0x1<<7) + +/* PWM_K64_FTM_QDCTRL Quadrature Decoder Ctrl&Status */ +#define PWM_K64_FTM_QDCTRL_QUADEN (0x1<<0) + +/* PWM_K64_FTM_SYNCONF Syncronization Configuration */ +#define PWM_K64_FTM_SYNCONF_HWTRIGMODE (0x1<<0) +#define PWM_K64_FTM_SYNCONF_CNTINC (0x1<<2) +#define PWM_K64_FTM_SYNCONF_INVC (0x1<<4) +#define PWM_K64_FTM_SYNCONF_SWOC (0x1<<5) +#define PWM_K64_FTM_SYNCONF_SYNCMODE (0x1<<7) + +/** + * @brief Initialization function for FlexTimer Module FTM (PWM mode) + * + * @param dev Device struct + * @return DEV_OK if successful, failed otherwise + */ +extern int pwm_ftm_init(struct device *dev); + +/** Configuration data */ +struct pwm_ftm_config { + + /* FTM register base address */ + uint32_t ftm_num; + + /* FTM register base address */ + uint32_t reg_base; + + /* FTM prescale (1,2,4,8,16,32,64,128) */ + uint32_t prescale; + + /* FTM clock source */ + uint32_t clock_source; + + /* If phase is not 0, the odd-numbered channel is not available */ + bool phase_enable0; /* combine pwm0, pwm1 for phase capability */ + bool phase_enable2; /* combine pwm2, pwm3 for phase capability */ + bool phase_enable4; /* combine pwm4, pwm4 for phase capability */ + bool phase_enable6; /* combine pwm6, pwm5 for phase capability */ + + /* FTM period (clock ticks) */ + uint32_t period; + +}; + +/** Runtime driver data */ +struct pwm_ftm_drv_data { + uint32_t phase[4]; +}; + +#endif /* __PWM_K64_FTM_H__ */