Intel® Quark™ Microcontroller Software Interface  1.4.0
Intel® Quark™ Microcontroller BSP
qm_pwm.c
1 /*
2  * {% copyright %}
3  */
4 
5 #include "qm_pwm.h"
6 
7 /* Store callback information for each PWM channel. */
8 static void (*callback[QM_PWM_NUM][QM_PWM_ID_NUM])(void *data,
9  uint32_t int_status);
10 static void *callback_data[QM_PWM_NUM][QM_PWM_ID_NUM];
11 
12 #if (NUM_PWM_CONTROLLER_INTERRUPTS > 1)
13 const uint32_t pwm_isr_vectors[QM_PWM_ID_NUM] = {
14  QM_IRQ_PWM_0_INT_0_PRIORITY, QM_IRQ_PWM_0_INT_1_PRIORITY,
15  QM_IRQ_PWM_0_INT_2_PRIORITY, QM_IRQ_PWM_0_INT_3_PRIORITY};
16 #endif /* NUM_PWM_CONTROLLER_INTERRUPTS > 1 */
17 
18 #ifndef UNIT_TEST
19 qm_pwm_reg_t *qm_pwm[QM_PWM_NUM] = {(qm_pwm_reg_t *)(QM_PWM_BASE)};
20 #endif /* UNIT_TEST */
21 
22 #if (NUM_PWM_CONTROLLER_INTERRUPTS > 1)
23 /*
24  * If there is more than one interrupt line for PWM, use a common handler
25  * and only clear the corresponding interrupt IRQ.
26  */
27 /* Interrupt service routine handler for PWM channels. */
28 static void pwm_isr_handler(const qm_pwm_t pwm, const qm_pwm_id_t id)
29 {
30  qm_pwm_reg_t *const controller = QM_PWM[pwm];
31  /* Check for callback function. */
32  if (callback[pwm][id]) {
33  (callback[pwm][id])(callback_data[pwm][id], BIT(id));
34  }
35 
36  /* Clear interrupt on read. */
37  controller->timer[id].eoi;
38  QM_ISR_EOI(pwm_isr_vectors[id]);
39 }
40 
41 QM_ISR_DECLARE(qm_pwm_0_isr_0)
42 {
43  pwm_isr_handler(QM_PWM_0, QM_PWM_ID_0);
44 }
45 
46 QM_ISR_DECLARE(qm_pwm_0_isr_1)
47 {
48  pwm_isr_handler(QM_PWM_0, QM_PWM_ID_1);
49 }
50 
51 QM_ISR_DECLARE(qm_pwm_0_isr_2)
52 {
53  pwm_isr_handler(QM_PWM_0, QM_PWM_ID_2);
54 }
55 
56 QM_ISR_DECLARE(qm_pwm_0_isr_3)
57 {
58  pwm_isr_handler(QM_PWM_0, QM_PWM_ID_3);
59 }
60 
61 #else /* NUM_PWM_CONTROLLER_INTERRUPTS > 1 */
62 QM_ISR_DECLARE(qm_pwm_0_isr_0)
63 {
64  qm_pwm_reg_t *const controller = QM_PWM[QM_PWM_0];
65  uint32_t int_status = controller->timersintstatus;
66  uint8_t pwm_id = 0;
67 
68  for (; pwm_id < QM_PWM_ID_NUM; pwm_id++) {
69  if (int_status & BIT(pwm_id)) {
70  if (callback[QM_PWM_0][pwm_id]) {
71  (*callback[QM_PWM_0][pwm_id])(
72  callback_data[QM_PWM_0][pwm_id],
73  BIT(pwm_id));
74  controller->timer[pwm_id].eoi;
75  }
76  }
77  }
78  QM_ISR_EOI(QM_IRQ_PWM_0_INT_VECTOR);
79 }
80 
81 #endif /* NUM_PWM_CONTROLLER_INTERRUPTS > 1 */
82 
83 int qm_pwm_start(const qm_pwm_t pwm, const qm_pwm_id_t id)
84 {
85  QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
86  QM_CHECK(id < QM_PWM_ID_NUM, -EINVAL);
87 
88  qm_pwm_reg_t *const controller = QM_PWM[pwm];
89  controller->timer[id].controlreg |= PWM_START;
90 
91  return 0;
92 }
93 
94 int qm_pwm_stop(const qm_pwm_t pwm, const qm_pwm_id_t id)
95 {
96  QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
97  QM_CHECK(id < QM_PWM_ID_NUM, -EINVAL);
98 
99  qm_pwm_reg_t *const controller = QM_PWM[pwm];
100 
101  controller->timer[id].controlreg &= ~PWM_START;
102 
103  return 0;
104 }
105 
106 int qm_pwm_set_config(const qm_pwm_t pwm, const qm_pwm_id_t id,
107  const qm_pwm_config_t *const cfg)
108 {
109  QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
110  QM_CHECK(id < QM_PWM_ID_NUM, -EINVAL);
111  QM_CHECK(cfg != NULL, -EINVAL);
112  QM_CHECK(cfg->mode <= QM_PWM_MODE_PWM, -EINVAL);
113  QM_CHECK(0 < cfg->lo_count, -EINVAL);
114  /* If mode is PWM, hi_count must be > 0, otherwise don't care. */
115  QM_CHECK(cfg->mode == QM_PWM_MODE_PWM ? 0 != cfg->hi_count : 1,
116  -EINVAL);
117 
118  qm_pwm_reg_t *const controller = QM_PWM[pwm];
119  controller->timer[id].loadcount = cfg->lo_count - 1;
120  controller->timer[id].controlreg =
121  (cfg->mode | (cfg->mask_interrupt << QM_PWM_INTERRUPT_MASK_OFFSET));
122  controller->timer_loadcount2[id] = cfg->hi_count - 1;
123 
124  /* Assign user callback function. */
125  callback[pwm][id] = cfg->callback;
126  callback_data[pwm][id] = cfg->callback_data;
127 
128  return 0;
129 }
130 
131 int qm_pwm_set(const qm_pwm_t pwm, const qm_pwm_id_t id,
132  const uint32_t lo_count, const uint32_t hi_count)
133 {
134  QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
135  QM_CHECK(id < QM_PWM_ID_NUM, -EINVAL);
136  QM_CHECK(0 < lo_count, -EINVAL);
137  /* If mode is PWM, hi_count must be > 0, otherwise don't care. */
138  QM_CHECK(((QM_PWM[pwm]->timer[id].controlreg & QM_PWM_CONF_MODE_MASK) ==
139  QM_PWM_MODE_PWM
140  ? 0 < hi_count
141  : 1),
142  -EINVAL);
143 
144  qm_pwm_reg_t *const controller = QM_PWM[pwm];
145  controller->timer[id].loadcount = lo_count - 1;
146  controller->timer_loadcount2[id] = hi_count - 1;
147 
148  return 0;
149 }
150 
151 int qm_pwm_get(const qm_pwm_t pwm, const qm_pwm_id_t id,
152  uint32_t *const lo_count, uint32_t *const hi_count)
153 {
154  QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
155  QM_CHECK(id < QM_PWM_ID_NUM, -EINVAL);
156  QM_CHECK(lo_count != NULL, -EINVAL);
157  QM_CHECK(hi_count != NULL, -EINVAL);
158 
159  qm_pwm_reg_t *const controller = QM_PWM[pwm];
160  *lo_count = controller->timer[id].loadcount;
161  *hi_count = controller->timer_loadcount2[id];
162 
163  return 0;
164 }
165 
166 #if (ENABLE_RESTORE_CONTEXT)
168 {
169  QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
170  QM_CHECK(ctx != NULL, -EINVAL);
171 
172  qm_pwm_reg_t *const controller = QM_PWM[pwm];
173  uint8_t i;
174 
175  for (i = 0; i < QM_PWM_ID_NUM; i++) {
176  ctx->channel[i].loadcount = controller->timer[i].loadcount;
177  ctx->channel[i].controlreg = controller->timer[i].controlreg;
178  ctx->channel[i].loadcount2 = controller->timer_loadcount2[i];
179  }
180 
181  return 0;
182 }
183 
185  const qm_pwm_context_t *const ctx)
186 {
187  QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
188  QM_CHECK(ctx != NULL, -EINVAL);
189 
190  qm_pwm_reg_t *const controller = QM_PWM[pwm];
191  uint8_t i;
192 
193  for (i = 0; i < QM_PWM_ID_NUM; i++) {
194  controller->timer[i].loadcount = ctx->channel[i].loadcount;
195  controller->timer[i].controlreg = ctx->channel[i].controlreg;
196  controller->timer_loadcount2[i] = ctx->channel[i].loadcount2;
197  }
198 
199  return 0;
200 }
201 #else
203 {
204  (void)pwm;
205  (void)ctx;
206 
207  return 0;
208 }
209 
211  const qm_pwm_context_t *const ctx)
212 {
213  (void)pwm;
214  (void)ctx;
215 
216  return 0;
217 }
218 #endif /* ENABLE_RESTORE_CONTEXT */
void(* callback)(void *data, uint32_t int_status)
User callback.
Definition: qm_pwm.h:53
uint32_t lo_count
Number of cycles the PWM output is driven low.
Definition: qm_pwm.h:38
int qm_pwm_set(const qm_pwm_t pwm, const qm_pwm_id_t id, const uint32_t lo_count, const uint32_t hi_count)
Set the next period values of a PWM channel.
Definition: qm_pwm.c:131
int qm_pwm_restore_context(const qm_pwm_t pwm, const qm_pwm_context_t *const ctx)
Restore PWM peripheral's context.
Definition: qm_pwm.c:184
void * callback_data
Callback user data.
Definition: qm_pwm.h:54
int qm_pwm_start(const qm_pwm_t pwm, const qm_pwm_id_t id)
Start a PWM/timer channel.
Definition: qm_pwm.c:83
qm_pwm_mode_t mode
Pwm mode.
Definition: qm_pwm.h:45
qm_pwm_channel_t timer[QM_PWM_ID_NUM]
2 Timers.
Definition: qm_soc_regs.h:399
QM_RW uint32_t loadcount
Load Coun.t.
Definition: qm_soc_regs.h:390
PWM context type.
Definition: qm_soc_regs.h:702
PWM / Timer register map.
Definition: qm_soc_regs.h:398
uint32_t loadcount
Load Count 1.
Definition: qm_soc_regs.h:704
QM PWM / Timer configuration type.
Definition: qm_pwm.h:33
int qm_pwm_set_config(const qm_pwm_t pwm, const qm_pwm_id_t id, const qm_pwm_config_t *const cfg)
Change the configuration of a PWM channel.
Definition: qm_pwm.c:106
QM_RW uint32_t timer_loadcount2[QM_PWM_ID_NUM]
Timer Load Count 2.
Definition: qm_soc_regs.h:406
QM_RW uint32_t timersintstatus
Timers Interrupt Status.
Definition: qm_soc_regs.h:401
int qm_pwm_save_context(const qm_pwm_t pwm, qm_pwm_context_t *const ctx)
Save PWM peripheral's context.
Definition: qm_pwm.c:167
bool mask_interrupt
Mask interrupt.
Definition: qm_pwm.h:44
QM_ISR_DECLARE(qm_pwm_0_isr_0)
ISR for PWM 0 Channel 0 interrupt.
Definition: qm_pwm.c:41
qm_pwm_id_t
PWM ID type.
Definition: qm_soc_regs.h:386
int qm_pwm_stop(const qm_pwm_t pwm, const qm_pwm_id_t id)
Stop a PWM/timer channel.
Definition: qm_pwm.c:94
QM_RW uint32_t controlreg
Control.
Definition: qm_soc_regs.h:392
uint32_t loadcount2
Load Count 2.
Definition: qm_soc_regs.h:705
QM_RW uint32_t eoi
End Of Interrupt.
Definition: qm_soc_regs.h:393
qm_pwm_t
Number of PWM / Timer controllers.
Definition: qm_soc_regs.h:383
int qm_pwm_get(const qm_pwm_t pwm, const qm_pwm_id_t id, uint32_t *const lo_count, uint32_t *const hi_count)
Get the current period values of a PWM channel.
Definition: qm_pwm.c:151
uint32_t hi_count
Number of cycles the PWM output is driven high.
Definition: qm_pwm.h:43
uint32_t controlreg
Control Register.
Definition: qm_soc_regs.h:706