source: rtems/bsps/sparc/shared/pwm/grpwm.c @ 11f3b9a

5
Last change on this file since 11f3b9a was 11f3b9a, checked in by Sebastian Huber <sebastian.huber@…>, on 11/26/18 at 14:55:38

bsps/sparc: Add grlib_malloc(), grlib_calloc()

This avoids a dependency to errno in device driver code.

  • Property mode set to 100644
File size: 22.1 KB
Line 
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 */
40struct 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 */     
48struct 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 ***/
150struct 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
166struct 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
177int grpwm_device_init(struct grpwm_priv *priv);
178int grpwm_register_io(rtems_device_major_number *m);
179static int grpwm_driver_io_registered = 0;
180static rtems_device_major_number grpwm_driver_io_major = 0;
181
182int grpwm_init2(struct drvmgr_dev *dev);
183int grpwm_init3(struct drvmgr_dev *dev);
184
185struct drvmgr_drv_ops grpwm_ops =
186{
187        .init = {NULL, grpwm_init2, grpwm_init3, NULL},
188        .remove = NULL,
189        .info = NULL
190};
191
192struct amba_dev_id grpwm_ids[] =
193{
194        {VENDOR_GAISLER, GAISLER_GRPWM},
195        {0, 0}          /* Mark end of table */
196};
197
198struct 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
215void grpwm_register_drv (void)
216{
217        DBG("Registering GRPWM driver\n");
218        drvmgr_drv_register(&grpwm_drv_info.general);
219}
220
221int 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
238int 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
293static rtems_device_driver grpwm_initialize(rtems_device_major_number  major, rtems_device_minor_number  minor, void *arg);
294static rtems_device_driver grpwm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
295static rtems_device_driver grpwm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
296static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
297static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
298static 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
302static rtems_driver_address_table grpwm_driver = GRPWM_DRIVER_TABLE_ENTRY;
303
304int 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
329static 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 */
341static 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 = &regs->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
365static 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 */
403static 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
452static 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 */
473static 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
533static 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
554static rtems_device_driver grpwm_initialize(rtems_device_major_number  major, rtems_device_minor_number  minor, void *arg)
555{
556        return RTEMS_SUCCESSFUL;
557}
558
559static 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;
587out:
588        rtems_semaphore_release(priv->dev_sem);
589        return ret;
590}
591
592static 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
611static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
612{
613        return RTEMS_UNSATISFIED;
614}
615
616static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
617{
618        return RTEMS_UNSATISFIED;
619}
620
621static 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
752char 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
765int 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 = &regs->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}
Note: See TracBrowser for help on using the repository browser.