drivers: pwm: Microchip XEC PWM add MEC172x support

Add support for MEC172x series to Microchip XEC PWM driver.
Standardize device tree properties for both SoC families.
Standardize device structure usage.

Signed-off-by: Jay Vasanth <jay.vasanth@microchip.com>
This commit is contained in:
Jay Vasanth 2022-03-11 14:37:39 -05:00 committed by Anas Nashif
commit 845c1185a2
4 changed files with 94 additions and 60 deletions

View file

@ -1,22 +1,30 @@
/* pwm_mchp_xec.c - Microchip XEC PWM driver */
#define DT_DRV_COMPAT microchip_xec_pwm
/* /*
* Copyright (c) 2019 Intel Corporation * Copyright (c) 2019 Intel Corporation
* Copyright (c) 2022 Microchip Technololgy Inc.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <logging/log.h> #define DT_DRV_COMPAT microchip_xec_pwm
LOG_MODULE_REGISTER(pwm_mchp_xec, CONFIG_PWM_LOG_LEVEL);
#include <drivers/pwm.h>
#include <soc.h>
#include <errno.h> #include <errno.h>
#include <soc.h>
#include <drivers/pwm.h>
#ifdef CONFIG_SOC_SERIES_MEC172X
#include <drivers/clock_control/mchp_xec_clock_control.h>
#include <drivers/interrupt_controller/intc_mchp_xec_ecia.h>
#endif
#include <device.h>
#include <errno.h>
#include <kernel.h>
#include <init.h>
#include <pm/device.h>
#include <stdlib.h> #include <stdlib.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(pwm_mchp_xec, CONFIG_PWM_LOG_LEVEL);
/* Minimal on/off are 1 & 1 both are incremented, so 4. /* Minimal on/off are 1 & 1 both are incremented, so 4.
* 0 cannot be set (used for full low/high output) so a * 0 cannot be set (used for full low/high output) so a
* combination of on_off of 2 is not possible. * combination of on_off of 2 is not possible.
@ -43,18 +51,11 @@ LOG_MODULE_REGISTER(pwm_mchp_xec, CONFIG_PWM_LOG_LEVEL);
#define XEC_PWM_FREQ_LIMIT 1 /* 0.1hz * XEC_PWM_FREQ_PF */ #define XEC_PWM_FREQ_LIMIT 1 /* 0.1hz * XEC_PWM_FREQ_PF */
struct pwm_xec_config { struct pwm_xec_config {
uint32_t base_address; struct pwm_regs * const regs;
uint8_t pcr_idx;
uint8_t pcr_pos;
}; };
#define PWM_XEC_REG_BASE(_dev) \
((PWM_Type *) \
((const struct pwm_xec_config * const) \
_dev->config)->base_address)
#define PWM_XEC_CONFIG(_dev) \
(((const struct pwm_xec_config * const) \
_dev->config))
struct xec_params { struct xec_params {
uint32_t on; uint32_t on;
uint32_t off; uint32_t off;
@ -63,7 +64,7 @@ struct xec_params {
#define NUM_DIV_ELEMS 16 #define NUM_DIV_ELEMS 16
uint32_t max_freq_high_on_div[NUM_DIV_ELEMS] = { static const uint32_t max_freq_high_on_div[NUM_DIV_ELEMS] = {
48000000, 48000000,
24000000, 24000000,
16000000, 16000000,
@ -82,7 +83,7 @@ uint32_t max_freq_high_on_div[NUM_DIV_ELEMS] = {
3000000 3000000
}; };
uint32_t max_freq_low_on_div[NUM_DIV_ELEMS] = { static const uint32_t max_freq_low_on_div[NUM_DIV_ELEMS] = {
100000, 100000,
50000, 50000,
33333, 33333,
@ -106,7 +107,7 @@ static uint32_t xec_compute_frequency(uint32_t clk, uint32_t on, uint32_t off)
return ((clk * XEC_PWM_FREQ_PF)/((on + 1) + (off + 1))); return ((clk * XEC_PWM_FREQ_PF)/((on + 1) + (off + 1)));
} }
static uint16_t xec_select_div(uint32_t freq, uint32_t max_freq[16]) static uint16_t xec_select_div(uint32_t freq, const uint32_t max_freq[16])
{ {
uint8_t i; uint8_t i;
@ -147,9 +148,9 @@ static uint32_t xec_compute_dc(uint32_t on, uint32_t off)
} }
static uint16_t xec_compare_div_on_off(uint32_t target_freq, uint32_t dc, static uint16_t xec_compare_div_on_off(uint32_t target_freq, uint32_t dc,
uint32_t max_freq[16], const uint32_t max_freq[16],
uint8_t div_a, uint8_t div_b, uint8_t div_a, uint8_t div_b,
uint32_t *on_a, uint32_t *off_a) uint32_t *on_a, uint32_t *off_a)
{ {
uint32_t freq_a, freq_b, on_b, off_b; uint32_t freq_a, freq_b, on_b, off_b;
@ -180,8 +181,8 @@ static uint16_t xec_compare_div_on_off(uint32_t target_freq, uint32_t dc,
} }
static uint8_t xec_select_best_div_on_off(uint32_t target_freq, uint32_t dc, static uint8_t xec_select_best_div_on_off(uint32_t target_freq, uint32_t dc,
uint32_t max_freq[16], const uint32_t max_freq[16],
uint32_t *on, uint32_t *off) uint32_t *on, uint32_t *off)
{ {
int div_comp; int div_comp;
uint8_t div; uint8_t div;
@ -237,12 +238,13 @@ static void xec_compute_and_set_parameters(const struct device *dev,
uint32_t target_freq, uint32_t target_freq,
uint32_t on, uint32_t off) uint32_t on, uint32_t off)
{ {
PWM_Type *pwm_regs = PWM_XEC_REG_BASE(dev); const struct pwm_xec_config * const cfg = dev->config;
struct pwm_regs * const regs = cfg->regs;
bool compute_high, compute_low; bool compute_high, compute_low;
struct xec_params hc_params; struct xec_params hc_params;
struct xec_params lc_params; struct xec_params lc_params;
struct xec_params *params; struct xec_params *params;
uint32_t dc, reg; uint32_t dc, cfgval;
dc = xec_compute_dc(on, off); dc = xec_compute_dc(on, off);
@ -287,30 +289,31 @@ static void xec_compute_and_set_parameters(const struct device *dev,
lc_params.div = UINT8_MAX; lc_params.div = UINT8_MAX;
} }
done: done:
pwm_regs->CONFIG &= ~MCHP_PWM_CFG_ENABLE; regs->CONFIG &= ~MCHP_PWM_CFG_ENABLE;
reg = pwm_regs->CONFIG; cfgval = regs->CONFIG;
params = xec_compare_params(target_freq, &hc_params, &lc_params); params = xec_compare_params(target_freq, &hc_params, &lc_params);
if (params == &hc_params) { if (params == &hc_params) {
reg |= MCHP_PWM_CFG_CLK_SEL_48M; cfgval |= MCHP_PWM_CFG_CLK_SEL_48M;
} else { } else {
reg |= MCHP_PWM_CFG_CLK_SEL_100K; cfgval |= MCHP_PWM_CFG_CLK_SEL_100K;
} }
pwm_regs->COUNT_ON = params->on; regs->COUNT_ON = params->on;
pwm_regs->COUNT_OFF = params->off; regs->COUNT_OFF = params->off;
reg |= MCHP_PWM_CFG_CLK_PRE_DIV(params->div); cfgval |= MCHP_PWM_CFG_CLK_PRE_DIV(params->div);
reg |= MCHP_PWM_CFG_ENABLE; cfgval |= MCHP_PWM_CFG_ENABLE;
pwm_regs->CONFIG = reg; regs->CONFIG = cfgval;
} }
static int pwm_xec_pin_set(const struct device *dev, uint32_t pwm, static int pwm_xec_pin_set(const struct device *dev, uint32_t pwm,
uint32_t period_cycles, uint32_t pulse_cycles, uint32_t period_cycles, uint32_t pulse_cycles,
pwm_flags_t flags) pwm_flags_t flags)
{ {
PWM_Type *pwm_regs = PWM_XEC_REG_BASE(dev); const struct pwm_xec_config * const cfg = dev->config;
struct pwm_regs * const regs = cfg->regs;
uint32_t target_freq; uint32_t target_freq;
uint32_t on, off; uint32_t on, off;
@ -337,13 +340,13 @@ static int pwm_xec_pin_set(const struct device *dev, uint32_t pwm,
} }
if ((pulse_cycles == 0U) && (period_cycles == 0U)) { if ((pulse_cycles == 0U) && (period_cycles == 0U)) {
pwm_regs->CONFIG &= ~MCHP_PWM_CFG_ENABLE; regs->CONFIG &= ~MCHP_PWM_CFG_ENABLE;
} else if ((pulse_cycles == 0U) && (period_cycles > 0U)) { } else if ((pulse_cycles == 0U) && (period_cycles > 0U)) {
pwm_regs->COUNT_ON = 0; regs->COUNT_ON = 0;
pwm_regs->COUNT_OFF = 1; regs->COUNT_OFF = 1;
} else if ((pulse_cycles > 0U) && (period_cycles == 0U)) { } else if ((pulse_cycles > 0U) && (period_cycles == 0U)) {
pwm_regs->COUNT_ON = 1; regs->COUNT_ON = 1;
pwm_regs->COUNT_OFF = 0; regs->COUNT_OFF = 0;
} else { } else {
xec_compute_and_set_parameters(dev, target_freq, on, off); xec_compute_and_set_parameters(dev, target_freq, on, off);
} }
@ -370,6 +373,11 @@ static int pwm_xec_get_cycles_per_sec(const struct device *dev, uint32_t pwm,
return 0; return 0;
} }
static const struct pwm_driver_api pwm_xec_driver_api = {
.pin_set = pwm_xec_pin_set,
.get_cycles_per_sec = pwm_xec_get_cycles_per_sec,
};
static int pwm_xec_init(const struct device *dev) static int pwm_xec_init(const struct device *dev)
{ {
ARG_UNUSED(dev); ARG_UNUSED(dev);
@ -377,23 +385,22 @@ static int pwm_xec_init(const struct device *dev)
return 0; return 0;
} }
static struct pwm_driver_api pwm_xec_api = { #define XEC_PWM_CONFIG(inst) \
.pin_set = pwm_xec_pin_set, static struct pwm_xec_config pwm_xec_config_##inst = { \
.get_cycles_per_sec = pwm_xec_get_cycles_per_sec .regs = (struct pwm_regs * const)DT_INST_REG_ADDR(inst), \
}; .pcr_idx = (uint8_t)DT_INST_PROP_BY_IDX(inst, pcrs, 0), \
.pcr_pos = (uint8_t)DT_INST_PROP_BY_IDX(inst, pcrs, 1), \
};
#define XEC_INST_INIT(inst) \ #define XEC_PWM_DEVICE_INIT(index) \
static struct pwm_xec_config pwm_xec_dev_config_##inst = { \
.base_address = DT_INST_REG_ADDR(inst) \
}; \
\ \
DEVICE_DT_INST_DEFINE(inst, \ XEC_PWM_CONFIG(index); \
pwm_xec_init, \ \
NULL, \ DEVICE_DT_INST_DEFINE(index, &pwm_xec_init, \
NULL, \ NULL, \
&pwm_xec_dev_config_##inst, \ NULL, \
POST_KERNEL, \ &pwm_xec_config_##index, POST_KERNEL, \
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
&pwm_xec_api); &pwm_xec_driver_api);
DT_INST_FOREACH_STATUS_OKAY(XEC_INST_INIT) DT_INST_FOREACH_STATUS_OKAY(XEC_PWM_DEVICE_INIT)

View file

@ -341,6 +341,7 @@
pwm0: pwm@40005800 { pwm0: pwm@40005800 {
compatible = "microchip,xec-pwm"; compatible = "microchip,xec-pwm";
reg = <0x40005800 0x20>; reg = <0x40005800 0x20>;
pcrs = <1 4>;
label = "PWM_0"; label = "PWM_0";
status = "disabled"; status = "disabled";
#pwm-cells = <1>; #pwm-cells = <1>;
@ -348,6 +349,7 @@
pwm1: pwm@40005810 { pwm1: pwm@40005810 {
compatible = "microchip,xec-pwm"; compatible = "microchip,xec-pwm";
reg = <0x40005810 0x20>; reg = <0x40005810 0x20>;
pcrs = <1 20>;
label = "PWM_1"; label = "PWM_1";
status = "disabled"; status = "disabled";
#pwm-cells = <1>; #pwm-cells = <1>;
@ -355,6 +357,7 @@
pwm2: pwm@40005820 { pwm2: pwm@40005820 {
compatible = "microchip,xec-pwm"; compatible = "microchip,xec-pwm";
reg = <0x40005820 0x20>; reg = <0x40005820 0x20>;
pcrs = <1 21>;
label = "PWM_2"; label = "PWM_2";
status = "disabled"; status = "disabled";
#pwm-cells = <1>; #pwm-cells = <1>;
@ -362,6 +365,7 @@
pwm3: pwm@40005830 { pwm3: pwm@40005830 {
compatible = "microchip,xec-pwm"; compatible = "microchip,xec-pwm";
reg = <0x40005830 0x20>; reg = <0x40005830 0x20>;
pcrs = <1 22>;
label = "PWM_3"; label = "PWM_3";
status = "disabled"; status = "disabled";
#pwm-cells = <1>; #pwm-cells = <1>;
@ -369,6 +373,7 @@
pwm4: pwm@40005840 { pwm4: pwm@40005840 {
compatible = "microchip,xec-pwm"; compatible = "microchip,xec-pwm";
reg = <0x40005840 0x20>; reg = <0x40005840 0x20>;
pcrs = <1 23>;
label = "PWM_4"; label = "PWM_4";
status = "disabled"; status = "disabled";
#pwm-cells = <1>; #pwm-cells = <1>;
@ -376,6 +381,7 @@
pwm5: pwm@40005850 { pwm5: pwm@40005850 {
compatible = "microchip,xec-pwm"; compatible = "microchip,xec-pwm";
reg = <0x40005850 0x20>; reg = <0x40005850 0x20>;
pcrs = <1 24>;
label = "PWM_5"; label = "PWM_5";
status = "disabled"; status = "disabled";
#pwm-cells = <1>; #pwm-cells = <1>;
@ -383,6 +389,7 @@
pwm6: pwm@40005860 { pwm6: pwm@40005860 {
compatible = "microchip,xec-pwm"; compatible = "microchip,xec-pwm";
reg = <0x40005860 0x20>; reg = <0x40005860 0x20>;
pcrs = <1 25>;
label = "PWM_6"; label = "PWM_6";
status = "disabled"; status = "disabled";
#pwm-cells = <1>; #pwm-cells = <1>;
@ -390,6 +397,7 @@
pwm7: pwm@40005870 { pwm7: pwm@40005870 {
compatible = "microchip,xec-pwm"; compatible = "microchip,xec-pwm";
reg = <0x40005870 0x20>; reg = <0x40005870 0x20>;
pcrs = <1 26>;
label = "PWM_7"; label = "PWM_7";
status = "disabled"; status = "disabled";
#pwm-cells = <1>; #pwm-cells = <1>;
@ -397,6 +405,7 @@
pwm8: pwm@40005880 { pwm8: pwm@40005880 {
compatible = "microchip,xec-pwm"; compatible = "microchip,xec-pwm";
reg = <0x40005880 0x20>; reg = <0x40005880 0x20>;
pcrs = <1 27>;
label = "PWM_8"; label = "PWM_8";
status = "disabled"; status = "disabled";
#pwm-cells = <1>; #pwm-cells = <1>;

View file

@ -587,6 +587,7 @@
status = "disabled"; status = "disabled";
}; };
pwm0: pwm@40005800 { pwm0: pwm@40005800 {
compatible = "microchip,xec-pwm";
reg = <0x40005800 0x20>; reg = <0x40005800 0x20>;
pcrs = <1 4>; pcrs = <1 4>;
label = "PWM_0"; label = "PWM_0";
@ -594,6 +595,7 @@
#pwm-cells = <1>; #pwm-cells = <1>;
}; };
pwm1: pwm@40005810 { pwm1: pwm@40005810 {
compatible = "microchip,xec-pwm";
reg = <0x40005810 0x20>; reg = <0x40005810 0x20>;
pcrs = <1 20>; pcrs = <1 20>;
label = "PWM_1"; label = "PWM_1";
@ -601,6 +603,7 @@
#pwm-cells = <1>; #pwm-cells = <1>;
}; };
pwm2: pwm@40005820 { pwm2: pwm@40005820 {
compatible = "microchip,xec-pwm";
reg = <0x40005820 0x20>; reg = <0x40005820 0x20>;
pcrs = <1 21>; pcrs = <1 21>;
label = "PWM_2"; label = "PWM_2";
@ -608,6 +611,7 @@
#pwm-cells = <1>; #pwm-cells = <1>;
}; };
pwm3: pwm@40005830 { pwm3: pwm@40005830 {
compatible = "microchip,xec-pwm";
reg = <0x40005830 0x20>; reg = <0x40005830 0x20>;
pcrs = <1 22>; pcrs = <1 22>;
label = "PWM_3"; label = "PWM_3";
@ -615,6 +619,7 @@
#pwm-cells = <1>; #pwm-cells = <1>;
}; };
pwm4: pwm@40005840 { pwm4: pwm@40005840 {
compatible = "microchip,xec-pwm";
reg = <0x40005840 0x20>; reg = <0x40005840 0x20>;
pcrs = <1 23>; pcrs = <1 23>;
label = "PWM_4"; label = "PWM_4";
@ -622,6 +627,7 @@
#pwm-cells = <1>; #pwm-cells = <1>;
}; };
pwm5: pwm@40005850 { pwm5: pwm@40005850 {
compatible = "microchip,xec-pwm";
reg = <0x40005850 0x20>; reg = <0x40005850 0x20>;
pcrs = <1 24>; pcrs = <1 24>;
label = "PWM_5"; label = "PWM_5";
@ -629,6 +635,7 @@
#pwm-cells = <1>; #pwm-cells = <1>;
}; };
pwm6: pwm@40005860 { pwm6: pwm@40005860 {
compatible = "microchip,xec-pwm";
reg = <0x40005860 0x20>; reg = <0x40005860 0x20>;
pcrs = <1 25>; pcrs = <1 25>;
label = "PWM_6"; label = "PWM_6";
@ -636,6 +643,7 @@
#pwm-cells = <1>; #pwm-cells = <1>;
}; };
pwm7: pwm@40005870 { pwm7: pwm@40005870 {
compatible = "microchip,xec-pwm";
reg = <0x40005870 0x20>; reg = <0x40005870 0x20>;
pcrs = <1 26>; pcrs = <1 26>;
label = "PWM_7"; label = "PWM_7";
@ -643,6 +651,7 @@
#pwm-cells = <1>; #pwm-cells = <1>;
}; };
pwm8: pwm@40005880 { pwm8: pwm@40005880 {
compatible = "microchip,xec-pwm";
reg = <0x40005880 0x20>; reg = <0x40005880 0x20>;
pcrs = <1 27>; pcrs = <1 27>;
label = "PWM_8"; label = "PWM_8";

View file

@ -13,3 +13,12 @@ properties:
label: label:
required: true required: true
pcrs:
type: array
required: true
description: PWM PCR register index and bit position
pcr-cells:
- regidx
- bitpos