forked from andreynech/rtdm-pwm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpwm-task-proc.c
232 lines (189 loc) · 5.26 KB
/
pwm-task-proc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#include <rtdm/rtdm_driver.h>
#include "pwm-task-proc.h"
#include "div100.h"
//extern lldiv_t_rr __aeabi_ldivmod(long long, long long);
/*
* IEN - Input Enable
* IDIS - Input Disable
* PTD - Pull type Down
* PTU - Pull type Up
* DIS - Pull type selection is inactive
* EN - Pull type selection is active
* M0 - Mode 0
*/
#define IEN (1 << 8)
#define IDIS (0 << 8)
#define PTU (1 << 4)
#define PTD (0 << 4)
#define EN (1 << 3)
#define DIS (0 << 3)
#define M0 0
#define M1 1
#define M2 2
#define M3 3
#define M4 4
#define M5 5
#define M6 6
#define M7 7
#define OFFSET(OFF) (OFF / sizeof(ulong))
#define RANGE_MAP100(c, d, x) (c + div100((d - c) * x))
static int RC_NUM = 0;
static rtdm_timer_t up_timer;
static rtdm_timer_t down_timer[8];
static nanosecs_rel_t up_period[8];
static uint8_t reconfigured[8];
// Initialized with default pulse ranges
static int ranges[8][2] = {
{950, 2050},
{950, 2050},
{950, 2050},
{950, 2050},
{950, 2050},
{950, 2050},
{950, 2050},
{950, 2050}
};
// Memory for triggering gpio
static void __iomem *gpio = NULL;
void
pwm_up(rtdm_timer_t *timer)
{
size_t channel = 0; // TODO: should be looked up using timer parameter
int retval;
//set_data_out has offset 0x94
iowrite32(0x40000000, gpio + 0x6094);
//rtdm_task_sleep(2000*1000);
//iowrite32(0x40000000, gpio + 0x6090);
//return;
if(reconfigured[channel])
{
reconfigured[channel] = 0;
rtdm_timer_stop(&down_timer[channel]);
retval = rtdm_timer_start(&down_timer[channel],
up_period[channel], // we will use periodic timer
20000000,
RTDM_TIMERMODE_RELATIVE);
//rtdm_timer_stop_in_handler(&down_timer[channel]);
//retval = rtdm_timer_start_in_handler(&down_timer[channel],
// 0, // we will use periodic timer
// up_period[channel],
// RTDM_TIMERMODE_RELATIVE);
if(retval)
rtdm_printk("PWM: error reconfiguring down-timer #%i: %i\n",
channel, retval);
}
}
void
pwm_down(rtdm_timer_t *timer)
{
//clear_data_out has offset 0x90
iowrite32(0x40000000, gpio + 0x6090);
}
void
setpwmwidth(int channel, int percentage)
{
//rtdm_printk("PWM: %i -> %i\n", channel, percentage);
up_period[channel] = 1000 * RANGE_MAP100(ranges[channel][0],
ranges[channel][1],
percentage);
reconfigured[channel] = 1;
}
nanosecs_rel_t
getpwmwidth(int channel)
{
return up_period[channel];
}
int
initpwm(pwm_desc_t *channels, int nchannels)
{
int i;
int retval;
void __iomem *pinconf;
if(nchannels < 0 || nchannels > 8)
{
rtdm_printk("PWM: number of channels should be between 1 and 8\n");
return 1;
}
RC_NUM = nchannels;
for(i = 0; i < RC_NUM; i++)
{
ranges[channels[i].channel][0] = channels[i].pwmMinWidth;
ranges[channels[i].channel][1] = channels[i].pwmMaxWidth;
up_period[channels[i].channel] =
1000 * RANGE_MAP100(ranges[i][0], ranges[i][1], 50);
reconfigured[i] = 0;
}
rtdm_printk("PWM: pulse lengths initialized\n");
rtdm_printk("PWM: configuring I/O pads mode\n");
pinconf = ioremap(0x48000000, 0x05cc);
if(!pinconf)
{
rtdm_printk("PWM: pinconf mapping failed\n");
return 0;
}
// set lower 16 pins to GPIO bank5
// (EN | PTD | M4) is 0x0C (0b01100)
iowrite16((EN | PTD | M4), pinconf + 0x2190);
iounmap(pinconf);
rtdm_printk("PWM: configuring GPIO bank 5\n");
gpio =
ioremap(0x49050000, 0x05cc);
if(!gpio)
{
rtdm_printk("PWM: GPIO mapping failed\n");
return 0;
}
// 0x4000 0000 - bit 30 is set
// 0x8000 0000 - bit 31 is set
// First set all output on bank5 to high
// (set_data_out has offset 0x94)
iowrite32(0xFFFFFFFF, gpio + 0x6094);
// Configure low 16 GPIO pins on bank 5 as output.
// GPIO 5 is at physical address 0x49056000 = 0x49050000+0x6000
// GPIO Output enable (GPIO_OE) is offset by 0x34 for each bank
// (set low for output)
iowrite32(0x00000000, gpio + 0x6034);
// Also disable the wakeupenable and irqenable intertupts
// GPIO clear_Wakeupenable is offset by 0x80 for each bank
iowrite32(0x0000FFFF, gpio + 0x6080);
// GPIO clear_irqenable1 is offset by 0x60 for each bank
iowrite32(0x0000FFFF, gpio + 0x6060);
// GPIO clear_irqenable2 is offset by 0x70 for each bank
iowrite32(0x0000FFFF, gpio + 0x6070);
rtdm_printk("PWM: Starting PWM generation timers.\n");
retval = rtdm_timer_init(&up_timer, pwm_up, "up timer");
if(retval)
{
rtdm_printk("PWM: error initializing up-timer: %i\n", retval);
return retval;
}
for(i = 0; i < RC_NUM; i++)
{
retval = rtdm_timer_init(&down_timer[i], pwm_down, "down timer");
if(retval)
{
rtdm_printk("PWM: error initializing down-timer #%i: %i\n", i, retval);
return retval;
}
}
retval = rtdm_timer_start(&up_timer,
20000000, // we will use periodic timer
20000000, // 20ms period
RTDM_TIMERMODE_RELATIVE);
if(retval)
{
rtdm_printk("PWM: error starting up-timer: %i\n", retval);
return retval;
}
rtdm_printk("PWM: timers created\n");
return 0;
}
void
cleanuppwm(void)
{
int i = 0;
rtdm_timer_destroy(&up_timer);
for(; i < RC_NUM; ++i)
rtdm_timer_destroy(&down_timer[i]);
iounmap(gpio);
}