1 | /* |
---|
2 | * GRPWM PWM Driver interface. |
---|
3 | * |
---|
4 | * COPYRIGHT (c) 2009. |
---|
5 | * Cobham Gaisler AB, |
---|
6 | * |
---|
7 | * The license and distribution terms for this file may be |
---|
8 | * found in the file LICENSE in this distribution or at |
---|
9 | * http://www.rtems.com/license/LICENSE. |
---|
10 | */ |
---|
11 | |
---|
12 | #include <bsp.h> |
---|
13 | #include <rtems/libio.h> |
---|
14 | #include <stdlib.h> |
---|
15 | #include <assert.h> |
---|
16 | #include <rtems/bspIo.h> |
---|
17 | #include <string.h> |
---|
18 | #include <stdio.h> |
---|
19 | |
---|
20 | #include <drvmgr/drvmgr.h> |
---|
21 | #include <drvmgr/ambapp_bus.h> |
---|
22 | #include <bsp/grpwm.h> |
---|
23 | #include <ambapp.h> |
---|
24 | |
---|
25 | /* #define DEBUG 1 */ |
---|
26 | |
---|
27 | #ifdef DEBUG |
---|
28 | #define DBG(x...) printk(x) |
---|
29 | #define STATIC |
---|
30 | #else |
---|
31 | #define DBG(x...) |
---|
32 | #define STATIC static |
---|
33 | #endif |
---|
34 | |
---|
35 | /*** REGISTER LAYOUT ***/ |
---|
36 | |
---|
37 | /* PWM Channel specific registers */ |
---|
38 | struct grpwm_pwm_regs { |
---|
39 | volatile unsigned int period; /* 0x00 */ |
---|
40 | volatile unsigned int comp; /* 0x04 */ |
---|
41 | volatile unsigned int dbcomp; /* 0x08 */ |
---|
42 | volatile unsigned int ctrl; /* 0x0C */ |
---|
43 | }; |
---|
44 | |
---|
45 | /* Core common registers */ |
---|
46 | struct grpwm_regs { |
---|
47 | volatile unsigned int ctrl; /* 0x00 */ |
---|
48 | volatile unsigned int scaler; /* 0x04 */ |
---|
49 | volatile unsigned int ipend; /* 0x08 */ |
---|
50 | volatile unsigned int cap1; /* 0x0C */ |
---|
51 | volatile unsigned int cap2; /* 0x10 */ |
---|
52 | volatile unsigned int wctrl; /* 0x14 */ |
---|
53 | int reserved0[2]; |
---|
54 | struct grpwm_pwm_regs pwms[8]; /* 0x20 */ |
---|
55 | int reserved1[(0x8000-0xA0)/4]; /* 0xA0-0x7FFC */ |
---|
56 | volatile unsigned int wram[0x8000/4]; /* 0x8000-0xFFFC */ |
---|
57 | }; |
---|
58 | |
---|
59 | /*** REGISTER BIT LAYOUT ***/ |
---|
60 | |
---|
61 | /* CTRL REGISTER - 0x0 */ |
---|
62 | #define GRPWM_CTRL_EN_BIT 0 |
---|
63 | #define GRPWM_CTRL_SCSEL_BIT 8 |
---|
64 | #define GRPWM_CTRL_NOUP_BIT 12 |
---|
65 | #define GRPWM_CTRL_EN (1<<GRPWM_CTRL_EN_BIT) |
---|
66 | #define GRPWM_CTRL_SCSEL (0x7<<GRPWM_CTRL_SCSEL_BIT) |
---|
67 | #define GRPWM_CTRL_NOUP (0xff<<GRPWM_CTRL_NOUP_BIT) |
---|
68 | |
---|
69 | |
---|
70 | /* CAPABILITY1 REGISTER - 0x0C */ |
---|
71 | #define GRPWM_CAP_NPWM_BIT 0 |
---|
72 | #define GRPWM_CAP_PBITS_BIT 3 |
---|
73 | #define GRPWM_CAP_SBITS_BIT 8 |
---|
74 | #define GRPWM_CAP_NSC_BIT 13 |
---|
75 | #define GRPWM_CAP_DBB_BIT 16 |
---|
76 | #define GRPWM_CAP_DBSC_BIT 21 |
---|
77 | #define GRPWM_CAP_ASY_BIT 22 |
---|
78 | #define GRPWM_CAP_SYM_BIT 23 |
---|
79 | #define GRPWM_CAP_SEP_BIT 25 |
---|
80 | #define GRPWM_CAP_DCM_BIT 27 |
---|
81 | |
---|
82 | #define GRPWM_CAP_NPWM (0x7<<GRPWM_CAP_NPWM_BIT) |
---|
83 | #define GRPWM_CAP_PBITS (0x1f<<GRPWM_CAP_PBITS_BIT) |
---|
84 | #define GRPWM_CAP_SBITS (0x1f<<GRPWM_CAP_SBITS_BIT) |
---|
85 | #define GRPWM_CAP_NSC (0x7<<GRPWM_CAP_NSC_BIT) |
---|
86 | #define GRPWM_CAP_DBB (0x1f<<GRPWM_CAP_DBB_BIT) |
---|
87 | #define GRPWM_CAP_DBSC (1<<GRPWM_CAP_DBSC_BIT) |
---|
88 | #define GRPWM_CAP_ASY (1<<GRPWM_CAP_ASY_BIT) |
---|
89 | #define GRPWM_CAP_SYM (1<<GRPWM_CAP_SYM_BIT) |
---|
90 | #define GRPWM_CAP_SEP (0x3<<GRPWM_CAP_SEP_BIT) |
---|
91 | #define GRPWM_CAP_DCM (1<<GRPWM_CAP_DCM_BIT) |
---|
92 | |
---|
93 | /* CAPABILITY2 REGISTER - 0x10 */ |
---|
94 | #define GRPWM_CAP2_WPWM_BIT 0 |
---|
95 | #define GRPWM_CAP2_WDBITS_BIT 1 |
---|
96 | #define GRPWM_CAP2_WABITS_BIT 6 |
---|
97 | #define GRPWM_CAP2_WSYNC_BIT 10 |
---|
98 | |
---|
99 | #define GRPWM_CAP2_WPWM (0x1<<GRPWM_CAP2_WPWM_BIT) |
---|
100 | #define GRPWM_CAP2_WDBITS (0x1f<<GRPWM_CAP2_WDBITS_BIT) |
---|
101 | #define GRPWM_CAP2_WABITS (0xf<<GRPWM_CAP2_WABITS_BIT) |
---|
102 | #define GRPWM_CAP2_WSYNC (1<<GRPWM_CAP2_WSYNC_BIT) |
---|
103 | |
---|
104 | /* WAVE FORM CONFIG REGISTER - 0x14 */ |
---|
105 | #define GRPWM_WCTRL_STOP_BIT 0 |
---|
106 | #define GRPWM_WCTRL_WSYNC_BIT 16 |
---|
107 | #define GRPWM_WCTRL_WSEN_BIT 29 |
---|
108 | #define GRPWM_WCTRL_WSYNCCFG_BIT 30 |
---|
109 | |
---|
110 | #define GRPWM_WCTRL_STOP (0x1fff<<GRPWM_WCTRL_STOP_BIT) |
---|
111 | #define GRPWM_WCTRL_WSYNC (0x1fff<<GRPWM_WCTRL_WSYNC_BIT) |
---|
112 | #define GRPWM_WCTRL_WSEN (0x1<<GRPWM_WCTRL_WSEN_BIT) |
---|
113 | #define GRPWM_WCTRL_WSYNCCFG (0x3<<GRPWM_WCTRL_WSYNCCFG_BIT) |
---|
114 | |
---|
115 | |
---|
116 | /* PWM CONTROL REGISTER - 0x2C, 0x3C... */ |
---|
117 | #define GRPWM_PCTRL_EN_BIT 0 |
---|
118 | #define GRPWM_PCTRL_POL_BIT 1 |
---|
119 | #define GRPWM_PCTRL_PAIR_BIT 2 |
---|
120 | #define GRPWM_PCTRL_FIX_BIT 3 |
---|
121 | #define GRPWM_PCTRL_METH_BIT 6 |
---|
122 | #define GRPWM_PCTRL_DCEN_BIT 8 |
---|
123 | #define GRPWM_PCTRL_WEN_BIT 9 |
---|
124 | #define GRPWM_PCTRL_SCSEL_BIT 10 |
---|
125 | #define GRPWM_PCTRL_IEN_BIT 13 |
---|
126 | #define GRPWM_PCTRL_IT_BIT 14 |
---|
127 | #define GRPWM_PCTRL_ISC_BIT 15 |
---|
128 | #define GRPWM_PCTRL_DBEN_BIT 21 |
---|
129 | #define GRPWM_PCTRL_DBSC_BIT 22 |
---|
130 | #define GRPWM_PCTRL_FLIP_BIT 26 |
---|
131 | |
---|
132 | #define GRPWM_PCTRL_EN (0x1<<GRPWM_PCTRL_EN_BIT) |
---|
133 | #define GRPWM_PCTRL_POL (0x1<<GRPWM_PCTRL_POL_BIT) |
---|
134 | #define GRPWM_PCTRL_PAIR (0x1<<GRPWM_PCTRL_PAIR_BIT) |
---|
135 | #define GRPWM_PCTRL_FIX (0x7<<GRPWM_PCTRL_FIX_BIT) |
---|
136 | #define GRPWM_PCTRL_METH (0x1<<GRPWM_PCTRL_METH_BIT) |
---|
137 | #define GRPWM_PCTRL_DCEN (0x1<<GRPWM_PCTRL_DCEN_BIT) |
---|
138 | #define GRPWM_PCTRL_WEN (0x1<<GRPWM_PCTRL_WEN_BIT) |
---|
139 | #define GRPWM_PCTRL_SCSEL (0x7<<GRPWM_PCTRL_SCSEL_BIT) |
---|
140 | #define GRPWM_PCTRL_IEN (0x1<<GRPWM_PCTRL_IEN_BIT) |
---|
141 | #define GRPWM_PCTRL_IT (0x1<<GRPWM_PCTRL_IT_BIT) |
---|
142 | #define GRPWM_PCTRL_ISC (0x3f<<GRPWM_PCTRL_ISC_BIT) |
---|
143 | #define GRPWM_PCTRL_DBEN (0x1<<GRPWM_PCTRL_DBEN_BIT) |
---|
144 | #define GRPWM_PCTRL_DBSC (0xf<<GRPWM_PCTRL_DBSC_BIT) |
---|
145 | #define GRPWM_PCTRL_FLIP (0xf<<GRPWM_PCTRL_FLIP_BIT) |
---|
146 | |
---|
147 | /*** DRIVER PRIVATE STRUCTURE ***/ |
---|
148 | struct grpwm_priv { |
---|
149 | struct drvmgr_dev *dev; |
---|
150 | struct grpwm_regs *regs; |
---|
151 | char devName[32]; |
---|
152 | int irq; |
---|
153 | int open; |
---|
154 | |
---|
155 | /* Driver implementation */ |
---|
156 | char nscalers; /* Number of scalers */ |
---|
157 | char wave; /* If Wave form is available */ |
---|
158 | int wlength; /* Wave Form RAM Length */ |
---|
159 | int channel_cnt; |
---|
160 | struct grpwm_chan_priv *channels[8]; |
---|
161 | rtems_id dev_sem; |
---|
162 | }; |
---|
163 | |
---|
164 | struct grpwm_chan_priv { |
---|
165 | struct grpwm_priv *common; |
---|
166 | struct grpwm_pwm_regs *pwmregs; |
---|
167 | /* IRQ */ |
---|
168 | int irqindex; |
---|
169 | void (*isr)(int channel, void *arg); |
---|
170 | void *isr_arg; |
---|
171 | }; |
---|
172 | |
---|
173 | /******************* Driver Manager Part ***********************/ |
---|
174 | |
---|
175 | int grpwm_device_init(struct grpwm_priv *priv); |
---|
176 | int grpwm_register_io(rtems_device_major_number *m); |
---|
177 | static int grpwm_driver_io_registered = 0; |
---|
178 | static rtems_device_major_number grpwm_driver_io_major = 0; |
---|
179 | |
---|
180 | int grpwm_init2(struct drvmgr_dev *dev); |
---|
181 | int grpwm_init3(struct drvmgr_dev *dev); |
---|
182 | |
---|
183 | struct drvmgr_drv_ops grpwm_ops = |
---|
184 | { |
---|
185 | .init = {NULL, grpwm_init2, grpwm_init3, NULL}, |
---|
186 | .remove = NULL, |
---|
187 | .info = NULL |
---|
188 | }; |
---|
189 | |
---|
190 | struct amba_dev_id grpwm_ids[] = |
---|
191 | { |
---|
192 | {VENDOR_GAISLER, GAISLER_GRPWM}, |
---|
193 | {0, 0} /* Mark end of table */ |
---|
194 | }; |
---|
195 | |
---|
196 | struct amba_drv_info grpwm_drv_info = |
---|
197 | { |
---|
198 | { |
---|
199 | DRVMGR_OBJ_DRV, /* Driver */ |
---|
200 | NULL, /* Next driver */ |
---|
201 | NULL, /* Device list */ |
---|
202 | DRIVER_AMBAPP_GAISLER_GRPWM_ID, /* Driver ID */ |
---|
203 | "GRPWM_DRV", /* Driver Name */ |
---|
204 | DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ |
---|
205 | &grpwm_ops, |
---|
206 | NULL, /* Funcs */ |
---|
207 | 0, /* No devices yet */ |
---|
208 | 0, |
---|
209 | }, |
---|
210 | &grpwm_ids[0] |
---|
211 | }; |
---|
212 | |
---|
213 | void grpwm_register_drv (void) |
---|
214 | { |
---|
215 | DBG("Registering GRPWM driver\n"); |
---|
216 | drvmgr_drv_register(&grpwm_drv_info.general); |
---|
217 | } |
---|
218 | |
---|
219 | int grpwm_init2(struct drvmgr_dev *dev) |
---|
220 | { |
---|
221 | struct grpwm_priv *priv; |
---|
222 | |
---|
223 | DBG("GRPWM[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); |
---|
224 | |
---|
225 | priv = dev->priv = malloc(sizeof(struct grpwm_priv)); |
---|
226 | if ( !priv ) |
---|
227 | return DRVMGR_NOMEM; |
---|
228 | memset(priv, 0, sizeof(*priv)); |
---|
229 | priv->dev = dev; |
---|
230 | |
---|
231 | /* This core will not find other cores, so we wait for init2() */ |
---|
232 | |
---|
233 | return DRVMGR_OK; |
---|
234 | } |
---|
235 | |
---|
236 | int grpwm_init3(struct drvmgr_dev *dev) |
---|
237 | { |
---|
238 | struct grpwm_priv *priv = dev->priv; |
---|
239 | char prefix[32]; |
---|
240 | rtems_status_code status; |
---|
241 | |
---|
242 | if ( !priv ) |
---|
243 | return DRVMGR_FAIL; |
---|
244 | |
---|
245 | if ( grpwm_driver_io_registered == 0) { |
---|
246 | /* Register the I/O driver only once for all cores */ |
---|
247 | if ( grpwm_register_io(&grpwm_driver_io_major) ) { |
---|
248 | /* Failed to register I/O driver */ |
---|
249 | dev->priv = NULL; |
---|
250 | return DRVMGR_FAIL; |
---|
251 | } |
---|
252 | |
---|
253 | grpwm_driver_io_registered = 1; |
---|
254 | } |
---|
255 | |
---|
256 | /* I/O system registered and initialized |
---|
257 | * Now we take care of device initialization. |
---|
258 | */ |
---|
259 | if ( grpwm_device_init(priv) ) { |
---|
260 | free(dev->priv); |
---|
261 | dev->priv = NULL; |
---|
262 | return DRVMGR_FAIL; |
---|
263 | } |
---|
264 | |
---|
265 | /* Get Filesystem name prefix */ |
---|
266 | prefix[0] = '\0'; |
---|
267 | if ( drvmgr_get_dev_prefix(dev, prefix) ) { |
---|
268 | /* Failed to get prefix, make sure of a unique FS name |
---|
269 | * by using the driver minor. |
---|
270 | */ |
---|
271 | sprintf(priv->devName, "/dev/grpwm%d", dev->minor_drv); |
---|
272 | } else { |
---|
273 | /* Got special prefix, this means we have a bus prefix |
---|
274 | * And we should use our "bus minor" |
---|
275 | */ |
---|
276 | sprintf(priv->devName, "/dev/%sgrpwm%d", prefix, dev->minor_bus); |
---|
277 | } |
---|
278 | |
---|
279 | /* Register Device */ |
---|
280 | status = rtems_io_register_name(priv->devName, grpwm_driver_io_major, |
---|
281 | dev->minor_drv); |
---|
282 | if (status != RTEMS_SUCCESSFUL) { |
---|
283 | return DRVMGR_FAIL; |
---|
284 | } |
---|
285 | |
---|
286 | return DRVMGR_OK; |
---|
287 | } |
---|
288 | |
---|
289 | /******************* Driver Implementation ***********************/ |
---|
290 | |
---|
291 | static rtems_device_driver grpwm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
292 | static rtems_device_driver grpwm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
293 | static rtems_device_driver grpwm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
294 | static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
295 | static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
296 | static rtems_device_driver grpwm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
297 | |
---|
298 | #define GRPWM_DRIVER_TABLE_ENTRY { grpwm_initialize, grpwm_open, grpwm_close, grpwm_read, grpwm_write, grpwm_ioctl } |
---|
299 | |
---|
300 | static rtems_driver_address_table grpwm_driver = GRPWM_DRIVER_TABLE_ENTRY; |
---|
301 | |
---|
302 | int grpwm_register_io(rtems_device_major_number *m) |
---|
303 | { |
---|
304 | rtems_status_code r; |
---|
305 | |
---|
306 | if ((r = rtems_io_register_driver(0, &grpwm_driver, m)) == RTEMS_SUCCESSFUL) { |
---|
307 | DBG("GRPWM driver successfully registered, major: %d\n", *m); |
---|
308 | } else { |
---|
309 | switch(r) { |
---|
310 | case RTEMS_TOO_MANY: |
---|
311 | DBG("GRPWM rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); |
---|
312 | return -1; |
---|
313 | case RTEMS_INVALID_NUMBER: |
---|
314 | DBG("GRPWM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); |
---|
315 | return -1; |
---|
316 | case RTEMS_RESOURCE_IN_USE: |
---|
317 | DBG("GRPWM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); |
---|
318 | return -1; |
---|
319 | default: |
---|
320 | DBG("GRPWM rtems_io_register_driver failed\n"); |
---|
321 | return -1; |
---|
322 | } |
---|
323 | } |
---|
324 | return 0; |
---|
325 | } |
---|
326 | |
---|
327 | static void grpwm_scaler_set( |
---|
328 | struct grpwm_regs *regs, |
---|
329 | int scaler, |
---|
330 | unsigned int value) |
---|
331 | { |
---|
332 | /* Select scaler */ |
---|
333 | regs->ctrl = (regs->ctrl & ~GRPWM_CTRL_SCSEL) | (scaler << GRPWM_CTRL_SCSEL_BIT); |
---|
334 | /* Write scaler */ |
---|
335 | regs->scaler = value; |
---|
336 | } |
---|
337 | |
---|
338 | /* Write Wave form RAM */ |
---|
339 | static void grpwm_write_wram( |
---|
340 | struct grpwm_regs *regs, |
---|
341 | unsigned int *data, |
---|
342 | int length) |
---|
343 | { |
---|
344 | unsigned int *end; |
---|
345 | volatile unsigned int *pos; |
---|
346 | |
---|
347 | pos = ®s->wram[0]; |
---|
348 | |
---|
349 | /* Write RAM */ |
---|
350 | if ( data ) { |
---|
351 | end = data + length; |
---|
352 | while ( data < end ) { |
---|
353 | *pos++ = *data++; |
---|
354 | } |
---|
355 | } else { |
---|
356 | while( length > 0 ) { |
---|
357 | *pos++ = 0; |
---|
358 | length -= 4; |
---|
359 | } |
---|
360 | } |
---|
361 | } |
---|
362 | |
---|
363 | static void grpwm_hw_reset(struct grpwm_priv *priv) |
---|
364 | { |
---|
365 | int i; |
---|
366 | struct grpwm_chan_priv *pwm; |
---|
367 | struct grpwm_regs *regs = priv->regs; |
---|
368 | |
---|
369 | /* Disable Core */ |
---|
370 | regs->ctrl = 0; |
---|
371 | |
---|
372 | /* Clear all registers */ |
---|
373 | regs->ipend = 0xffffffff; |
---|
374 | regs->wctrl = 0; |
---|
375 | |
---|
376 | /* Init all PWM channels */ |
---|
377 | for (i=0; i<priv->channel_cnt; i++) { |
---|
378 | pwm = priv->channels[i]; |
---|
379 | pwm->pwmregs->ctrl = 0; |
---|
380 | pwm->pwmregs->period = 0; |
---|
381 | pwm->pwmregs->comp = 0; |
---|
382 | pwm->pwmregs->dbcomp = 0; |
---|
383 | pwm->pwmregs->ctrl = 0; /* Twice because METH and POL requires EN=0 */ |
---|
384 | } |
---|
385 | |
---|
386 | /* Clear RAM */ |
---|
387 | if ( priv->wave ) { |
---|
388 | grpwm_write_wram(regs, NULL, priv->wlength); |
---|
389 | } |
---|
390 | |
---|
391 | /* Set max scaler */ |
---|
392 | for (i=0; i<priv->nscalers; i++) { |
---|
393 | grpwm_scaler_set(regs, i, 0xffffffff); |
---|
394 | } |
---|
395 | } |
---|
396 | |
---|
397 | /* Update one Channel but leaves the "Hold update" bit set |
---|
398 | * |
---|
399 | * A bit mask of updated bits are returned. |
---|
400 | */ |
---|
401 | static unsigned int grpwm_update_prepare_channel( |
---|
402 | struct grpwm_priv *priv, |
---|
403 | int channel, |
---|
404 | struct grpwm_ioctl_update_chan *up |
---|
405 | ) |
---|
406 | { |
---|
407 | struct grpwm_chan_priv *pwm; |
---|
408 | struct grpwm_pwm_regs *pwmregs; |
---|
409 | unsigned int ctrl; |
---|
410 | unsigned int ret; |
---|
411 | |
---|
412 | pwm = priv->channels[channel]; |
---|
413 | pwmregs = pwm->pwmregs; |
---|
414 | |
---|
415 | /* Read channel control register */ |
---|
416 | ctrl = pwmregs->ctrl; |
---|
417 | ret = 0; |
---|
418 | |
---|
419 | if ( up->options & GRPWM_UPDATE_OPTION_DISABLE ) { |
---|
420 | ctrl &= ~GRPWM_PCTRL_EN; |
---|
421 | pwmregs->ctrl = ctrl; |
---|
422 | ret |= GRPWM_PCTRL_EN; |
---|
423 | } |
---|
424 | |
---|
425 | /* Hold the updates */ |
---|
426 | if ( up->options & (GRPWM_UPDATE_OPTION_PERIOD| |
---|
427 | GRPWM_UPDATE_OPTION_COMP|GRPWM_UPDATE_OPTION_DBCOMP) ) { |
---|
428 | |
---|
429 | if ( up->options & (GRPWM_UPDATE_OPTION_PERIOD) ) { |
---|
430 | DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->period, up->period); |
---|
431 | pwmregs->period = up->period; |
---|
432 | } |
---|
433 | if ( up->options & (GRPWM_UPDATE_OPTION_COMP) ) { |
---|
434 | DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->comp, up->compare); |
---|
435 | pwmregs->comp = up->compare; |
---|
436 | } |
---|
437 | if ( up->options & (GRPWM_UPDATE_OPTION_DBCOMP) ) { |
---|
438 | DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->dbcomp, up->dbcomp); |
---|
439 | pwmregs->dbcomp = up->dbcomp; |
---|
440 | } |
---|
441 | } |
---|
442 | |
---|
443 | if ( up->options & GRPWM_UPDATE_OPTION_ENABLE ) { |
---|
444 | ret |= GRPWM_PCTRL_EN; |
---|
445 | pwmregs->ctrl = ctrl | GRPWM_PCTRL_EN; |
---|
446 | } |
---|
447 | return ret; |
---|
448 | } |
---|
449 | |
---|
450 | static void grpwm_update_active(struct grpwm_priv *priv, int enable) |
---|
451 | { |
---|
452 | unsigned int ctrl; |
---|
453 | int i; |
---|
454 | |
---|
455 | ctrl = priv->regs->ctrl; |
---|
456 | |
---|
457 | /* Make all "Update Hold" bits be cleared */ |
---|
458 | ctrl &= ~GRPWM_CTRL_NOUP; |
---|
459 | |
---|
460 | /* A change in any of the Channel enable/disable bits? */ |
---|
461 | if ( enable ) { |
---|
462 | ctrl &= ~GRPWM_CTRL_EN; |
---|
463 | for(i=0; i<priv->channel_cnt; i++) { |
---|
464 | ctrl |= priv->regs->pwms[i].ctrl & GRPWM_CTRL_EN; |
---|
465 | } |
---|
466 | } |
---|
467 | priv->regs->ctrl = ctrl; |
---|
468 | } |
---|
469 | |
---|
470 | /* Configure the hardware of a channel according to this */ |
---|
471 | static rtems_status_code grpwm_config_channel( |
---|
472 | struct grpwm_priv *priv, |
---|
473 | int channel, |
---|
474 | struct grpwm_ioctl_config *cfg |
---|
475 | ) |
---|
476 | { |
---|
477 | struct grpwm_chan_priv *pwm; |
---|
478 | unsigned int pctrl, wctrl=0; |
---|
479 | |
---|
480 | pwm = priv->channels[channel]; |
---|
481 | if ( pwm->pwmregs->ctrl & GRPWM_PCTRL_EN_BIT ) { |
---|
482 | return RTEMS_RESOURCE_IN_USE; |
---|
483 | } |
---|
484 | if ( cfg->options & ~GRPWM_CONFIG_OPTION_MASK ) { |
---|
485 | return RTEMS_INVALID_NAME; |
---|
486 | } |
---|
487 | if ( (cfg->options & GRPWM_CONFIG_OPTION_DUAL) && |
---|
488 | ((priv->regs->cap1 & GRPWM_CAP_DCM) == 0) ) { |
---|
489 | return RTEMS_INVALID_NAME; |
---|
490 | } |
---|
491 | /* IRQ set up */ |
---|
492 | pwm->isr_arg = cfg->isr_arg; |
---|
493 | pwm->isr = cfg->isr; |
---|
494 | |
---|
495 | pctrl = cfg->options | |
---|
496 | (cfg->dbscaler << GRPWM_PCTRL_DBSC_BIT) | |
---|
497 | (cfg->irqscaler << GRPWM_PCTRL_ISC_BIT) | |
---|
498 | (cfg->scaler_index << GRPWM_PCTRL_SCSEL_BIT); |
---|
499 | |
---|
500 | /* Set Wave form gerneration if available */ |
---|
501 | if ( !priv->wave || (priv->channel_cnt != (channel+1)) ) { |
---|
502 | /* Wave Form not available for this channel (or core) */ |
---|
503 | if ( cfg->wave_activate || cfg->wave_data || cfg->wave_data_length ) { |
---|
504 | return RTEMS_INVALID_NAME; |
---|
505 | } |
---|
506 | } else if ( cfg->wave_activate ) { |
---|
507 | /* Enable Wave form generation */ |
---|
508 | DBG("GRPWM: ENABLING WAVE FORM GENERATION 0x%x\n", cfg->wave_data_length); |
---|
509 | |
---|
510 | if ( cfg->wave_data ) { |
---|
511 | grpwm_write_wram(priv->regs, cfg->wave_data, cfg->wave_data_length); |
---|
512 | } |
---|
513 | |
---|
514 | /* Write length register, and let user control Wave-Sync functionality */ |
---|
515 | wctrl = (((cfg->wave_data_length-1) << GRPWM_WCTRL_STOP_BIT) & GRPWM_WCTRL_STOP); |
---|
516 | wctrl |= cfg->wave_synccfg & (GRPWM_WCTRL_WSYNCCFG|GRPWM_WCTRL_WSEN); |
---|
517 | wctrl |= (cfg->wave_sync << 16) & 0x1fff0000; |
---|
518 | priv->regs->wctrl = wctrl; |
---|
519 | |
---|
520 | /* Enable Wave form */ |
---|
521 | pctrl |= GRPWM_PCTRL_WEN; |
---|
522 | } |
---|
523 | |
---|
524 | DBG("GRPWM: CONFIG: 0x%x, WAVE CONFIG: 0x%x\n", pctrl, wctrl); |
---|
525 | |
---|
526 | pwm->pwmregs->ctrl = pctrl; |
---|
527 | |
---|
528 | return RTEMS_SUCCESSFUL; |
---|
529 | } |
---|
530 | |
---|
531 | static void grpwm_isr(void *arg) |
---|
532 | { |
---|
533 | unsigned int ipend; |
---|
534 | struct grpwm_chan_priv *pwm = arg; |
---|
535 | struct grpwm_priv *priv = pwm->common; |
---|
536 | int i; |
---|
537 | |
---|
538 | /* Get current pending interrupts */ |
---|
539 | ipend = priv->regs->ipend; |
---|
540 | |
---|
541 | for (i=0; i<priv->channel_cnt; i++) { |
---|
542 | if ( ipend & (1<<i) ) { |
---|
543 | pwm = priv->channels[i]; |
---|
544 | if ( pwm->isr ) { |
---|
545 | pwm->isr(i, pwm->isr_arg); |
---|
546 | } |
---|
547 | } |
---|
548 | } |
---|
549 | priv->regs->ipend = ipend; |
---|
550 | } |
---|
551 | |
---|
552 | static rtems_device_driver grpwm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
553 | { |
---|
554 | return RTEMS_SUCCESSFUL; |
---|
555 | } |
---|
556 | |
---|
557 | static rtems_device_driver grpwm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
558 | { |
---|
559 | struct grpwm_priv *priv; |
---|
560 | rtems_device_driver ret; |
---|
561 | struct drvmgr_dev *dev; |
---|
562 | |
---|
563 | if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) { |
---|
564 | DBG("Wrong minor %d\n", minor); |
---|
565 | return RTEMS_INVALID_NAME; |
---|
566 | } |
---|
567 | priv = (struct grpwm_priv *)dev->priv; |
---|
568 | |
---|
569 | /* Wait until we get semaphore */ |
---|
570 | if ( rtems_semaphore_obtain(priv->dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != |
---|
571 | RTEMS_SUCCESSFUL ){ |
---|
572 | return RTEMS_INTERNAL_ERROR; |
---|
573 | } |
---|
574 | |
---|
575 | /* is device busy/taken? */ |
---|
576 | if ( priv->open ) { |
---|
577 | ret=RTEMS_RESOURCE_IN_USE; |
---|
578 | goto out; |
---|
579 | } |
---|
580 | |
---|
581 | /* Mark device taken */ |
---|
582 | priv->open = 1; |
---|
583 | |
---|
584 | ret = RTEMS_SUCCESSFUL; |
---|
585 | out: |
---|
586 | rtems_semaphore_release(priv->dev_sem); |
---|
587 | return ret; |
---|
588 | } |
---|
589 | |
---|
590 | static rtems_device_driver grpwm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
591 | { |
---|
592 | struct grpwm_priv *priv; |
---|
593 | struct drvmgr_dev *dev; |
---|
594 | |
---|
595 | if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) { |
---|
596 | return RTEMS_INVALID_NAME; |
---|
597 | } |
---|
598 | priv = (struct grpwm_priv *)dev->priv; |
---|
599 | |
---|
600 | /* Reset Hardware */ |
---|
601 | grpwm_hw_reset(priv); |
---|
602 | |
---|
603 | /* Mark Device closed */ |
---|
604 | priv->open = 0; |
---|
605 | |
---|
606 | return RTEMS_SUCCESSFUL; |
---|
607 | } |
---|
608 | |
---|
609 | static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
610 | { |
---|
611 | return RTEMS_UNSATISFIED; |
---|
612 | } |
---|
613 | |
---|
614 | static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
615 | { |
---|
616 | return RTEMS_UNSATISFIED; |
---|
617 | } |
---|
618 | |
---|
619 | static rtems_device_driver grpwm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
620 | { |
---|
621 | |
---|
622 | struct grpwm_priv *priv; |
---|
623 | struct drvmgr_dev *dev; |
---|
624 | rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg; |
---|
625 | |
---|
626 | if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) { |
---|
627 | return RTEMS_INVALID_NAME; |
---|
628 | } |
---|
629 | priv = (struct grpwm_priv *)dev->priv; |
---|
630 | |
---|
631 | if (!ioarg) |
---|
632 | return RTEMS_INVALID_NAME; |
---|
633 | |
---|
634 | ioarg->ioctl_return = 0; |
---|
635 | switch(ioarg->command) { |
---|
636 | default: /* Not a valid command */ |
---|
637 | return RTEMS_NOT_DEFINED; |
---|
638 | |
---|
639 | case GRPWM_IOCTL_GET_CAP: |
---|
640 | { |
---|
641 | struct grpwm_ioctl_cap *cap = (void *)ioarg->buffer; |
---|
642 | if ( cap == NULL ) |
---|
643 | return RTEMS_INVALID_NAME; |
---|
644 | |
---|
645 | /* Copy Capability registers to user */ |
---|
646 | cap->channel_cnt = priv->channel_cnt; |
---|
647 | cap->pwm = priv->regs->cap1; |
---|
648 | cap->wave = priv->regs->cap2; |
---|
649 | break; |
---|
650 | } |
---|
651 | case GRPWM_IOCTL_SET_CONFIG: |
---|
652 | { |
---|
653 | struct grpwm_ioctl_config *cfg = (void *)ioarg->buffer; |
---|
654 | if ( cfg == NULL ) |
---|
655 | return RTEMS_INVALID_NAME; |
---|
656 | if ( cfg->channel >= priv->channel_cnt ) |
---|
657 | return RTEMS_INVALID_NAME; |
---|
658 | |
---|
659 | return grpwm_config_channel(priv, cfg->channel, cfg); |
---|
660 | } |
---|
661 | case GRPWM_IOCTL_SET_SCALER: |
---|
662 | { |
---|
663 | unsigned int invalid_mask; |
---|
664 | int i; |
---|
665 | struct grpwm_ioctl_scaler *sc = ioarg->buffer; |
---|
666 | |
---|
667 | if ( sc == NULL ) |
---|
668 | return RTEMS_INVALID_NAME; |
---|
669 | |
---|
670 | /* Test if caller reqest to set a scaler not existing */ |
---|
671 | invalid_mask = ~((1 << priv->nscalers) - 1); |
---|
672 | if ( invalid_mask & sc->index_mask ) { |
---|
673 | return RTEMS_INVALID_NAME; |
---|
674 | } |
---|
675 | |
---|
676 | /* Set scalers requested */ |
---|
677 | for (i=0; i<priv->nscalers; i++) { |
---|
678 | if ( sc->index_mask & (1<<i) ) { |
---|
679 | /* Update Scaler 'i' */ |
---|
680 | grpwm_scaler_set(priv->regs, i, sc->values[i]); |
---|
681 | } |
---|
682 | } |
---|
683 | break; |
---|
684 | } |
---|
685 | case GRPWM_IOCTL_UPDATE: |
---|
686 | { |
---|
687 | struct grpwm_ioctl_update *up = ioarg->buffer; |
---|
688 | unsigned int invalid_mask, pctrl = 0; |
---|
689 | int i; |
---|
690 | |
---|
691 | if ( up == NULL ) |
---|
692 | return RTEMS_INVALID_NAME; |
---|
693 | |
---|
694 | /* Test if caller reqest to set a scaler not existing */ |
---|
695 | invalid_mask = ~((1 << priv->channel_cnt) - 1); |
---|
696 | if ( invalid_mask & up->chanmask ) { |
---|
697 | return RTEMS_INVALID_NAME; |
---|
698 | } |
---|
699 | |
---|
700 | /* In order for the changes to take effect at the same time, the "Hold update" |
---|
701 | * bits is set for all PWM channels that will be updated. The hold update bits |
---|
702 | * will be cleared at the same time for all channels. |
---|
703 | */ |
---|
704 | priv->regs->ctrl = (priv->regs->ctrl & ~GRPWM_CTRL_NOUP) | |
---|
705 | (up->chanmask << GRPWM_CTRL_NOUP_BIT); |
---|
706 | |
---|
707 | for (i=0; i<priv->channel_cnt; i++) { |
---|
708 | if ( up->chanmask & (1<<i) ) { |
---|
709 | /* Prepare update channel 'i' */ |
---|
710 | pctrl |= grpwm_update_prepare_channel(priv, i, &up->channels[i]); |
---|
711 | } |
---|
712 | } |
---|
713 | |
---|
714 | /* 1. Update all channels requested, |
---|
715 | * 2. Enable the core if at least one channel is enabled |
---|
716 | * 3. Disable the core if all channels are disabled |
---|
717 | */ |
---|
718 | grpwm_update_active(priv, (pctrl & GRPWM_PCTRL_EN)); |
---|
719 | |
---|
720 | break; |
---|
721 | } |
---|
722 | case GRPWM_IOCTL_IRQ: |
---|
723 | { |
---|
724 | unsigned int data = (unsigned int)ioarg->buffer; |
---|
725 | int channel = (data >> 8) & 0x7; |
---|
726 | struct grpwm_chan_priv *pwm; |
---|
727 | unsigned int pctrl; |
---|
728 | |
---|
729 | pwm = priv->channels[channel]; |
---|
730 | |
---|
731 | if ( data & GRPWM_IRQ_CLEAR ) { |
---|
732 | priv->regs->ipend |= (1<<channel); |
---|
733 | drvmgr_interrupt_clear(priv->dev, pwm->irqindex); |
---|
734 | } |
---|
735 | if ( (data & 0x3) && !pwm->isr ) { |
---|
736 | /* Enable IRQ but no ISR */ |
---|
737 | return RTEMS_INVALID_NAME; |
---|
738 | } |
---|
739 | pctrl = pwm->pwmregs->ctrl & ~(GRPWM_PCTRL_IEN|GRPWM_PCTRL_IT); |
---|
740 | pctrl |= ((data & 0x3) << GRPWM_PCTRL_IEN_BIT); |
---|
741 | pwm->pwmregs->ctrl = pctrl; |
---|
742 | break; |
---|
743 | } |
---|
744 | } |
---|
745 | |
---|
746 | return RTEMS_SUCCESSFUL; |
---|
747 | } |
---|
748 | |
---|
749 | #define MAX_CHANNEL 8 |
---|
750 | char grpwm_irqindex_lookup[8][MAX_CHANNEL] = |
---|
751 | { |
---|
752 | /* Channel 1 2 3 4 5 6 7 8 */ |
---|
753 | /* npwm 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, |
---|
754 | /* npwm 2 */ {0, 1, 0, 0, 0, 0, 0, 0}, |
---|
755 | /* npwm 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, |
---|
756 | /* npwm 4 */ {0, 0, 0, 1, 0, 0, 0, 0}, |
---|
757 | /* npwm 5 */ {0, 0, 0, 1, 2, 0, 0, 0}, |
---|
758 | /* npwm 6 */ {0, 0, 0, 1, 1, 1, 0, 0}, |
---|
759 | /* npwm 7 */ {0, 0, 0, 1, 1, 1, 2, 0}, |
---|
760 | /* npwm 8 */ {0, 0, 0, 1, 1, 1, 2, 3} |
---|
761 | }; |
---|
762 | |
---|
763 | int grpwm_device_init(struct grpwm_priv *priv) |
---|
764 | { |
---|
765 | struct amba_dev_info *ambadev; |
---|
766 | struct ambapp_core *pnpinfo; |
---|
767 | int mask, i, sepirq; |
---|
768 | unsigned int wabits; |
---|
769 | struct grpwm_chan_priv *pwm; |
---|
770 | struct grpwm_regs *regs; |
---|
771 | |
---|
772 | /* Get device information from AMBA PnP information */ |
---|
773 | ambadev = (struct amba_dev_info *)priv->dev->businfo; |
---|
774 | if ( ambadev == NULL ) { |
---|
775 | return -1; |
---|
776 | } |
---|
777 | pnpinfo = &ambadev->info; |
---|
778 | priv->irq = pnpinfo->irq; |
---|
779 | regs = priv->regs = (struct grpwm_regs *)pnpinfo->apb_slv->start; |
---|
780 | |
---|
781 | DBG("GRPWM: 0x%08x irq %d\n", (unsigned int)regs, priv->irq); |
---|
782 | |
---|
783 | /* Disable Core */ |
---|
784 | regs->ctrl = 0; |
---|
785 | |
---|
786 | /* Clear all registers */ |
---|
787 | regs->ipend = 0xffffffff; |
---|
788 | regs->wctrl = 0; |
---|
789 | |
---|
790 | /* Find the number of PWM channels */ |
---|
791 | priv->channel_cnt = 1 + ((regs->cap1 & GRPWM_CAP_NPWM) >> GRPWM_CAP_NPWM_BIT); |
---|
792 | pwm = malloc(sizeof(*pwm)*priv->channel_cnt); |
---|
793 | if ( !pwm ) |
---|
794 | return -1; |
---|
795 | memset(pwm, 0, sizeof(*pwm)*priv->channel_cnt); |
---|
796 | |
---|
797 | /* Init all PWM channels */ |
---|
798 | sepirq = ((regs->cap1 & GRPWM_CAP_SEP) >> GRPWM_CAP_SEP_BIT); |
---|
799 | for (i=0; i<priv->channel_cnt; i++, pwm++) { |
---|
800 | priv->channels[i] = pwm; |
---|
801 | pwm->common = priv; |
---|
802 | pwm->pwmregs = ®s->pwms[i]; |
---|
803 | if ( sepirq == 0 ) { |
---|
804 | pwm->irqindex = 0; |
---|
805 | } else if ( sepirq == 1 ) { |
---|
806 | pwm->irqindex = i; |
---|
807 | } else { |
---|
808 | pwm->irqindex = grpwm_irqindex_lookup[priv->channel_cnt][i]; |
---|
809 | } |
---|
810 | } |
---|
811 | |
---|
812 | /* Detect if Wave Form capability is availble for last PWM channel */ |
---|
813 | if ( regs->cap2 & GRPWM_CAP2_WPWM ) { |
---|
814 | priv->wave = 1; |
---|
815 | |
---|
816 | /* Clear RAM */ |
---|
817 | wabits = (regs->cap2 & GRPWM_CAP2_WABITS) >> GRPWM_CAP2_WABITS_BIT; |
---|
818 | priv->wlength = 1 << wabits; |
---|
819 | } |
---|
820 | priv->nscalers = 1 + ((regs->cap1 & GRPWM_CAP_NSC) >> GRPWM_CAP_NSC_BIT); |
---|
821 | |
---|
822 | grpwm_hw_reset(priv); |
---|
823 | |
---|
824 | /* Device Semaphore created with count = 1 */ |
---|
825 | if ( rtems_semaphore_create(rtems_build_name('G', 'P', 'W', 'M'), |
---|
826 | 1, |
---|
827 | RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ |
---|
828 | RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, |
---|
829 | 0, |
---|
830 | &priv->dev_sem) != RTEMS_SUCCESSFUL ) { |
---|
831 | return -1; |
---|
832 | } |
---|
833 | |
---|
834 | /* Register interrupt handler for all PWM channels */ |
---|
835 | mask = 0; |
---|
836 | for (i=0; i<priv->channel_cnt; i++) { |
---|
837 | pwm = priv->channels[i]; |
---|
838 | if ( (mask & (1 << pwm->irqindex)) == 0 ) { |
---|
839 | /* Not registered interrupt handler for this IRQ index before, |
---|
840 | * we do it now. |
---|
841 | */ |
---|
842 | mask |= (1 << pwm->irqindex); |
---|
843 | drvmgr_interrupt_register( |
---|
844 | priv->dev, |
---|
845 | pwm->irqindex, |
---|
846 | "grpwm", |
---|
847 | grpwm_isr, |
---|
848 | pwm); |
---|
849 | } |
---|
850 | } |
---|
851 | |
---|
852 | return 0; |
---|
853 | } |
---|