diff options
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/pwm/grpwm.c')
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/pwm/grpwm.c | 853 |
1 files changed, 0 insertions, 853 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/pwm/grpwm.c b/c/src/lib/libbsp/sparc/shared/pwm/grpwm.c deleted file mode 100644 index 302df73e83..0000000000 --- a/c/src/lib/libbsp/sparc/shared/pwm/grpwm.c +++ /dev/null @@ -1,853 +0,0 @@ -/* - * GRPWM PWM Driver interface. - * - * COPYRIGHT (c) 2009. - * Cobham Gaisler AB, - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include <bsp.h> -#include <rtems/libio.h> -#include <stdlib.h> -#include <assert.h> -#include <rtems/bspIo.h> -#include <string.h> -#include <stdio.h> - -#include <drvmgr/drvmgr.h> -#include <drvmgr/ambapp_bus.h> -#include <bsp/grpwm.h> -#include <ambapp.h> - -/* #define DEBUG 1 */ - -#ifdef DEBUG -#define DBG(x...) printk(x) -#define STATIC -#else -#define DBG(x...) -#define STATIC static -#endif - -/*** REGISTER LAYOUT ***/ - -/* PWM Channel specific registers */ -struct grpwm_pwm_regs { - volatile unsigned int period; /* 0x00 */ - volatile unsigned int comp; /* 0x04 */ - volatile unsigned int dbcomp; /* 0x08 */ - volatile unsigned int ctrl; /* 0x0C */ -}; - -/* Core common registers */ -struct grpwm_regs { - volatile unsigned int ctrl; /* 0x00 */ - volatile unsigned int scaler; /* 0x04 */ - volatile unsigned int ipend; /* 0x08 */ - volatile unsigned int cap1; /* 0x0C */ - volatile unsigned int cap2; /* 0x10 */ - volatile unsigned int wctrl; /* 0x14 */ - int reserved0[2]; - struct grpwm_pwm_regs pwms[8]; /* 0x20 */ - int reserved1[(0x8000-0xA0)/4]; /* 0xA0-0x7FFC */ - volatile unsigned int wram[0x8000/4]; /* 0x8000-0xFFFC */ -}; - -/*** REGISTER BIT LAYOUT ***/ - -/* CTRL REGISTER - 0x0 */ -#define GRPWM_CTRL_EN_BIT 0 -#define GRPWM_CTRL_SCSEL_BIT 8 -#define GRPWM_CTRL_NOUP_BIT 12 -#define GRPWM_CTRL_EN (1<<GRPWM_CTRL_EN_BIT) -#define GRPWM_CTRL_SCSEL (0x7<<GRPWM_CTRL_SCSEL_BIT) -#define GRPWM_CTRL_NOUP (0xff<<GRPWM_CTRL_NOUP_BIT) - - -/* CAPABILITY1 REGISTER - 0x0C */ -#define GRPWM_CAP_NPWM_BIT 0 -#define GRPWM_CAP_PBITS_BIT 3 -#define GRPWM_CAP_SBITS_BIT 8 -#define GRPWM_CAP_NSC_BIT 13 -#define GRPWM_CAP_DBB_BIT 16 -#define GRPWM_CAP_DBSC_BIT 21 -#define GRPWM_CAP_ASY_BIT 22 -#define GRPWM_CAP_SYM_BIT 23 -#define GRPWM_CAP_SEP_BIT 25 -#define GRPWM_CAP_DCM_BIT 27 - -#define GRPWM_CAP_NPWM (0x7<<GRPWM_CAP_NPWM_BIT) -#define GRPWM_CAP_PBITS (0x1f<<GRPWM_CAP_PBITS_BIT) -#define GRPWM_CAP_SBITS (0x1f<<GRPWM_CAP_SBITS_BIT) -#define GRPWM_CAP_NSC (0x7<<GRPWM_CAP_NSC_BIT) -#define GRPWM_CAP_DBB (0x1f<<GRPWM_CAP_DBB_BIT) -#define GRPWM_CAP_DBSC (1<<GRPWM_CAP_DBSC_BIT) -#define GRPWM_CAP_ASY (1<<GRPWM_CAP_ASY_BIT) -#define GRPWM_CAP_SYM (1<<GRPWM_CAP_SYM_BIT) -#define GRPWM_CAP_SEP (0x3<<GRPWM_CAP_SEP_BIT) -#define GRPWM_CAP_DCM (1<<GRPWM_CAP_DCM_BIT) - -/* CAPABILITY2 REGISTER - 0x10 */ -#define GRPWM_CAP2_WPWM_BIT 0 -#define GRPWM_CAP2_WDBITS_BIT 1 -#define GRPWM_CAP2_WABITS_BIT 6 -#define GRPWM_CAP2_WSYNC_BIT 10 - -#define GRPWM_CAP2_WPWM (0x1<<GRPWM_CAP2_WPWM_BIT) -#define GRPWM_CAP2_WDBITS (0x1f<<GRPWM_CAP2_WDBITS_BIT) -#define GRPWM_CAP2_WABITS (0xf<<GRPWM_CAP2_WABITS_BIT) -#define GRPWM_CAP2_WSYNC (1<<GRPWM_CAP2_WSYNC_BIT) - -/* WAVE FORM CONFIG REGISTER - 0x14 */ -#define GRPWM_WCTRL_STOP_BIT 0 -#define GRPWM_WCTRL_WSYNC_BIT 16 -#define GRPWM_WCTRL_WSEN_BIT 29 -#define GRPWM_WCTRL_WSYNCCFG_BIT 30 - -#define GRPWM_WCTRL_STOP (0x1fff<<GRPWM_WCTRL_STOP_BIT) -#define GRPWM_WCTRL_WSYNC (0x1fff<<GRPWM_WCTRL_WSYNC_BIT) -#define GRPWM_WCTRL_WSEN (0x1<<GRPWM_WCTRL_WSEN_BIT) -#define GRPWM_WCTRL_WSYNCCFG (0x3<<GRPWM_WCTRL_WSYNCCFG_BIT) - - -/* PWM CONTROL REGISTER - 0x2C, 0x3C... */ -#define GRPWM_PCTRL_EN_BIT 0 -#define GRPWM_PCTRL_POL_BIT 1 -#define GRPWM_PCTRL_PAIR_BIT 2 -#define GRPWM_PCTRL_FIX_BIT 3 -#define GRPWM_PCTRL_METH_BIT 6 -#define GRPWM_PCTRL_DCEN_BIT 8 -#define GRPWM_PCTRL_WEN_BIT 9 -#define GRPWM_PCTRL_SCSEL_BIT 10 -#define GRPWM_PCTRL_IEN_BIT 13 -#define GRPWM_PCTRL_IT_BIT 14 -#define GRPWM_PCTRL_ISC_BIT 15 -#define GRPWM_PCTRL_DBEN_BIT 21 -#define GRPWM_PCTRL_DBSC_BIT 22 -#define GRPWM_PCTRL_FLIP_BIT 26 - -#define GRPWM_PCTRL_EN (0x1<<GRPWM_PCTRL_EN_BIT) -#define GRPWM_PCTRL_POL (0x1<<GRPWM_PCTRL_POL_BIT) -#define GRPWM_PCTRL_PAIR (0x1<<GRPWM_PCTRL_PAIR_BIT) -#define GRPWM_PCTRL_FIX (0x7<<GRPWM_PCTRL_FIX_BIT) -#define GRPWM_PCTRL_METH (0x1<<GRPWM_PCTRL_METH_BIT) -#define GRPWM_PCTRL_DCEN (0x1<<GRPWM_PCTRL_DCEN_BIT) -#define GRPWM_PCTRL_WEN (0x1<<GRPWM_PCTRL_WEN_BIT) -#define GRPWM_PCTRL_SCSEL (0x7<<GRPWM_PCTRL_SCSEL_BIT) -#define GRPWM_PCTRL_IEN (0x1<<GRPWM_PCTRL_IEN_BIT) -#define GRPWM_PCTRL_IT (0x1<<GRPWM_PCTRL_IT_BIT) -#define GRPWM_PCTRL_ISC (0x3f<<GRPWM_PCTRL_ISC_BIT) -#define GRPWM_PCTRL_DBEN (0x1<<GRPWM_PCTRL_DBEN_BIT) -#define GRPWM_PCTRL_DBSC (0xf<<GRPWM_PCTRL_DBSC_BIT) -#define GRPWM_PCTRL_FLIP (0xf<<GRPWM_PCTRL_FLIP_BIT) - -/*** DRIVER PRIVATE STRUCTURE ***/ -struct grpwm_priv { - struct drvmgr_dev *dev; - struct grpwm_regs *regs; - char devName[32]; - int irq; - int open; - - /* Driver implementation */ - char nscalers; /* Number of scalers */ - char wave; /* If Wave form is available */ - int wlength; /* Wave Form RAM Length */ - int channel_cnt; - struct grpwm_chan_priv *channels[8]; - rtems_id dev_sem; -}; - -struct grpwm_chan_priv { - struct grpwm_priv *common; - struct grpwm_pwm_regs *pwmregs; - /* IRQ */ - int irqindex; - void (*isr)(int channel, void *arg); - void *isr_arg; -}; - -/******************* Driver Manager Part ***********************/ - -int grpwm_device_init(struct grpwm_priv *priv); -int grpwm_register_io(rtems_device_major_number *m); -static int grpwm_driver_io_registered = 0; -static rtems_device_major_number grpwm_driver_io_major = 0; - -int grpwm_init2(struct drvmgr_dev *dev); -int grpwm_init3(struct drvmgr_dev *dev); - -struct drvmgr_drv_ops grpwm_ops = -{ - .init = {NULL, grpwm_init2, grpwm_init3, NULL}, - .remove = NULL, - .info = NULL -}; - -struct amba_dev_id grpwm_ids[] = -{ - {VENDOR_GAISLER, GAISLER_GRPWM}, - {0, 0} /* Mark end of table */ -}; - -struct amba_drv_info grpwm_drv_info = -{ - { - DRVMGR_OBJ_DRV, /* Driver */ - NULL, /* Next driver */ - NULL, /* Device list */ - DRIVER_AMBAPP_GAISLER_GRPWM_ID, /* Driver ID */ - "GRPWM_DRV", /* Driver Name */ - DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ - &grpwm_ops, - NULL, /* Funcs */ - 0, /* No devices yet */ - 0, - }, - &grpwm_ids[0] -}; - -void grpwm_register_drv (void) -{ - DBG("Registering GRPWM driver\n"); - drvmgr_drv_register(&grpwm_drv_info.general); -} - -int grpwm_init2(struct drvmgr_dev *dev) -{ - struct grpwm_priv *priv; - - DBG("GRPWM[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); - - priv = dev->priv = malloc(sizeof(struct grpwm_priv)); - if ( !priv ) - return DRVMGR_NOMEM; - memset(priv, 0, sizeof(*priv)); - priv->dev = dev; - - /* This core will not find other cores, so we wait for init2() */ - - return DRVMGR_OK; -} - -int grpwm_init3(struct drvmgr_dev *dev) -{ - struct grpwm_priv *priv = dev->priv; - char prefix[32]; - rtems_status_code status; - - if ( !priv ) - return DRVMGR_FAIL; - - if ( grpwm_driver_io_registered == 0) { - /* Register the I/O driver only once for all cores */ - if ( grpwm_register_io(&grpwm_driver_io_major) ) { - /* Failed to register I/O driver */ - dev->priv = NULL; - return DRVMGR_FAIL; - } - - grpwm_driver_io_registered = 1; - } - - /* I/O system registered and initialized - * Now we take care of device initialization. - */ - if ( grpwm_device_init(priv) ) { - free(dev->priv); - dev->priv = NULL; - return DRVMGR_FAIL; - } - - /* Get Filesystem name prefix */ - prefix[0] = '\0'; - if ( drvmgr_get_dev_prefix(dev, prefix) ) { - /* Failed to get prefix, make sure of a unique FS name - * by using the driver minor. - */ - sprintf(priv->devName, "/dev/grpwm%d", dev->minor_drv); - } else { - /* Got special prefix, this means we have a bus prefix - * And we should use our "bus minor" - */ - sprintf(priv->devName, "/dev/%sgrpwm%d", prefix, dev->minor_bus); - } - - /* Register Device */ - status = rtems_io_register_name(priv->devName, grpwm_driver_io_major, - dev->minor_drv); - if (status != RTEMS_SUCCESSFUL) { - return DRVMGR_FAIL; - } - - return DRVMGR_OK; -} - -/******************* Driver Implementation ***********************/ - -static rtems_device_driver grpwm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grpwm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grpwm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grpwm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); - -#define GRPWM_DRIVER_TABLE_ENTRY { grpwm_initialize, grpwm_open, grpwm_close, grpwm_read, grpwm_write, grpwm_ioctl } - -static rtems_driver_address_table grpwm_driver = GRPWM_DRIVER_TABLE_ENTRY; - -int grpwm_register_io(rtems_device_major_number *m) -{ - rtems_status_code r; - - if ((r = rtems_io_register_driver(0, &grpwm_driver, m)) == RTEMS_SUCCESSFUL) { - DBG("GRPWM driver successfully registered, major: %d\n", *m); - } else { - switch(r) { - case RTEMS_TOO_MANY: - DBG("GRPWM rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); - return -1; - case RTEMS_INVALID_NUMBER: - DBG("GRPWM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); - return -1; - case RTEMS_RESOURCE_IN_USE: - DBG("GRPWM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); - return -1; - default: - DBG("GRPWM rtems_io_register_driver failed\n"); - return -1; - } - } - return 0; -} - -static void grpwm_scaler_set( - struct grpwm_regs *regs, - int scaler, - unsigned int value) -{ - /* Select scaler */ - regs->ctrl = (regs->ctrl & ~GRPWM_CTRL_SCSEL) | (scaler << GRPWM_CTRL_SCSEL_BIT); - /* Write scaler */ - regs->scaler = value; -} - -/* Write Wave form RAM */ -static void grpwm_write_wram( - struct grpwm_regs *regs, - unsigned int *data, - int length) -{ - unsigned int *end; - volatile unsigned int *pos; - - pos = ®s->wram[0]; - - /* Write RAM */ - if ( data ) { - end = data + length; - while ( data < end ) { - *pos++ = *data++; - } - } else { - while( length > 0 ) { - *pos++ = 0; - length -= 4; - } - } -} - -static void grpwm_hw_reset(struct grpwm_priv *priv) -{ - int i; - struct grpwm_chan_priv *pwm; - struct grpwm_regs *regs = priv->regs; - - /* Disable Core */ - regs->ctrl = 0; - - /* Clear all registers */ - regs->ipend = 0xffffffff; - regs->wctrl = 0; - - /* Init all PWM channels */ - for (i=0; i<priv->channel_cnt; i++) { - pwm = priv->channels[i]; - pwm->pwmregs->ctrl = 0; - pwm->pwmregs->period = 0; - pwm->pwmregs->comp = 0; - pwm->pwmregs->dbcomp = 0; - pwm->pwmregs->ctrl = 0; /* Twice because METH and POL requires EN=0 */ - } - - /* Clear RAM */ - if ( priv->wave ) { - grpwm_write_wram(regs, NULL, priv->wlength); - } - - /* Set max scaler */ - for (i=0; i<priv->nscalers; i++) { - grpwm_scaler_set(regs, i, 0xffffffff); - } -} - -/* Update one Channel but leaves the "Hold update" bit set - * - * A bit mask of updated bits are returned. - */ -static unsigned int grpwm_update_prepare_channel( - struct grpwm_priv *priv, - int channel, - struct grpwm_ioctl_update_chan *up - ) -{ - struct grpwm_chan_priv *pwm; - struct grpwm_pwm_regs *pwmregs; - unsigned int ctrl; - unsigned int ret; - - pwm = priv->channels[channel]; - pwmregs = pwm->pwmregs; - - /* Read channel control register */ - ctrl = pwmregs->ctrl; - ret = 0; - - if ( up->options & GRPWM_UPDATE_OPTION_DISABLE ) { - ctrl &= ~GRPWM_PCTRL_EN; - pwmregs->ctrl = ctrl; - ret |= GRPWM_PCTRL_EN; - } - - /* Hold the updates */ - if ( up->options & (GRPWM_UPDATE_OPTION_PERIOD| - GRPWM_UPDATE_OPTION_COMP|GRPWM_UPDATE_OPTION_DBCOMP) ) { - - if ( up->options & (GRPWM_UPDATE_OPTION_PERIOD) ) { - DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->period, up->period); - pwmregs->period = up->period; - } - if ( up->options & (GRPWM_UPDATE_OPTION_COMP) ) { - DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->comp, up->compare); - pwmregs->comp = up->compare; - } - if ( up->options & (GRPWM_UPDATE_OPTION_DBCOMP) ) { - DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->dbcomp, up->dbcomp); - pwmregs->dbcomp = up->dbcomp; - } - } - - if ( up->options & GRPWM_UPDATE_OPTION_ENABLE ) { - ret |= GRPWM_PCTRL_EN; - pwmregs->ctrl = ctrl | GRPWM_PCTRL_EN; - } - return ret; -} - -static void grpwm_update_active(struct grpwm_priv *priv, int enable) -{ - unsigned int ctrl; - int i; - - ctrl = priv->regs->ctrl; - - /* Make all "Update Hold" bits be cleared */ - ctrl &= ~GRPWM_CTRL_NOUP; - - /* A change in any of the Channel enable/disable bits? */ - if ( enable ) { - ctrl &= ~GRPWM_CTRL_EN; - for(i=0; i<priv->channel_cnt; i++) { - ctrl |= priv->regs->pwms[i].ctrl & GRPWM_CTRL_EN; - } - } - priv->regs->ctrl = ctrl; -} - -/* Configure the hardware of a channel according to this */ -static rtems_status_code grpwm_config_channel( - struct grpwm_priv *priv, - int channel, - struct grpwm_ioctl_config *cfg - ) -{ - struct grpwm_chan_priv *pwm; - unsigned int pctrl, wctrl=0; - - pwm = priv->channels[channel]; - if ( pwm->pwmregs->ctrl & GRPWM_PCTRL_EN_BIT ) { - return RTEMS_RESOURCE_IN_USE; - } - if ( cfg->options & ~GRPWM_CONFIG_OPTION_MASK ) { - return RTEMS_INVALID_NAME; - } - if ( (cfg->options & GRPWM_CONFIG_OPTION_DUAL) && - ((priv->regs->cap1 & GRPWM_CAP_DCM) == 0) ) { - return RTEMS_INVALID_NAME; - } - /* IRQ set up */ - pwm->isr_arg = cfg->isr_arg; - pwm->isr = cfg->isr; - - pctrl = cfg->options | - (cfg->dbscaler << GRPWM_PCTRL_DBSC_BIT) | - (cfg->irqscaler << GRPWM_PCTRL_ISC_BIT) | - (cfg->scaler_index << GRPWM_PCTRL_SCSEL_BIT); - - /* Set Wave form gerneration if available */ - if ( !priv->wave || (priv->channel_cnt != (channel+1)) ) { - /* Wave Form not available for this channel (or core) */ - if ( cfg->wave_activate || cfg->wave_data || cfg->wave_data_length ) { - return RTEMS_INVALID_NAME; - } - } else if ( cfg->wave_activate ) { - /* Enable Wave form generation */ - DBG("GRPWM: ENABLING WAVE FORM GENERATION 0x%x\n", cfg->wave_data_length); - - if ( cfg->wave_data ) { - grpwm_write_wram(priv->regs, cfg->wave_data, cfg->wave_data_length); - } - - /* Write length register, and let user control Wave-Sync functionality */ - wctrl = (((cfg->wave_data_length-1) << GRPWM_WCTRL_STOP_BIT) & GRPWM_WCTRL_STOP); - wctrl |= cfg->wave_synccfg & (GRPWM_WCTRL_WSYNCCFG|GRPWM_WCTRL_WSEN); - wctrl |= (cfg->wave_sync << 16) & 0x1fff0000; - priv->regs->wctrl = wctrl; - - /* Enable Wave form */ - pctrl |= GRPWM_PCTRL_WEN; - } - - DBG("GRPWM: CONFIG: 0x%x, WAVE CONFIG: 0x%x\n", pctrl, wctrl); - - pwm->pwmregs->ctrl = pctrl; - - return RTEMS_SUCCESSFUL; -} - -static void grpwm_isr(void *arg) -{ - unsigned int ipend; - struct grpwm_chan_priv *pwm = arg; - struct grpwm_priv *priv = pwm->common; - int i; - - /* Get current pending interrupts */ - ipend = priv->regs->ipend; - - for (i=0; i<priv->channel_cnt; i++) { - if ( ipend & (1<<i) ) { - pwm = priv->channels[i]; - if ( pwm->isr ) { - pwm->isr(i, pwm->isr_arg); - } - } - } - priv->regs->ipend = ipend; -} - -static rtems_device_driver grpwm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) -{ - return RTEMS_SUCCESSFUL; -} - -static rtems_device_driver grpwm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) -{ - struct grpwm_priv *priv; - rtems_device_driver ret; - struct drvmgr_dev *dev; - - if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) { - DBG("Wrong minor %d\n", minor); - return RTEMS_INVALID_NAME; - } - priv = (struct grpwm_priv *)dev->priv; - - /* Wait until we get semaphore */ - if ( rtems_semaphore_obtain(priv->dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != - RTEMS_SUCCESSFUL ){ - return RTEMS_INTERNAL_ERROR; - } - - /* is device busy/taken? */ - if ( priv->open ) { - ret=RTEMS_RESOURCE_IN_USE; - goto out; - } - - /* Mark device taken */ - priv->open = 1; - - ret = RTEMS_SUCCESSFUL; -out: - rtems_semaphore_release(priv->dev_sem); - return ret; -} - -static rtems_device_driver grpwm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) -{ - struct grpwm_priv *priv; - struct drvmgr_dev *dev; - - if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) { - return RTEMS_INVALID_NAME; - } - priv = (struct grpwm_priv *)dev->priv; - - /* Reset Hardware */ - grpwm_hw_reset(priv); - - /* Mark Device closed */ - priv->open = 0; - - return RTEMS_SUCCESSFUL; -} - -static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) -{ - return RTEMS_UNSATISFIED; -} - -static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) -{ - return RTEMS_UNSATISFIED; -} - -static rtems_device_driver grpwm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) -{ - - struct grpwm_priv *priv; - struct drvmgr_dev *dev; - rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg; - - if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) { - return RTEMS_INVALID_NAME; - } - priv = (struct grpwm_priv *)dev->priv; - - if (!ioarg) - return RTEMS_INVALID_NAME; - - ioarg->ioctl_return = 0; - switch(ioarg->command) { - default: /* Not a valid command */ - return RTEMS_NOT_DEFINED; - - case GRPWM_IOCTL_GET_CAP: - { - struct grpwm_ioctl_cap *cap = (void *)ioarg->buffer; - if ( cap == NULL ) - return RTEMS_INVALID_NAME; - - /* Copy Capability registers to user */ - cap->channel_cnt = priv->channel_cnt; - cap->pwm = priv->regs->cap1; - cap->wave = priv->regs->cap2; - break; - } - case GRPWM_IOCTL_SET_CONFIG: - { - struct grpwm_ioctl_config *cfg = (void *)ioarg->buffer; - if ( cfg == NULL ) - return RTEMS_INVALID_NAME; - if ( cfg->channel >= priv->channel_cnt ) - return RTEMS_INVALID_NAME; - - return grpwm_config_channel(priv, cfg->channel, cfg); - } - case GRPWM_IOCTL_SET_SCALER: - { - unsigned int invalid_mask; - int i; - struct grpwm_ioctl_scaler *sc = ioarg->buffer; - - if ( sc == NULL ) - return RTEMS_INVALID_NAME; - - /* Test if caller reqest to set a scaler not existing */ - invalid_mask = ~((1 << priv->nscalers) - 1); - if ( invalid_mask & sc->index_mask ) { - return RTEMS_INVALID_NAME; - } - - /* Set scalers requested */ - for (i=0; i<priv->nscalers; i++) { - if ( sc->index_mask & (1<<i) ) { - /* Update Scaler 'i' */ - grpwm_scaler_set(priv->regs, i, sc->values[i]); - } - } - break; - } - case GRPWM_IOCTL_UPDATE: - { - struct grpwm_ioctl_update *up = ioarg->buffer; - unsigned int invalid_mask, pctrl = 0; - int i; - - if ( up == NULL ) - return RTEMS_INVALID_NAME; - - /* Test if caller reqest to set a scaler not existing */ - invalid_mask = ~((1 << priv->channel_cnt) - 1); - if ( invalid_mask & up->chanmask ) { - return RTEMS_INVALID_NAME; - } - - /* In order for the changes to take effect at the same time, the "Hold update" - * bits is set for all PWM channels that will be updated. The hold update bits - * will be cleared at the same time for all channels. - */ - priv->regs->ctrl = (priv->regs->ctrl & ~GRPWM_CTRL_NOUP) | - (up->chanmask << GRPWM_CTRL_NOUP_BIT); - - for (i=0; i<priv->channel_cnt; i++) { - if ( up->chanmask & (1<<i) ) { - /* Prepare update channel 'i' */ - pctrl |= grpwm_update_prepare_channel(priv, i, &up->channels[i]); - } - } - - /* 1. Update all channels requested, - * 2. Enable the core if at least one channel is enabled - * 3. Disable the core if all channels are disabled - */ - grpwm_update_active(priv, (pctrl & GRPWM_PCTRL_EN)); - - break; - } - case GRPWM_IOCTL_IRQ: - { - unsigned int data = (unsigned int)ioarg->buffer; - int channel = (data >> 8) & 0x7; - struct grpwm_chan_priv *pwm; - unsigned int pctrl; - - pwm = priv->channels[channel]; - - if ( data & GRPWM_IRQ_CLEAR ) { - priv->regs->ipend |= (1<<channel); - drvmgr_interrupt_clear(priv->dev, pwm->irqindex); - } - if ( (data & 0x3) && !pwm->isr ) { - /* Enable IRQ but no ISR */ - return RTEMS_INVALID_NAME; - } - pctrl = pwm->pwmregs->ctrl & ~(GRPWM_PCTRL_IEN|GRPWM_PCTRL_IT); - pctrl |= ((data & 0x3) << GRPWM_PCTRL_IEN_BIT); - pwm->pwmregs->ctrl = pctrl; - break; - } - } - - return RTEMS_SUCCESSFUL; -} - -#define MAX_CHANNEL 8 -char grpwm_irqindex_lookup[8][MAX_CHANNEL] = -{ -/* Channel 1 2 3 4 5 6 7 8 */ -/* npwm 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* npwm 2 */ {0, 1, 0, 0, 0, 0, 0, 0}, -/* npwm 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* npwm 4 */ {0, 0, 0, 1, 0, 0, 0, 0}, -/* npwm 5 */ {0, 0, 0, 1, 2, 0, 0, 0}, -/* npwm 6 */ {0, 0, 0, 1, 1, 1, 0, 0}, -/* npwm 7 */ {0, 0, 0, 1, 1, 1, 2, 0}, -/* npwm 8 */ {0, 0, 0, 1, 1, 1, 2, 3} -}; - -int grpwm_device_init(struct grpwm_priv *priv) -{ - struct amba_dev_info *ambadev; - struct ambapp_core *pnpinfo; - int mask, i, sepirq; - unsigned int wabits; - struct grpwm_chan_priv *pwm; - struct grpwm_regs *regs; - - /* Get device information from AMBA PnP information */ - ambadev = (struct amba_dev_info *)priv->dev->businfo; - if ( ambadev == NULL ) { - return -1; - } - pnpinfo = &ambadev->info; - priv->irq = pnpinfo->irq; - regs = priv->regs = (struct grpwm_regs *)pnpinfo->apb_slv->start; - - DBG("GRPWM: 0x%08x irq %d\n", (unsigned int)regs, priv->irq); - - /* Disable Core */ - regs->ctrl = 0; - - /* Clear all registers */ - regs->ipend = 0xffffffff; - regs->wctrl = 0; - - /* Find the number of PWM channels */ - priv->channel_cnt = 1 + ((regs->cap1 & GRPWM_CAP_NPWM) >> GRPWM_CAP_NPWM_BIT); - pwm = malloc(sizeof(*pwm)*priv->channel_cnt); - if ( !pwm ) - return -1; - memset(pwm, 0, sizeof(*pwm)*priv->channel_cnt); - - /* Init all PWM channels */ - sepirq = ((regs->cap1 & GRPWM_CAP_SEP) >> GRPWM_CAP_SEP_BIT); - for (i=0; i<priv->channel_cnt; i++, pwm++) { - priv->channels[i] = pwm; - pwm->common = priv; - pwm->pwmregs = ®s->pwms[i]; - if ( sepirq == 0 ) { - pwm->irqindex = 0; - } else if ( sepirq == 1 ) { - pwm->irqindex = i; - } else { - pwm->irqindex = grpwm_irqindex_lookup[priv->channel_cnt][i]; - } - } - - /* Detect if Wave Form capability is availble for last PWM channel */ - if ( regs->cap2 & GRPWM_CAP2_WPWM ) { - priv->wave = 1; - - /* Clear RAM */ - wabits = (regs->cap2 & GRPWM_CAP2_WABITS) >> GRPWM_CAP2_WABITS_BIT; - priv->wlength = 1 << wabits; - } - priv->nscalers = 1 + ((regs->cap1 & GRPWM_CAP_NSC) >> GRPWM_CAP_NSC_BIT); - - grpwm_hw_reset(priv); - - /* Device Semaphore created with count = 1 */ - if ( rtems_semaphore_create(rtems_build_name('G', 'P', 'W', 'M'), - 1, - RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ - RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, - 0, - &priv->dev_sem) != RTEMS_SUCCESSFUL ) { - return -1; - } - - /* Register interrupt handler for all PWM channels */ - mask = 0; - for (i=0; i<priv->channel_cnt; i++) { - pwm = priv->channels[i]; - if ( (mask & (1 << pwm->irqindex)) == 0 ) { - /* Not registered interrupt handler for this IRQ index before, - * we do it now. - */ - mask |= (1 << pwm->irqindex); - drvmgr_interrupt_register( - priv->dev, - pwm->irqindex, - "grpwm", - grpwm_isr, - pwm); - } - } - - return 0; -} |