source: rtems/c/src/lib/libbsp/sparc/shared/pwm/grpwm.c @ 4a7d1026

4.115
Last change on this file since 4a7d1026 was 4a7d1026, checked in by Daniel Hellstrom <daniel@…>, on 04/13/15 at 08:25:52

sparc bsps: updated license to rtems.org

  • Property mode set to 100644
File size: 22.2 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/* #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 */
38struct 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 */     
46struct 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 ***/
148struct 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
164struct 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
175int grpwm_device_init(struct grpwm_priv *priv);
176int grpwm_register_io(rtems_device_major_number *m);
177static int grpwm_driver_io_registered = 0;
178static rtems_device_major_number grpwm_driver_io_major = 0;
179
180int grpwm_init2(struct drvmgr_dev *dev);
181int grpwm_init3(struct drvmgr_dev *dev);
182
183struct drvmgr_drv_ops grpwm_ops =
184{
185        .init = {NULL, grpwm_init2, grpwm_init3, NULL},
186        .remove = NULL,
187        .info = NULL
188};
189
190struct amba_dev_id grpwm_ids[] =
191{
192        {VENDOR_GAISLER, GAISLER_GRPWM},
193        {0, 0}          /* Mark end of table */
194};
195
196struct 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
213void grpwm_register_drv (void)
214{
215        DBG("Registering GRPWM driver\n");
216        drvmgr_drv_register(&grpwm_drv_info.general);
217}
218
219int 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
236int 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
291static rtems_device_driver grpwm_initialize(rtems_device_major_number  major, rtems_device_minor_number  minor, void *arg);
292static rtems_device_driver grpwm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
293static rtems_device_driver grpwm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
294static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
295static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
296static 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
300static rtems_driver_address_table grpwm_driver = GRPWM_DRIVER_TABLE_ENTRY;
301
302int 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
327static 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 */
339static 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 = &regs->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
363static 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 */
401static 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
450static 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 */
471static 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
531static 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
552static rtems_device_driver grpwm_initialize(rtems_device_major_number  major, rtems_device_minor_number  minor, void *arg)
553{
554        return RTEMS_SUCCESSFUL;
555}
556
557static 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;
585out:
586        rtems_semaphore_release(priv->dev_sem);
587        return ret;
588}
589
590static 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
609static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
610{
611        return RTEMS_UNSATISFIED;
612}
613
614static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
615{
616        return RTEMS_UNSATISFIED;
617}
618
619static 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
750char 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
763int 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 = &regs->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}
Note: See TracBrowser for help on using the repository browser.