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