diff --git a/boards/nxp/mr_canhubk3/mr_canhubk3.dts b/boards/nxp/mr_canhubk3/mr_canhubk3.dts index 6759aaf49fba8..6abf6438d9bf3 100644 --- a/boards/nxp/mr_canhubk3/mr_canhubk3.dts +++ b/boards/nxp/mr_canhubk3/mr_canhubk3.dts @@ -499,7 +499,6 @@ emios0_bus_a { mode = "MCB_UP_COUNTER"; prescaler = <16>; - period = <1000>; status = "okay"; }; }; @@ -513,63 +512,43 @@ pwm_0 { channel = <0>; pwm-mode = "OPWFMB"; - period = <65535>; - duty-cycle = <0>; prescaler = <8>; - polarity = "ACTIVE_HIGH"; }; pwm_1 { channel = <1>; pwm-mode = "OPWFMB"; - period = <65535>; - duty-cycle = <0>; prescaler = <8>; - polarity = "ACTIVE_HIGH"; }; pwm_2 { channel = <2>; pwm-mode = "OPWFMB"; - period = <65535>; - duty-cycle = <0>; prescaler = <8>; - polarity = "ACTIVE_HIGH"; }; pwm_3 { channel = <3>; pwm-mode = "OPWFMB"; - period = <65535>; - duty-cycle = <0>; prescaler = <8>; - polarity = "ACTIVE_HIGH"; }; pwm_4 { channel = <4>; pwm-mode = "OPWFMB"; - period = <65535>; - duty-cycle = <0>; prescaler = <8>; - polarity = "ACTIVE_HIGH"; }; pwm_5 { channel = <5>; pwm-mode = "OPWFMB"; - period = <65535>; - duty-cycle = <0>; prescaler = <8>; - polarity = "ACTIVE_HIGH"; }; rgb_red { channel = <19>; master-bus = <&emios0_bus_a>; - duty-cycle = <0>; pwm-mode = "OPWMB"; - polarity = "ACTIVE_LOW"; }; }; }; @@ -586,14 +565,12 @@ emios1_bus_a { prescaler = <16>; mode = "MCB_UP_COUNTER"; - period = <1000>; status = "okay"; }; emios1_bus_f { prescaler = <16>; mode = "MCB_UP_COUNTER"; - period = <1000>; status = "okay"; }; }; @@ -606,17 +583,13 @@ rgb_green { channel = <10>; master-bus = <&emios1_bus_a>; - duty-cycle = <0>; pwm-mode = "OPWMB"; - polarity = "ACTIVE_LOW"; }; rgb_blue { channel = <5>; master-bus = <&emios1_bus_f>; - duty-cycle = <0>; pwm-mode = "OPWMB"; - polarity = "ACTIVE_LOW"; }; }; }; diff --git a/boards/nxp/s32z2xxdc2/doc/index.rst b/boards/nxp/s32z2xxdc2/doc/index.rst index 9cb0972bf8fc7..f353b68194f51 100644 --- a/boards/nxp/s32z2xxdc2/doc/index.rst +++ b/boards/nxp/s32z2xxdc2/doc/index.rst @@ -60,6 +60,8 @@ The boards support the following hardware features: +-----------+------------+-------------------------------------+ | DSPI | on-chip | spi | +-----------+------------+-------------------------------------+ +| eMIOS | on-chip | pwm | ++-----------+------------+-------------------------------------+ Other hardware features are not currently supported by the port. diff --git a/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu0.yaml b/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu0.yaml index 070c33e6bfd32..60b258ad5a166 100644 --- a/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu0.yaml +++ b/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu0.yaml @@ -19,4 +19,5 @@ supported: - adc - i2c - dma + - pwm vendor: nxp diff --git a/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu0_D.yaml b/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu0_D.yaml index 9d692144a76c2..c35cc47699bd0 100644 --- a/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu0_D.yaml +++ b/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu0_D.yaml @@ -19,4 +19,5 @@ supported: - adc - i2c - dma + - pwm vendor: nxp diff --git a/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu1.yaml b/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu1.yaml index 3de95effa8003..3d4f2062cc984 100644 --- a/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu1.yaml +++ b/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu1.yaml @@ -19,4 +19,5 @@ supported: - adc - i2c - dma + - pwm vendor: nxp diff --git a/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu1_D.yaml b/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu1_D.yaml index ef45138807eda..334d75319ca05 100644 --- a/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu1_D.yaml +++ b/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270_rtu1_D.yaml @@ -19,4 +19,5 @@ supported: - adc - i2c - dma + - pwm vendor: nxp diff --git a/drivers/misc/nxp_s32_emios/nxp_s32_emios.c b/drivers/misc/nxp_s32_emios/nxp_s32_emios.c index d22d94b301542..371dca15389b0 100644 --- a/drivers/misc/nxp_s32_emios/nxp_s32_emios.c +++ b/drivers/misc/nxp_s32_emios/nxp_s32_emios.c @@ -59,15 +59,10 @@ static int nxp_s32_emios_init(const struct device *dev) .enableGlobalTimeBase = true \ }; -#define NXP_S32_EMIOS_MASTER_BUS_VERIFY(node_id) \ - BUILD_ASSERT(IN_RANGE(DT_PROP(node_id, period), \ - MIN_MASTER_BUS_PERIOD, MAX_MASTER_BUS_PERIOD), \ - "Node "DT_NODE_PATH(node_id)": period is out of range"); - #define NXP_S32_EMIOS_MASTER_BUS_CONFIG(node_id) \ { \ .hwChannel = DT_PROP(node_id, channel), \ - .defaultPeriod = DT_PROP(node_id, period), \ + .defaultPeriod = MAX_MASTER_BUS_PERIOD, \ .masterBusPrescaler = DT_PROP(node_id, prescaler) - 1, \ .allowDebugMode = DT_PROP(node_id, freeze), \ .masterMode = NXP_S32_EMIOS_MASTER_BUS_MODE(DT_STRING_TOKEN(node_id, mode)), \ @@ -75,8 +70,6 @@ static int nxp_s32_emios_init(const struct device *dev) }, #define NXP_S32_EMIOS_GENERATE_MASTER_BUS_CONFIG(n) \ - DT_FOREACH_CHILD_STATUS_OKAY(DT_INST_CHILD(n, master_bus), \ - NXP_S32_EMIOS_MASTER_BUS_VERIFY) \ const Emios_Ip_MasterBusConfigType nxp_s32_emios_##n##_master_bus_config[] = { \ DT_FOREACH_CHILD_STATUS_OKAY(DT_INST_CHILD(n, master_bus), \ NXP_S32_EMIOS_MASTER_BUS_CONFIG) \ diff --git a/drivers/pwm/pwm_nxp_s32_emios.c b/drivers/pwm/pwm_nxp_s32_emios.c index 34cd5c3b0a560..2547892d56c21 100644 --- a/drivers/pwm/pwm_nxp_s32_emios.c +++ b/drivers/pwm/pwm_nxp_s32_emios.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -22,40 +23,58 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_PWM_LOG_LEVEL); #define DT_DRV_COMPAT nxp_s32_emios_pwm +#if !defined(EMIOS_PWM_IP_NUM_OF_CHANNELS_USED) +#define EMIOS_PWM_IP_NUM_OF_CHANNELS_USED EMIOS_PWM_IP_NUM_OF_CHANNELS_USED_U8 +#endif + /* * Need to fill to this array at runtime, cannot do at build time like * the HAL over configuration tool due to limitation of the integration */ #if EMIOS_PWM_IP_USED extern uint8 eMios_Pwm_Ip_IndexInChState[EMIOS_PWM_IP_INSTANCE_COUNT][EMIOS_PWM_IP_CHANNEL_COUNT]; +#define EMIOS_PWM_MASTER_CHANNEL(channel, bus) \ + ((bus == EMIOS_PWM_IP_BUS_A) ? 23 : \ + ((bus == EMIOS_PWM_IP_BUS_F) ? 22 : \ + ((bus == EMIOS_PWM_IP_BUS_BCDE) ? ((channel >> 3) * 8) : channel))) #endif #ifdef CONFIG_PWM_CAPTURE extern uint8 eMios_Icu_Ip_IndexInChState[EMIOS_ICU_IP_INSTANCE_COUNT][EMIOS_ICU_IP_NUM_OF_CHANNELS]; +#define EMIOS_ICU_MASTER_CHANNEL(channel, bus) \ + ((bus == EMIOS_ICU_BUS_A) ? 23 : \ + ((bus == EMIOS_ICU_BUS_F) ? 22 : \ + ((bus == EMIOS_ICU_BUS_DIVERSE) ? ((channel >> 3) * 8) : channel))) + /* We need maximum three edges for measure both period and cycle */ #define MAX_NUM_EDGE 3 +#endif -struct pwm_nxp_s32_capture_data { - bool continuous; +struct pwm_nxp_s32_channel_data { bool inverted; + uint8_t master_channel; + +#if EMIOS_PWM_IP_USED + uint32_t curr_period; +#endif + +#ifdef CONFIG_PWM_CAPTURE + bool continuous; bool pulse_capture; bool period_capture; void *user_data; pwm_capture_callback_handler_t callback; eMios_Icu_ValueType edge_buff[MAX_NUM_EDGE]; -}; #endif +}; struct pwm_nxp_s32_data { uint32_t emios_clk; #if EMIOS_PWM_IP_USED uint8_t start_pwm_ch; #endif - -#ifdef CONFIG_PWM_CAPTURE - struct pwm_nxp_s32_capture_data capture[EMIOS_ICU_IP_NUM_OF_CHANNELS]; -#endif + struct pwm_nxp_s32_channel_data ch_data[eMIOS_CH_UC_UC_COUNT]; }; #if EMIOS_PWM_IP_USED @@ -83,69 +102,237 @@ struct pwm_nxp_s32_config { #if EMIOS_PWM_IP_USED #ifdef EMIOS_PWM_IP_MODE_OPWFMB_USED -static int pwm_nxp_s32_set_cycles_internal_timebase(uint8_t instance, uint32_t channel, - uint32_t period_cycles, uint32_t pulse_cycles) +static int pwm_nxp_s32_set_cycles_opwfmb(const struct device *dev, uint32_t channel, + uint32_t period_cycles, uint32_t pulse_cycles, + pwm_flags_t flags) { - bool need_update = false; + const struct pwm_nxp_s32_config *config = dev->config; + struct pwm_nxp_s32_data *data = dev->data; + struct pwm_nxp_s32_channel_data *ch_data = &data->ch_data[channel]; - if ((period_cycles > EMIOS_PWM_IP_MAX_CNT_VAL) || - (period_cycles <= EMIOS_PWM_IP_MIN_CNT_VAL)) { - LOG_ERR("period_cycles is out of range"); - return -EINVAL; - } + Emios_Pwm_Ip_PolarityType polarity; - if (Emios_Pwm_Ip_GetPeriod(instance, channel) != period_cycles) { - Emios_Pwm_Ip_SetPeriod(instance, channel, period_cycles); - need_update = true; - } + unsigned int key; + + if ((ch_data->inverted != flags) || (!ch_data->curr_period)) { + /* If PWM flag is changed or this is the first time PWM channel is configured */ + polarity = (flags & PWM_POLARITY_MASK) ? EMIOS_PWM_IP_ACTIVE_LOW : + EMIOS_PWM_IP_ACTIVE_HIGH; - if (Emios_Pwm_Ip_GetDutyCycle(instance, channel) != pulse_cycles) { - need_update = true; - if (Emios_Pwm_Ip_SetDutyCycle(instance, channel, pulse_cycles)) { - LOG_ERR("Cannot set pulse cycles"); - return -EIO; + config->base->CH.UC[channel].C &= ~(eMIOS_C_MODE_MASK | + eMIOS_C_EDPOL_MASK); + config->base->CH.UC[channel].A = pulse_cycles; + config->base->CH.UC[channel].B = period_cycles; + + /* + * When entering OPWFMB mode, Output = Cn[EDPOL]. Unless 100% pulse cycle is + * expected, Cn[EDPOL] is set to complement value (i.e 0 if active high and + * 1 if active low). + */ + if (pulse_cycles) { + config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(polarity); + } else { + config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(!polarity); } - } - if (need_update) { - /* Force match so that the new period, duty cycle takes effect immediately */ - Emios_Pwm_Ip_ForceMatchTrailingEdge(instance, channel, true); + key = irq_lock(); + config->base->CH.UC[channel].C |= eMIOS_C_MODE(EMIOS_PWM_IP_MODE_OPWFMB_FLAG); + + if (pulse_cycles) { + /* Restore expected value for Cn[EDPOL] */ + config->base->CH.UC[channel].C = (config->base->CH.UC[channel].C & + ~(eMIOS_C_EDPOL_MASK)) | + eMIOS_C_EDPOL(!polarity); + } + irq_unlock(key); + + ch_data->curr_period = period_cycles; + ch_data->inverted = flags; + } else { + key = irq_lock(); + config->base->CH.UC[channel].A = pulse_cycles; + config->base->CH.UC[channel].B = period_cycles; + irq_unlock(key); } return 0; } #endif -#if defined(EMIOS_PWM_IP_MODE_OPWMCB_USED) || defined(EMIOS_PWM_IP_MODE_OPWMB_USED) -static int pwm_nxp_s32_set_cycles_external_timebase(uint8_t instance, uint32_t channel, - uint32_t period_cycles, uint32_t pulse_cycles) +#if defined(EMIOS_PWM_IP_MODE_OPWMCB_USED) +static int pwm_nxp_s32_set_cycles_opwmcb(const struct device *dev, uint32_t channel, + uint32_t period_cycles, uint32_t pulse_cycles, + Emios_Pwm_Ip_ChannelConfigType *pwm_info, + pwm_flags_t flags) { - uint8_t master_channel; + const struct pwm_nxp_s32_config *config = dev->config; + struct pwm_nxp_s32_data *data = dev->data; + struct pwm_nxp_s32_channel_data *ch_data = &data->ch_data[channel]; + struct pwm_nxp_s32_channel_data *master_ch_data = &data->ch_data[ch_data->master_channel]; - if ((period_cycles > EMIOS_PWM_IP_MAX_CNT_VAL) || - (period_cycles <= EMIOS_PWM_IP_MIN_CNT_VAL)) { - LOG_ERR("period_cycles is out of range"); - return -EINVAL; - } + unsigned int key; + Emios_Pwm_Ip_PolarityType polarity; + + /* Convert to written value into eMIOS register */ + if (pulse_cycles == 0) { + pulse_cycles = EMIOS_PWM_IP_MAX_CNT_VAL; + } else if (pulse_cycles == period_cycles) { + pulse_cycles = 1; + } else { + pulse_cycles = period_cycles - (pulse_cycles >> 1); + } + + if ((ch_data->inverted != flags) || (!ch_data->curr_period)) { + /* If PWM flag is changed or this is the first time PWM channel is configured */ + polarity = (flags & PWM_POLARITY_MASK) ? EMIOS_PWM_IP_ACTIVE_LOW : + EMIOS_PWM_IP_ACTIVE_HIGH; + + if (master_ch_data->curr_period != period_cycles) { + /* + * Move timebase channel to GPIO mode --> configure period --> MCB mode + * Period can be shared between multiple PWM channels, only configure + * when needed. + */ + config->base->CH.UC[ch_data->master_channel].C &= ~eMIOS_C_MODE_MASK; + config->base->CH.UC[ch_data->master_channel].A = period_cycles; + } + + config->base->CH.UC[channel].C &= ~(eMIOS_C_MODE_MASK | + eMIOS_C_EDPOL_MASK | + eMIOS_C_BSL_MASK); - if (Emios_Pwm_Ip_GetPeriod(instance, channel) != period_cycles) { /* - * This mode uses internal counter, so change period and cycle - * don't effect to the others + * When entering OPWMCB mode, Output = !Cn[EDPOL]. If 100% pulse cycle is expected + * Cn[EDPOL] is set to complement value (i.e 0 if active high and 1 if active low). */ - master_channel = Emios_Pwm_Ip_GetMasterBusChannel(instance, channel); + if (pulse_cycles == 1) { + /* 100% pulse cycle */ + config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(!polarity); + } else { + config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(polarity); + } + + config->base->CH.UC[channel].A = pulse_cycles; + config->base->CH.UC[channel].B = pwm_info->DeadTime; + + key = irq_lock(); + config->base->CH.UC[channel].C |= (eMIOS_C_MODE(pwm_info->Mode) | + eMIOS_C_BSL(pwm_info->Timebase)); + + if (pulse_cycles == 1) { + config->base->CH.UC[channel].C = (config->base->CH.UC[channel].C & + ~eMIOS_C_EDPOL_MASK) | + eMIOS_C_EDPOL(polarity); + } + irq_unlock(key); - if (Emios_Mcl_Ip_SetCounterBusPeriod(instance, master_channel, period_cycles)) { - LOG_ERR("Cannot set counter period"); - return -EIO; + if (master_ch_data->curr_period != period_cycles) { + config->base->CH.UC[ch_data->master_channel].C |= + eMIOS_C_MODE(EMIOS_IP_MCB_UP_DOWN_COUNTER); + master_ch_data->curr_period = period_cycles; } + + ch_data->inverted = flags; + ch_data->curr_period = period_cycles; + } else if (master_ch_data->curr_period != period_cycles) { + key = irq_lock(); + config->base->CH.UC[ch_data->master_channel].A = period_cycles; + config->base->CH.UC[channel].A = pulse_cycles; + irq_unlock(key); + + master_ch_data->curr_period = period_cycles; + } else { + config->base->CH.UC[channel].A = pulse_cycles; } - if (Emios_Pwm_Ip_GetDutyCycle(instance, channel) != pulse_cycles) { - if (Emios_Pwm_Ip_SetDutyCycle(instance, channel, pulse_cycles)) { - LOG_ERR("Cannot set pulse cycles"); - return -EIO; + return 0; +} +#endif + +#if defined(EMIOS_PWM_IP_MODE_OPWMB_USED) +static int pwm_nxp_s32_set_cycles_opwmb(const struct device *dev, uint32_t channel, + uint32_t period_cycles, uint32_t pulse_cycles, + Emios_Pwm_Ip_ChannelConfigType *pwm_info, + pwm_flags_t flags) +{ + const struct pwm_nxp_s32_config *config = dev->config; + struct pwm_nxp_s32_data *data = dev->data; + struct pwm_nxp_s32_channel_data *ch_data = &data->ch_data[channel]; + struct pwm_nxp_s32_channel_data *master_ch_data = &data->ch_data[ch_data->master_channel]; + + Emios_Pwm_Ip_PolarityType polarity; + + unsigned int key; + + if ((ch_data->inverted != flags) || (!ch_data->curr_period)) { + /* If PWM flag is changed or this is the first time PWM channel is configured */ + polarity = (flags & PWM_POLARITY_MASK) ? EMIOS_PWM_IP_ACTIVE_LOW : + EMIOS_PWM_IP_ACTIVE_HIGH; + + if (master_ch_data->curr_period != period_cycles) { + /* + * Move timebase channel to GPIO mode --> configure period --> MCB mode + * Period can be shared between multiple PWM channels, only configure + * when needed. + */ + config->base->CH.UC[ch_data->master_channel].C &= ~eMIOS_C_MODE_MASK; + config->base->CH.UC[ch_data->master_channel].A = period_cycles; + } + + config->base->CH.UC[channel].C &= ~(eMIOS_C_MODE_MASK | + eMIOS_C_EDPOL_MASK | eMIOS_C_BSL_MASK); + + config->base->CH.UC[channel].A = pwm_info->PhaseShift; + config->base->CH.UC[channel].B = pulse_cycles; + + /* + * When entering OPWMB mode, Output = Cn[EDPOL]. Unless 100% pulse cycle is + * expected, Cn[EDPOL] is set to complement value (i.e 0 if active high and + * 1 if active low). + */ + if (pulse_cycles == period_cycles) { + config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(polarity); + } else { + config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(!polarity); + } + + key = irq_lock(); + config->base->CH.UC[channel].C |= eMIOS_C_MODE(pwm_info->Mode) | + eMIOS_C_BSL(pwm_info->Timebase); + + if (pulse_cycles != period_cycles) { + config->base->CH.UC[channel].C = (config->base->CH.UC[channel].C & + ~(eMIOS_C_EDPOL_MASK)) | + eMIOS_C_EDPOL(polarity); + } + + if (!pwm_info->PhaseShift) { + /* + * If Phase Shift == 0, Force Match A to ensure PWM pulse can be + * generated immediately. Otherwise, it will need to wait until + * next period boundary. + */ + config->base->CH.UC[channel].C |= eMIOS_C_FORCMA(1); } + irq_unlock(key); + + if (master_ch_data->curr_period != period_cycles) { + config->base->CH.UC[ch_data->master_channel].C |= + eMIOS_C_MODE(EMIOS_IP_MCB_UP_COUNTER); + master_ch_data->curr_period = period_cycles; + } + + ch_data->inverted = flags; + ch_data->curr_period = period_cycles; + } else if (master_ch_data->curr_period != period_cycles) { + key = irq_lock(); + config->base->CH.UC[ch_data->master_channel].A = period_cycles; + config->base->CH.UC[channel].B = pulse_cycles; + irq_unlock(key); + + master_ch_data->curr_period = period_cycles; + } else { + config->base->CH.UC[channel].B = pulse_cycles; } return 0; @@ -176,49 +363,60 @@ static int pwm_nxp_s32_set_cycles(const struct device *dev, uint32_t channel, logic_ch = eMios_Pwm_Ip_IndexInChState[config->instance][channel] - data->start_pwm_ch; pwm_info = &config->pulse_info->pwm_info[logic_ch]; - if ((flags & PWM_POLARITY_MASK) == pwm_info->OutputPolarity) { - LOG_ERR("Only support configuring output polarity at boot time"); - return -ENOTSUP; - } - switch (pwm_info->Mode) { #ifdef EMIOS_PWM_IP_MODE_OPWFMB_USED case EMIOS_PWM_IP_MODE_OPWFMB_FLAG: - return pwm_nxp_s32_set_cycles_internal_timebase(config->instance, channel, - period_cycles, pulse_cycles); + + if ((period_cycles > EMIOS_PWM_IP_MAX_CNT_VAL) || + (period_cycles <= EMIOS_PWM_IP_MIN_CNT_VAL)) { + LOG_ERR("Period cycles is out of range"); + return -EINVAL; + } + + return pwm_nxp_s32_set_cycles_opwfmb(dev, channel, period_cycles, + pulse_cycles, flags); #endif #ifdef EMIOS_PWM_IP_MODE_OPWMCB_USED case EMIOS_PWM_IP_MODE_OPWMCB_TRAIL_EDGE_FLAG: case EMIOS_PWM_IP_MODE_OPWMCB_LEAD_EDGE_FLAG: - if ((period_cycles % 2)) { - LOG_ERR("OPWMCB mode: period must be an even number"); + + period_cycles = (period_cycles + 2) / 2; + + if ((period_cycles > EMIOS_PWM_IP_MAX_CNT_VAL) || + (period_cycles <= EMIOS_PWM_IP_MIN_CNT_VAL)) { + LOG_ERR("Period cycles is out of range"); return -EINVAL; } - return pwm_nxp_s32_set_cycles_external_timebase(config->instance, channel, - (period_cycles + 2) / 2, - pulse_cycles); + return pwm_nxp_s32_set_cycles_opwmcb(dev, channel, period_cycles, + pulse_cycles, pwm_info, flags); #endif #if defined(EMIOS_PWM_IP_MODE_OPWMB_USED) case EMIOS_PWM_IP_MODE_OPWMB_FLAG: - if ((Emios_Pwm_Ip_GetPhaseShift(config->instance, channel) + - pulse_cycles) > period_cycles) { - LOG_ERR("OPWMB mode: new duty cycle + phase shift must <= new period"); + + if ((period_cycles > EMIOS_PWM_IP_MAX_CNT_VAL) || + (period_cycles <= EMIOS_PWM_IP_MIN_CNT_VAL)) { + LOG_ERR("Period cycles is out of range"); return -EINVAL; } - return pwm_nxp_s32_set_cycles_external_timebase(config->instance, channel, - period_cycles, pulse_cycles); + pulse_cycles += pwm_info->PhaseShift; + + if (pulse_cycles > period_cycles) { + LOG_ERR("Pulse cycles is out of range"); + return -EINVAL; + } + + return pwm_nxp_s32_set_cycles_opwmb(dev, channel, period_cycles, + pulse_cycles, pwm_info, flags); #endif default: /* Never reach here */ - break; + return 0; } - - return 0; } #endif @@ -284,12 +482,12 @@ static int pwm_nxp_s32_capture_configure(const struct device *dev, return -EBUSY; } - data->capture[channel].continuous = (flags & PWM_CAPTURE_MODE_MASK); - data->capture[channel].inverted = (flags & PWM_POLARITY_MASK); - data->capture[channel].pulse_capture = (flags & PWM_CAPTURE_TYPE_PULSE); - data->capture[channel].period_capture = (flags & PWM_CAPTURE_TYPE_PERIOD); - data->capture[channel].callback = cb; - data->capture[channel].user_data = user_data; + data->ch_data[channel].continuous = (flags & PWM_CAPTURE_MODE_MASK); + data->ch_data[channel].inverted = (flags & PWM_POLARITY_MASK); + data->ch_data[channel].pulse_capture = (flags & PWM_CAPTURE_TYPE_PULSE); + data->ch_data[channel].period_capture = (flags & PWM_CAPTURE_TYPE_PERIOD); + data->ch_data[channel].callback = cb; + data->ch_data[channel].user_data = user_data; return 0; } @@ -313,7 +511,7 @@ static int pwm_nxp_s32_capture_enable(const struct device *dev, uint32_t channel return -EINVAL; } - if (!data->capture[channel].callback) { + if (!data->ch_data[channel].callback) { LOG_ERR("Callback is not configured"); return -EINVAL; } @@ -325,7 +523,7 @@ static int pwm_nxp_s32_capture_enable(const struct device *dev, uint32_t channel } /* If just measure period, we just need 2 edges */ - if (data->capture[channel].period_capture && !data->capture[channel].pulse_capture) { + if (data->ch_data[channel].period_capture && !data->ch_data[channel].pulse_capture) { num_edge = 2U; edge = EMIOS_ICU_RISING_EDGE; } else { @@ -338,7 +536,7 @@ static int pwm_nxp_s32_capture_enable(const struct device *dev, uint32_t channel Emios_Icu_Ip_EnableNotification(config->instance, channel); Emios_Icu_Ip_StartTimestamp(config->instance, channel, - data->capture[channel].edge_buff, + data->ch_data[channel].edge_buff, MAX_NUM_EDGE, num_edge); return 0; @@ -363,68 +561,22 @@ static int pwm_nxp_s32_capture_disable(const struct device *dev, uint32_t channe return 0; } - -static int pwm_nxp_s32_get_master_bus(const struct device *dev, uint32_t channel) -{ - const struct pwm_nxp_s32_config *config = dev->config; - uint8_t bus_select, master_bus; - - bus_select = (config->base->CH.UC[channel].C & eMIOS_C_BSL_MASK) >> eMIOS_C_BSL_SHIFT; - - switch (bus_select) { - case 0: - master_bus = 23U; - break; - case 1: - master_bus = (channel < 8U) ? 0U : ((channel < 16U) ? 8U : 16U); - break; - case 2: - master_bus = 22U; - break; - default: - /* Default is internal counter */ - master_bus = channel; - break; - } - - return master_bus; -} #endif static int pwm_nxp_s32_get_cycles_per_sec(const struct device *dev, - uint32_t channel, - uint64_t *cycles) + uint32_t channel, uint64_t *cycles) { const struct pwm_nxp_s32_config *config = dev->config; struct pwm_nxp_s32_data *data = dev->data; - uint8_t master_bus = 0xFFU; - uint8_t internal_prescaler, global_prescaler; + uint8_t internal_prescaler, global_prescaler, master_channel; -#if EMIOS_PWM_IP_USED - if (eMios_Pwm_Ip_IndexInChState[config->instance][channel] < - EMIOS_PWM_IP_NUM_OF_CHANNELS_USED) { - master_bus = Emios_Pwm_Ip_GetMasterBusChannel(config->instance, channel); - } -#endif - -#ifdef CONFIG_PWM_CAPTURE - if (eMios_Icu_Ip_IndexInChState[config->instance][channel] < - EMIOS_ICU_IP_NUM_OF_CHANNELS_USED) { - master_bus = pwm_nxp_s32_get_master_bus(dev, channel); - } -#endif - - if (master_bus == 0xFF) { - LOG_ERR("Channel %d is not configured for PWM", channel); - return -EINVAL; - } - - internal_prescaler = (config->base->CH.UC[master_bus].C2 & eMIOS_C2_UCEXTPRE_MASK) >> + master_channel = data->ch_data[channel].master_channel; + internal_prescaler = (config->base->CH.UC[master_channel].C2 & eMIOS_C2_UCEXTPRE_MASK) >> eMIOS_C2_UCEXTPRE_SHIFT; /* Clock source for internal prescaler is from either eMIOS or eMIOS / global prescaler */ - if (config->base->CH.UC[master_bus].C2 & eMIOS_C2_UCPRECLK_MASK) { + if (config->base->CH.UC[master_channel].C2 & eMIOS_C2_UCPRECLK_MASK) { *cycles = data->emios_clk / (internal_prescaler + 1); } else { global_prescaler = (config->base->MCR & eMIOS_MCR_GPRE_MASK) >> @@ -441,7 +593,8 @@ static int pwm_nxp_s32_pulse_gen_init(const struct device *dev) const struct pwm_nxp_s32_config *config = dev->config; struct pwm_nxp_s32_data *data = dev->data; - const Emios_Pwm_Ip_ChannelConfigType *pwm_info; + struct pwm_nxp_s32_channel_data *ch_data; + Emios_Pwm_Ip_ChannelConfigType pwm_info; uint8_t ch_id; static uint8_t logic_ch; @@ -449,9 +602,20 @@ static int pwm_nxp_s32_pulse_gen_init(const struct device *dev) data->start_pwm_ch = logic_ch; for (ch_id = 0; ch_id < config->pulse_info->pwm_pulse_channels; ch_id++) { - pwm_info = &config->pulse_info->pwm_info[ch_id]; - eMios_Pwm_Ip_IndexInChState[config->instance][pwm_info->ChannelId] = logic_ch++; - Emios_Pwm_Ip_InitChannel(config->instance, pwm_info); + memcpy(&pwm_info, &config->pulse_info->pwm_info[ch_id], + sizeof(Emios_Pwm_Ip_ChannelConfigType)); + + /* + * Let eMIOS channel is in GPIO mode, the actual PWM mode will be + * configured at the first time pwm_set* is called. + */ + pwm_info.Mode = EMIOS_PWM_IP_MODE_GPO; + eMios_Pwm_Ip_IndexInChState[config->instance][pwm_info.ChannelId] = logic_ch++; + Emios_Pwm_Ip_InitChannel(config->instance, &pwm_info); + + ch_data = &data->ch_data[pwm_info.ChannelId]; + ch_data->master_channel = EMIOS_PWM_MASTER_CHANNEL(pwm_info.ChannelId, + pwm_info.Timebase); } return 0; @@ -462,7 +626,9 @@ static int pwm_nxp_s32_pulse_gen_init(const struct device *dev) static int pwm_nxp_s32_pulse_capture_init(const struct device *dev) { const struct pwm_nxp_s32_config *config = dev->config; + struct pwm_nxp_s32_data *data = dev->data; + struct pwm_nxp_s32_channel_data *ch_data; const eMios_Icu_Ip_ChannelConfigType *icu_info; uint8_t ch_id; @@ -470,7 +636,11 @@ static int pwm_nxp_s32_pulse_capture_init(const struct device *dev) for (ch_id = 0; ch_id < config->icu_cfg->nNumChannels; ch_id++) { icu_info = &(*config->icu_cfg->pChannelsConfig)[ch_id]; + ch_data = &data->ch_data[icu_info->hwChannel]; + eMios_Icu_Ip_IndexInChState[config->instance][icu_info->hwChannel] = logic_ch++; + ch_data->master_channel = EMIOS_ICU_MASTER_CHANNEL(icu_info->hwChannel, + icu_info->CntBus); } if (Emios_Icu_Ip_Init(config->instance, config->icu_cfg)) { @@ -487,29 +657,29 @@ static void pwm_nxp_s32_capture_callback(const struct device *dev, uint32_t chan uint32_t period = 0, pulse = 0; - if (data->capture[channel].period_capture && !data->capture[channel].pulse_capture) { - period = pwm_nxp_s32_capture_calc(data->capture[channel].edge_buff[0], - data->capture[channel].edge_buff[1]); + if (data->ch_data[channel].period_capture && !data->ch_data[channel].pulse_capture) { + period = pwm_nxp_s32_capture_calc(data->ch_data[channel].edge_buff[0], + data->ch_data[channel].edge_buff[1]); } else { - if (data->capture[channel].pulse_capture) { - pulse = pwm_nxp_s32_pulse_calc(data->capture[channel].inverted, - data->capture[channel].edge_buff, + if (data->ch_data[channel].pulse_capture) { + pulse = pwm_nxp_s32_pulse_calc(data->ch_data[channel].inverted, + data->ch_data[channel].edge_buff, Emios_Icu_Ip_GetInputLevel(config->instance, channel)); } - if (data->capture[channel].period_capture) { - period = pwm_nxp_s32_capture_calc(data->capture[channel].edge_buff[0], - data->capture[channel].edge_buff[2]); + if (data->ch_data[channel].period_capture) { + period = pwm_nxp_s32_capture_calc(data->ch_data[channel].edge_buff[0], + data->ch_data[channel].edge_buff[2]); } } - if (!data->capture[channel].continuous) { + if (!data->ch_data[channel].continuous) { Emios_Icu_Ip_StopTimestamp(config->instance, channel); } - data->capture[channel].callback(dev, channel, period, pulse, 0, - data->capture[channel].user_data); + data->ch_data[channel].callback(dev, channel, period, pulse, 0, + data->ch_data[channel].user_data); } #endif @@ -561,14 +731,6 @@ static DEVICE_API(pwm, pwm_nxp_s32_driver_api) = { #endif }; -/* - * If timebase is configured in MCB up/down count mode: pwm period = (2 * master bus's period - 2) - */ -#define EMIOS_PWM_PERIOD_TIME_BASE(node_id) \ - COND_CODE_1(DT_ENUM_HAS_VALUE(node_id, mode, MCB_UP_DOWN_COUNTER), \ - (2 * DT_PROP_BY_PHANDLE(node_id, master_bus, period) - 2), \ - (DT_PROP_BY_PHANDLE(node_id, master_bus, period))) - #define EMIOS_PWM_IS_MODE_OPWFMB(node_id) \ DT_ENUM_HAS_VALUE(node_id, pwm_mode, OPWFMB) @@ -594,22 +756,11 @@ static DEVICE_API(pwm, pwm_nxp_s32_driver_api) = { EMIOS_PWM_LOG(node_id, "invalid master bus")); #define EMIOS_PWM_PULSE_GEN_COMMON_VERIFY(node_id) \ - BUILD_ASSERT(DT_NODE_HAS_PROP(node_id, duty_cycle), \ - EMIOS_PWM_LOG(node_id, "duty-cycle must be configured")); \ - BUILD_ASSERT(DT_NODE_HAS_PROP(node_id, polarity), \ - EMIOS_PWM_LOG(node_id, "polarity must be configured")); \ BUILD_ASSERT(DT_NODE_HAS_PROP(node_id, input_filter), \ EMIOS_PWM_LOG(node_id, "input-filter is not used")); #define EMIOS_PWM_VERIFY_MODE_OPWFMB(node_id) \ EMIOS_PWM_PULSE_GEN_COMMON_VERIFY(node_id) \ - BUILD_ASSERT(DT_NODE_HAS_PROP(node_id, period), \ - EMIOS_PWM_LOG(node_id, "period must be configured")); \ - BUILD_ASSERT(IN_RANGE(DT_PROP(node_id, period), EMIOS_PWM_IP_MIN_CNT_VAL + 1, \ - EMIOS_PWM_IP_MAX_CNT_VAL), \ - EMIOS_PWM_LOG(node_id, "period is out of range")); \ - BUILD_ASSERT(DT_PROP(node_id, duty_cycle) <= DT_PROP(node_id, period), \ - EMIOS_PWM_LOG(node_id, "duty-cycle must <= period")); \ BUILD_ASSERT(!DT_NODE_HAS_PROP(node_id, master_bus), \ EMIOS_PWM_LOG(node_id, "master-bus must not be configured")); \ BUILD_ASSERT(DT_PROP(node_id, dead_time) == 0, \ @@ -622,16 +773,8 @@ static DEVICE_API(pwm, pwm_nxp_s32_driver_api) = { BUILD_ASSERT(DT_ENUM_HAS_VALUE(DT_PHANDLE(node_id, master_bus), mode, \ MCB_UP_DOWN_COUNTER), \ EMIOS_PWM_LOG(node_id, "master-bus must be configured in MCB up-down")); \ - BUILD_ASSERT((DT_PROP(node_id, duty_cycle) + DT_PROP(node_id, dead_time)) <= \ - EMIOS_PWM_PERIOD_TIME_BASE(node_id), \ - EMIOS_PWM_LOG(node_id, "duty-cycle + dead-time must <= period")); \ - BUILD_ASSERT(DT_PROP(node_id, dead_time) <= DT_PROP(node_id, duty_cycle), \ - EMIOS_PWM_LOG(node_id, "dead-time must <= duty-cycle")); \ BUILD_ASSERT(DT_PROP(node_id, phase_shift) == 0, \ EMIOS_PWM_LOG(node_id, "phase-shift is not used")); \ - BUILD_ASSERT(!DT_NODE_HAS_PROP(node_id, period), \ - EMIOS_PWM_LOG(node_id, "period is not used," \ - " driver takes the value from master bus")); \ BUILD_ASSERT(!DT_NODE_HAS_PROP(node_id, prescaler), \ EMIOS_PWM_LOG(node_id, "prescaler is not used," \ " driver takes the value from master bus")); \ @@ -643,12 +786,6 @@ static DEVICE_API(pwm, pwm_nxp_s32_driver_api) = { EMIOS_PWM_PULSE_GEN_COMMON_VERIFY(node_id) \ BUILD_ASSERT(DT_ENUM_HAS_VALUE(DT_PHANDLE(node_id, master_bus), mode, MCB_UP_COUNTER), \ EMIOS_PWM_LOG(node_id, "master-bus must be configured in MCB up")); \ - BUILD_ASSERT(!DT_NODE_HAS_PROP(node_id, period), \ - EMIOS_PWM_LOG(node_id, "period is not used," \ - " driver takes the value from master bus")); \ - BUILD_ASSERT((DT_PROP(node_id, duty_cycle) + DT_PROP(node_id, phase_shift)) <= \ - EMIOS_PWM_PERIOD_TIME_BASE(node_id), \ - EMIOS_PWM_LOG(node_id, "duty-cycle + phase-shift must <= period")); \ BUILD_ASSERT(DT_PROP(node_id, dead_time) == 0, \ EMIOS_PWM_LOG(node_id, "dead-time is not used")); \ BUILD_ASSERT(!DT_NODE_HAS_PROP(node_id, prescaler), \ @@ -662,9 +799,6 @@ static DEVICE_API(pwm, pwm_nxp_s32_driver_api) = { (BUILD_ASSERT( \ DT_ENUM_HAS_VALUE(DT_PHANDLE(node_id, master_bus), mode, MCB_UP_COUNTER), \ EMIOS_PWM_LOG(node_id, "master-bus must be configured in MCB up"));)) \ - IF_ENABLED(DT_NODE_HAS_PROP(node_id, master_bus), \ - (BUILD_ASSERT(DT_PROP_BY_PHANDLE(node_id, master_bus, period) == 0xFFFF, \ - EMIOS_PWM_LOG(node_id, "master-bus period must be 0xFFFF"));)) \ IF_ENABLED(UTIL_NOT(DT_NODE_HAS_PROP(node_id, master_bus)), \ (BUILD_ASSERT( \ BIT(DT_PROP(node_id, channel)) & DT_PROP(DT_GPARENT(node_id), internal_cnt),\ @@ -674,12 +808,6 @@ static DEVICE_API(pwm, pwm_nxp_s32_driver_api) = { (BUILD_ASSERT(DT_NODE_HAS_PROP(node_id, prescaler), \ EMIOS_PWM_LOG(node_id, "if use internal counter, prescaler must" \ " be configured")))); \ - BUILD_ASSERT(!DT_NODE_HAS_PROP(node_id, duty_cycle), \ - EMIOS_PWM_LOG(node_id, "duty-cycle is not used")); \ - BUILD_ASSERT(!DT_NODE_HAS_PROP(node_id, polarity), \ - EMIOS_PWM_LOG(node_id, "polarity is not used")); \ - BUILD_ASSERT(!DT_NODE_HAS_PROP(node_id, period), \ - EMIOS_PWM_LOG(node_id, "period is not used")); \ BUILD_ASSERT(DT_ENUM_HAS_VALUE(node_id, prescaler_src, PRESCALED_CLOCK), \ EMIOS_PWM_LOG(node_id, "prescaler-src is not used," \ " always use prescalered source")); @@ -707,9 +835,9 @@ static DEVICE_API(pwm, pwm_nxp_s32_driver_api) = { #define EMIOS_PWM_BUS(mode) DT_CAT(EMIOS_PWM_, mode) #define EMIOS_PWM_MODE(mode) DT_CAT3(EMIOS_PWM_IP_MODE_, mode, _FLAG) -#define EMIOS_PWM_POLARITY(mode) DT_CAT(EMIOS_PWM_IP_, mode) #define EMIOS_PWM_PS_SRC(mode) DT_CAT(EMIOS_PWM_IP_PS_SRC_, mode) +/* Keep minimal configuration used at driver initialization, no PWM signal is produced */ #define _EMIOS_PWM_PULSE_GEN_CONFIG(node_id) \ IF_ENABLED(UTIL_NOT(EMIOS_PWM_IS_CAPTURE_MODE(node_id)), \ ({ \ @@ -725,10 +853,10 @@ static DEVICE_API(pwm, pwm_nxp_s32_driver_api) = { .PhaseShift = DT_PROP(node_id, phase_shift), \ .DeadTime = DT_PROP(node_id, dead_time), \ .OutputDisableSource = EMIOS_PWM_IP_OUTPUT_DISABLE_NONE, \ - .OutputPolarity = EMIOS_PWM_POLARITY(DT_STRING_TOKEN(node_id, polarity)), \ + .OutputPolarity = EMIOS_PWM_IP_ACTIVE_LOW, \ .DebugMode = DT_PROP(node_id, freeze), \ - .PeriodCount = DT_PROP_OR(node_id, period, EMIOS_PWM_PERIOD_TIME_BASE(node_id)),\ - .DutyCycle = DT_PROP(node_id, duty_cycle), \ + .PeriodCount = 0, \ + .DutyCycle = 0, \ },)) #define EMIOS_PWM_PULSE_GEN_CONFIG(n) \ diff --git a/dts/arm/nxp/nxp_s32z27x_r52.dtsi b/dts/arm/nxp/nxp_s32z27x_r52.dtsi index 013c80c87eada..1149fad3636a5 100644 --- a/dts/arm/nxp/nxp_s32z27x_r52.dtsi +++ b/dts/arm/nxp/nxp_s32z27x_r52.dtsi @@ -1259,5 +1259,177 @@ status = "disabled"; }; + emios0: emios@420b0000 { + compatible = "nxp,s32-emios"; + reg = <0x420b0000 0x4000>; + clocks = <&clock NXP_S32_P4_REG_INTF_CLK>; + internal-cnt = <0xFFFFFFFF>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "0_CH0", "0_CH1", "0_CH2", "0_CH3", "0_CH4", + "0_CH5", "0_CH6", "0_CH7", "0_CH8", "0_CH9", + "0_CH10", "0_CH12", "0_CH14", "0_CH16", + "0_CH17", "0_CH18", "0_CH19", "0_CH20", + "0_CH21", "0_CH22", "0_CH23", "0_CH24", + "0_CH25", "0_CH26", "0_CH27", "0_CH28", + "0_CH29", "0_CH30", "0_CH31"; + status = "disabled"; + + master_bus { + emios0_bus_a: emios0_bus_a { + channel = <23>; + bus-type = "BUS_A"; + channel-mask = <0xFF7FFFFF>; + status = "disabled"; + }; + + emios0_bus_b: emios0_bus_b { + channel = <0>; + bus-type = "BUS_B"; + channel-mask = <0x000000FE>; + status = "disabled"; + }; + + emios0_bus_c: emios0_bus_c { + channel = <8>; + bus-type = "BUS_C"; + channel-mask = <0x0000FE00>; + status = "disabled"; + }; + + emios0_bus_d: emios0_bus_d { + channel = <16>; + bus-type = "BUS_D"; + channel-mask = <0x00FE0000>; + status = "disabled"; + }; + + emios0_bus_e: emios0_bus_e { + channel = <24>; + bus-type = "BUS_E"; + channel-mask = <0xFE000000>; + status = "disabled"; + }; + }; + + pwm { + compatible = "nxp,s32-emios-pwm"; + #pwm-cells = <3>; + status = "disabled"; + }; + }; + + emios1: emios@400b0000 { + compatible = "nxp,s32-emios"; + reg = <0x400b0000 0x4000>; + clocks = <&clock NXP_S32_P0_REG_INTF_CLK>; + internal-cnt = <0xFFFFFFFF>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "1_CH0", "1_CH1", "1_CH2", "1_CH3", "1_CH4", + "1_CH5", "1_CH6", "1_CH7", "1_CH8", "1_CH10", + "1_CH12", "1_CH14", "1_CH16", "1_CH17", + "1_CH18", "1_CH19", "1_CH20", "1_CH21", + "1_CH22", "1_CH23", "1_CH24", "1_CH25", + "1_CH26", "1_CH27", "1_CH28", "1_CH29", + "1_CH30", "1_CH31"; + status = "disabled"; + + master_bus { + emios1_bus_a: emios1_bus_a { + channel = <23>; + bus-type = "BUS_A"; + channel-mask = <0xFF7FFFFF>; + status = "disabled"; + }; + + emios1_bus_b: emios1_bus_b { + channel = <0>; + bus-type = "BUS_B"; + channel-mask = <0x000000FE>; + status = "disabled"; + }; + + emios1_bus_c: emios1_bus_c { + channel = <8>; + bus-type = "BUS_C"; + channel-mask = <0x0000FE00>; + status = "disabled"; + }; + + emios1_bus_d: emios1_bus_d { + channel = <16>; + bus-type = "BUS_D"; + channel-mask = <0x00FE0000>; + status = "disabled"; + }; + + emios1_bus_e: emios1_bus_e { + channel = <24>; + channel-mask = <0xFE000000>; + bus-type = "BUS_E"; + status = "disabled"; + }; + }; + + pwm { + compatible = "nxp,s32-emios-pwm"; + #pwm-cells = <3>; + status = "disabled"; + }; + }; }; }; diff --git a/dts/bindings/misc/nxp,s32-emios.yaml b/dts/bindings/misc/nxp,s32-emios.yaml index 61c831a01a066..f795746f2ead0 100644 --- a/dts/bindings/misc/nxp,s32-emios.yaml +++ b/dts/bindings/misc/nxp,s32-emios.yaml @@ -52,7 +52,6 @@ child-binding: bus-type = "BUS_A"; channel-mask = <0x07FFFFF>; prescaler = <1>; - period = <65535>; mode = ; freeze; status = "okay"; @@ -104,13 +103,6 @@ child-binding: - "MCB_UP_COUNTER" - "MCB_UP_DOWN_COUNTER" - period: - type: int - required: true - description: | - Default period (in ticks) for master bus at boot time. This determines PWM period - for channels use this bus as reference timebase. Could be in range [2 ... 65535] - freeze: type: boolean description: Freeze internal counter when the chip enters Debug mode. diff --git a/dts/bindings/pwm/nxp,s32-emios-pwm.yaml b/dts/bindings/pwm/nxp,s32-emios-pwm.yaml index 0b8a2ffc674ac..c8c4a64b27dc2 100644 --- a/dts/bindings/pwm/nxp,s32-emios-pwm.yaml +++ b/dts/bindings/pwm/nxp,s32-emios-pwm.yaml @@ -18,27 +18,20 @@ description: | channel = <0>; pwm-mode = "OPWFMB"; prescaler = <8>; - period = <65534>; - duty-cycle = <32768>; - polarity = "ACTIVE_HIGH"; }; pwm_1 { channel = <1>; master-bus = <&emios1_bus_a>; pwm-mode = "OPWMB"; - duty-cycle = <32768>; phase-shift = <100>; - polarity = "ACTIVE_LOW"; }; pwm_2 { channel = <2>; master-bus = <&emios1_bus_b>; pwm-mode = "OPWMCB_LEAD_EDGE"; - duty-cycle = <32768>; dead-time = <100>; - polarity = "ACTIVE_LOW"; }; pwm_3 { @@ -50,10 +43,8 @@ description: | }; OPWMB and OPWMCB modes use reference timebase, the master bus is chosen over - phandle 'master-bus'. For OPWMB mode, PWM's period is master bus's period and - is 2 * master bus's period - 2 for OPWMCB mode. Please notice that the devicetree - node for master bus should be enabled and configured for using, please see - 'nxp,s32-emios' bindings. + phandle 'master-bus'. Please notice that the devicetree node for master bus + should be enabled and configured for using, please see 'nxp,s32-emios' bindings. compatible: "nxp,s32-emios-pwm" @@ -124,25 +115,6 @@ child-binding: - "OPWMCB_LEAD_EDGE" - "SAIC" - polarity: - type: string - description: | - Output polarity for PWM channel. - enum: - - "ACTIVE_LOW" - - "ACTIVE_HIGH" - - duty-cycle: - type: int - description: | - Duty-cycle (in ticks) for PWM channel at boot time. - - period: - type: int - description: | - Period (in ticks) for OPWFMB at boot time. Period for the rest - of PWM mode depends on period's master bus. Must be in range [2 ... 65535]. - freeze: type: boolean description: Freeze individual internal counter when the chip enters Debug mode. diff --git a/tests/drivers/pwm/pwm_api/boards/s32z2xxdc2_s32z270_rtu0.overlay b/tests/drivers/pwm/pwm_api/boards/s32z2xxdc2_s32z270_rtu0.overlay new file mode 100644 index 0000000000000..eae92bfc7e4cd --- /dev/null +++ b/tests/drivers/pwm/pwm_api/boards/s32z2xxdc2_s32z270_rtu0.overlay @@ -0,0 +1,39 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + pwm-0 = &emios0_pwm; + }; +}; + +&pinctrl { + emios0_default: emios0_default { + group0 { + pinmux = ; + output-enable; + }; + }; +}; + +&emios0 { + clock-divider = <133>; + status = "okay"; + + emios0_pwm: pwm { + pinctrl-0 = <&emios0_default>; + pinctrl-names = "default"; + status = "okay"; + + pwm_24 { + channel = <24>; + prescaler = <16>; + pwm-mode = "OPWFMB"; + }; + }; +}; diff --git a/tests/drivers/pwm/pwm_api/boards/s32z2xxdc2_s32z270_rtu1.overlay b/tests/drivers/pwm/pwm_api/boards/s32z2xxdc2_s32z270_rtu1.overlay new file mode 100644 index 0000000000000..eae92bfc7e4cd --- /dev/null +++ b/tests/drivers/pwm/pwm_api/boards/s32z2xxdc2_s32z270_rtu1.overlay @@ -0,0 +1,39 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + pwm-0 = &emios0_pwm; + }; +}; + +&pinctrl { + emios0_default: emios0_default { + group0 { + pinmux = ; + output-enable; + }; + }; +}; + +&emios0 { + clock-divider = <133>; + status = "okay"; + + emios0_pwm: pwm { + pinctrl-0 = <&emios0_default>; + pinctrl-names = "default"; + status = "okay"; + + pwm_24 { + channel = <24>; + prescaler = <16>; + pwm-mode = "OPWFMB"; + }; + }; +}; diff --git a/tests/drivers/pwm/pwm_loopback/boards/mr_canhubk3.overlay b/tests/drivers/pwm/pwm_loopback/boards/mr_canhubk3.overlay index 898b6d938f797..9cbda8857fbd3 100644 --- a/tests/drivers/pwm/pwm_loopback/boards/mr_canhubk3.overlay +++ b/tests/drivers/pwm/pwm_loopback/boards/mr_canhubk3.overlay @@ -31,9 +31,6 @@ status = "okay"; pwm_1 { - /delete-property/ period; - /delete-property/ polarity; - /delete-property/ duty-cycle; prescaler = <16>; pwm-mode = "SAIC"; }; diff --git a/tests/drivers/pwm/pwm_loopback/boards/s32z2xxdc2_s32z270_rtu0.overlay b/tests/drivers/pwm/pwm_loopback/boards/s32z2xxdc2_s32z270_rtu0.overlay new file mode 100644 index 0000000000000..2b7fa95384e85 --- /dev/null +++ b/tests/drivers/pwm/pwm_loopback/boards/s32z2xxdc2_s32z270_rtu0.overlay @@ -0,0 +1,51 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + pwm_loopback_0 { + compatible = "test-pwm-loopback"; + pwms = <&emios0_pwm 24 0 PWM_POLARITY_NORMAL>, + <&emios0_pwm 25 0 PWM_POLARITY_NORMAL>; + }; +}; + +&pinctrl { + emios0_default: emios0_default { + group0 { + pinmux = ; + output-enable; + }; + group1 { + pinmux = ; + input-enable; + }; + }; +}; + +&emios0 { + clock-divider = <200>; + status = "okay"; + + emios0_pwm: pwm { + pinctrl-0 = <&emios0_default>; + pinctrl-names = "default"; + status = "okay"; + + pwm_24 { + channel = <24>; + prescaler = <16>; + pwm-mode = "OPWFMB"; + }; + + pwm_25 { + channel = <25>; + pwm-mode = "SAIC"; + prescaler = <16>; + }; + }; +}; diff --git a/tests/drivers/pwm/pwm_loopback/boards/s32z2xxdc2_s32z270_rtu1.overlay b/tests/drivers/pwm/pwm_loopback/boards/s32z2xxdc2_s32z270_rtu1.overlay new file mode 100644 index 0000000000000..2b7fa95384e85 --- /dev/null +++ b/tests/drivers/pwm/pwm_loopback/boards/s32z2xxdc2_s32z270_rtu1.overlay @@ -0,0 +1,51 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + pwm_loopback_0 { + compatible = "test-pwm-loopback"; + pwms = <&emios0_pwm 24 0 PWM_POLARITY_NORMAL>, + <&emios0_pwm 25 0 PWM_POLARITY_NORMAL>; + }; +}; + +&pinctrl { + emios0_default: emios0_default { + group0 { + pinmux = ; + output-enable; + }; + group1 { + pinmux = ; + input-enable; + }; + }; +}; + +&emios0 { + clock-divider = <200>; + status = "okay"; + + emios0_pwm: pwm { + pinctrl-0 = <&emios0_default>; + pinctrl-names = "default"; + status = "okay"; + + pwm_24 { + channel = <24>; + prescaler = <16>; + pwm-mode = "OPWFMB"; + }; + + pwm_25 { + channel = <25>; + pwm-mode = "SAIC"; + prescaler = <16>; + }; + }; +}; diff --git a/west.yml b/west.yml index d6e57c7efaec5..ec1cdbcbf1e64 100644 --- a/west.yml +++ b/west.yml @@ -203,7 +203,7 @@ manifest: groups: - hal - name: hal_nxp - revision: c15dd51d7af27593e38b65b1443a350e9d2de64f + revision: dad9b28b80c68c4e124dd3a61eb3821df387bf0e path: modules/hal/nxp groups: - hal